- 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
79 lines
4.2 KiB
Markdown
79 lines
4.2 KiB
Markdown
# 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](kernel.md)).
|