Users and permissions: accounts, login, enforced file permissions, setuid, su, passwd, doas

The kernel now checks owner/group/other on open, create, unlink, rename, exec
and path search; honours set-user-id and set-group-id; restricts kill, mount,
reboot and mknod; keeps supplementary groups; and implements chown. devtmpfs
nodes carry owners and modes that chmod/chown keep. Terminals run login, the
image has root and schos, X starts as the ordinary user.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
Nexoniarz 2026-10-26 13:16:07 +01:00
commit 020aa6113c
34 changed files with 1342 additions and 120 deletions

View file

@ -532,6 +532,7 @@ found:
p->sid = 0;
p->uid = p->euid = p->suid = 0;
p->gid = p->egid = p->sgid = 0;
p->ngroups = 0;
release(&ptable.lock);
@ -760,6 +761,8 @@ fork(void)
np->ctty = myproc()->ctty;
np->uid = myproc()->uid; np->euid = myproc()->euid; np->suid = myproc()->suid;
np->gid = myproc()->gid; np->egid = myproc()->egid; np->sgid = myproc()->sgid;
np->ngroups = myproc()->ngroups;
memmove(np->groups, myproc()->groups, sizeof(np->groups));
np->cwd = idup(myproc()->cwd);
np->root = myproc()->root ? idup(myproc()->root) : 0;
@ -1167,6 +1170,8 @@ clone_proc(uint64 flags, uint64 stack, uint64 ptid, uint64 ctid, uint64 tls)
np->ctty = cur->ctty;
np->uid = cur->uid; np->euid = cur->euid; np->suid = cur->suid;
np->gid = cur->gid; np->egid = cur->egid; np->sgid = cur->sgid;
np->ngroups = cur->ngroups;
memmove(np->groups, cur->groups, sizeof(np->groups));
np->cwd = idup(cur->cwd);
np->root = cur->root ? idup(cur->root) : 0;
memmove(np->cwd_path, cur->cwd_path, sizeof(cur->cwd_path));
@ -2614,8 +2619,21 @@ sig_to_threads(struct proc *p, int sig)
}
}
int
sigsend(int pid, int sig)
// May `from` signal `to`? Root may; anyone else only a process whose real or
// saved user id is one of their own ids -- kill(2)'s rule.
static int
sig_permitted(struct proc *from, struct proc *to)
{
if(from == 0 || from->euid == 0)
return 1;
return from->uid == to->uid || from->uid == to->suid ||
from->euid == to->uid || from->euid == to->suid;
}
// `check` is for a signal a process sends on purpose, by kill(2). The kernel's
// own -- SIGPIPE, the terminal's SIGINT -- is nobody's to refuse.
static int
sigsend_x(int pid, int sig, int check)
{
struct proc *p;
@ -2625,6 +2643,10 @@ sigsend(int pid, int sig)
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->pid == pid && p->state != UNUSED && p->state != ZOMBIE){
if(check && !sig_permitted(myproc(), p)){
release(&ptable.lock);
return -2;
}
if(init_ignores(p, sig)){
release(&ptable.lock);
return 0; // silently dropped, as POSIX requires
@ -2652,16 +2674,29 @@ sigsend(int pid, int sig)
return -1;
}
int
sigsend(int pid, int sig)
{
return sigsend_x(pid, sig, 0);
}
// -1 if there is no such process, -2 if there is and the caller may not.
int
sigsend_user(int pid, int sig)
{
return sigsend_x(pid, sig, 1);
}
// Deliver a signal to every member of a process group. This is what job
// control actually needs: a shell sends SIGINT/SIGTSTP/SIGHUP to a *group*,
// never to individual pids. sys_kill() with pid <= 0 routes here.
//
// Returns 0 if at least one process was signalled, -1 if the group is empty.
int
sigsend_pgrp(int pgid, int sig)
static int
sigsend_pgrp_x(int pgid, int sig, int check)
{
struct proc *p;
int found = 0;
int found = 0, denied = 0;
if(sig < 0 || sig >= 32)
return -1;
@ -2672,6 +2707,10 @@ sigsend_pgrp(int pgid, int sig)
continue;
if(p->pgid != pgid)
continue;
if(check && !sig_permitted(myproc(), p)){
denied = 1;
continue;
}
found = 1;
if(sig == 0)
continue; // signal 0 is an existence probe only
@ -2701,7 +2740,19 @@ sigsend_pgrp(int pgid, int sig)
}
release(&ptable.lock);
return found ? 0 : -1;
return found ? 0 : denied ? -2 : -1;
}
int
sigsend_pgrp(int pgid, int sig)
{
return sigsend_pgrp_x(pgid, sig, 0);
}
int
sigsend_pgrp_user(int pgid, int sig)
{
return sigsend_pgrp_x(pgid, sig, 1);
}
// Look up a process's process-group id. Returns -1 if no such live process.