Skip to main content

Phase 2: File Permissions

Motivation

After Phase 1 establishes who the user is, Phase 2 answers what they are allowed to touch. Without file permissions, a logged-in patient can open /device/config, overwrite /dosage/insulin.log, or read the audit log: defeating the entire point of authentication.

Phase 2 adds Unix-style DAC (Discretionary Access Control) to every inode.

The Permission Bit Model

Unix permission bits pack into a 16-bit mode word:

15–12 11–9 8–6 5–3 2–0
filetype (unused) owner group other
rwx rwx rwx

Each three-bit group:

Bit positionMeaning
r (bit 2)Read access
w (bit 1)Write access
x (bit 0)Execute access

Example: 0644 = rw-r--r--:

  • Owner: read + write
  • Group: read only
  • Other: read only

What Changed in struct dinode

/* kernel/fs.h: new fields on the on-disk inode */
struct dinode {
short type; // existing: T_FILE, T_DIR, T_DEVICE
short mode; // NEW: octal permission bits
short uid; // NEW: owner user ID
short gid; // NEW: owner group ID
// ... rest unchanged ...
};

The in-memory struct inode mirrors these fields. ialloc, iupdate, ilock, and stati all read and write the new fields.

Medical Files and Their Permissions

mkfs/mkfs.c creates these files at image build time:

PathModeOwnerAccessible by
/patient/records0400uid=1 (patient)Patient read-only, admin override
/dosage/insulin.log0620uid=2 (doctor)Doctor (rw), group write, admin override
/device/config0600uid=0 (admin)Admin only
/audit/syscall.log0400uid=0 (admin)Admin read-only

perm_check() Flowchart

The Four Enforcement Points

Every file access in xv6 passes through one of these four kernel locations:

HookFileWhen it runs
sys_open()kernel/sysfile.cBefore any file descriptor is created
fileread()kernel/file.cOn every read() syscall
filewrite()kernel/file.cOn every write() syscall
sys_exec()kernel/exec.cBefore loading a program image

Checking only at open is insufficient: an attacker with an already-open fd could still read/write after their permission is revoked.

chmod and chown Syscalls

# Inside xv6 shell (admin logged in)

# Restrict config to admin-only
chmod /device/config 0600

# Transfer ownership of a log file
chown /dosage/insulin.log 1 1

Both syscalls require the caller to be admin or the owner of the target file. A patient cannot chown their own records to another user.

Compliance Coverage

QEMU terminal showing patient denied on /device/config and allowed on /patient/records

TestWhat it checks
T07Patient cannot open /device/config (EACCES)
T08Patient can read /patient/records
T09Patient cannot write /patient/records (EACCES)
T10Clinician can write /dosage/insulin.log
T11Clinician cannot read /device/config (EACCES)
T12Admin can open all protected files

Known Implementation Detail: DIRSIZ

The filename compliance_test is 16 characters. The original xv6 DIRSIZ is 14. We increased it to 16:

/* kernel/fs.h */
#define DIRSIZ 16

This required updating mkfs.c to pad directory entries to the new size so that ls and directory reads remain aligned to struct dirent.