SchOS/docs/architecture/users.md
Nexoniarz 2aef583aad Twelve login terminals, root only, console fixes, a faster build, a Niveus splash, and X back on evdev
- tty1-tty12 all run login; the image has only root. /dev/tty7..12 could not
  be written (cdev.c knew minors 10-16 only), which sent their jobs into a
  restart storm that took the supervisor down; fixed, and stat reports them as
  Linux's tty7..12.
- Erasing text at a prompt did nothing: erase_one sent a bare backspace, which
  only moves; it and the echo path now send back-blank-back through vt_feed.
- A white cursor block was left at the end of every line of a verbose boot:
  a line feed at the bottom scrolls the pixels, cursor included, and the
  cursor was erased after the scroll. It comes off first now. A blank cell is
  also marked dirty, which it was not.
- ldlsd died with a general protection fault on real hardware in its variadic
  log function: Linux module code calls with an 8-byte-aligned stack and an
  unset %al, and the prologue's movaps faults. LDLS guest code is built with
  -mstackrealign.
- make iso took over a minute for any change, because staging r8169 rewrote
  the same files and every mtime moved; it now replaces files only if their
  contents differ (about 10 s).
- The loader's splash is redrawn in the boot manager's style, and the boot
  manager shows its cursor whenever a pointer device exists.
- xf86-input-libinput is out of the image again: with it Xorg took both
  keyboard and pointer from libinput and, on the user's laptop, neither worked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
2026-10-26 17:43:44 +01:00

4.2 KiB
Raw Permalink Blame History

Users and permissions

SchOS has accounts, a login prompt, and file permissions that the kernel enforces. Until now every process was root and uid was bookkeeping; this is the part that makes it a multi-user system.

What you meet

  • login on all twelve terminals, tty1–tty12. etc/schos-getty takes the terminal back from whoever had it and runs login, which asks who is there and starts their shell; when the shell exits schinit starts the prompt again. Alt+F1…F12 (or Ctrl+Alt+F1…F12) switches between them. (There is no longer a login-free root shell on tty6.)
  • One account in the image: root, with an empty password, so login lets it in without asking — it is a live image. passwd sets one. More users are an adduser away; wheel is empty, so su and doas have no one to serve until then.
  • su and passwd (cmd/su, cmd/passwd) are setuid root and small programs of their own, not toybox applets: toybox is one binary under every name, and a setuid copy of it can be asked for any applet by naming it, as root. su to root takes membership in wheel, whatever the password.
  • doas (Alpine's, setuid) with permit nopass :wheel in /etc/doas.conf.

What the kernel enforces

open, create, unlink, rename, link the usual owner/group/other bits, w+x on the directory, and the sticky bit (/tmp)
path walk x on every directory searched
exec x on the file; set-user-id and set-group-id make the new image run as its owner or group, and the saved ids follow
chmod, chown, utimensat owner or root; a non-root chown drops the set-id bits
access / faccessat by the real ids (AT_EACCESS for the effective ones)
kill, tkill, tgkill root, or a target whose real or saved uid is one of yours. The kernel's own signals (SIGPIPE, the terminal's) are nobody's to refuse
mount, umount, chroot, reboot, shutdown, setgroups, mknod of a device root
setuid family root may set anything; anyone else only to an id they already hold

Root reads and writes everything and executes a file only if some execute bit is set. A process's supplementary groups (setgroups) are consulted along with its effective group. Ownership is stored by SchFS (it always had the fields); FAT volumes belong to everyone, since they cannot say otherwise, and /proc and /sys are root's.

inode_permission() in kernel/fs/fs.c is the one check; the rest of this is call sites.

Devices

/dev is built by the kernel and each node has the owner, group and mode in the devnodes[] table of kernel/fs/devfs.c: null and zero are 0666, terminals root:tty 0660, fb0 root:video, input root:input, raw disks root:disk, pci, dbg and netdev root's alone. chmod and chown on a node are kept (login claims its terminal this way, and udev sets modes) in an override table applied whenever the inode is loaded. A new pseudo-terminal's slave belongs to whoever opened ptmx.

udev would set a node it has no rule for to 0600, which made /dev/null root-only, so etc/udev-schos.rules (installed as 90-schos.rules) names the kernel's devices with the answers the kernel gave.

The image

Everything in the image is owned by root: the build host's user means nothing inside it. mkschfs --owners FILE takes the exceptions, one path uid gid [mode] per line (tools/posix/mkaroot.sh writes it: the modes of /tmp, /var/tmp and /root). The setuid bits are set on su, passwd and doas in the root tree directly, because apk run as an ordinary user may have dropped them.

Not done

  • No PAM and no /etc/securetty. login is busybox's and checks /etc/shadow itself.
  • No capabilities. Root is euid == 0, all of it.
  • No per-user /run, no logind. X as a non-root user works (startx as schos, under QEMU: Window Maker up) by group permission alone — video, input and tty — and /etc/X11/Xwrapper.config lets anyone start it, because the wrapper's "console users" test looks for a Linux VT on a standard descriptor that xinit's server child does not keep.
  • /proc and /sys hide nothing from other users.
  • mprotect is still not enforced (kernel.md).