Capabilities ============ reminder: lab 1 due this friday 11:59pm will hand out lab 2 sometime this weekend quick detour: finish up flume from last time persistent privileges: get a token/coupon for a capability how does the shell/editor example work? why endpoint labels? suppose user has two tags: web site and financial records, shell owns both wanted to transform (e.g. colorize) web page with some tool colorize index.html > color.html what if colorize reads in and outputs financial data? shell blindly writes it to color.html and exports it endpoint labels help shell avoid this mistake set label on colorize output (i.e. shell input) to web site tag only how does the web server work? who sets what labels? how does auth work? how do integrity guarantees work in the web server? how does plug-in code use base wiki code? (filters do label xforms) can we mount a "return-to-libc" attack using existing code? (unlikely) are all inputs integrity-checked? inputs from user browser not checked might not be high-integrity; not actually coming from user attacker can trick user's browser into issuing requests browser doesn't do label tracking, so no integrity information confused deputy problem what's the motivating problem in this paper? setuid-like compiler writes statistics to /sysx/stat user can trick it into overwriting other files (gcc .. -o /sysx/bill) what do these guys propose as the fundamental issue? ambient authority -- privileges (e.g. Unix uid) automatically used name for a resource is separate from the privileges for accessing it related problem: TOCTTOU bugs what's their proposed solution? capabilities: whenever you name sth, explicitly specify the privs when would this help, or not help? easier to write secure privileged code (unlikely to misuse privileges) not any easier to avoid buffer overflows does not help existing applications must change applications to pass capabilities instead of other names can you think of other examples of ambient authority? Unix users (and things it controls: FS, process kill/debug, etc) HTTP URLs and their cookies IP addresses (vs firewalls) flume's strawman design without endpoints what about examples of capabilities? unix file descriptors java object pointers/refs (will talk more about these next lecture) cool thing about capabilities: can delegate without giving all your privs! microkernels KeyKOS: one example of a microkernel OS, built around capabilities motivation: OS kernel too complex -- security bugs, hard to change, .. OS abstractions: process, file, socket, shmem, user, tty, drivers, .. syscalls: read, write, mkdir, kill, stty, ioctl, connect, pipe, mmap.. idea: implement as little as possible in the OS kernel, rest in user-space typical goal: small kernel, userspace FS, TCP, display, process mgmt can pick your own FS if you feel like it, or your own TCP stack typical result: one big user-space blob called "Unix emulation" KeyKOS was quite different, had many user-space components keykos kernel interface device: access to underlying HW, given to device driver process page: 4KB of memory node: a block of 16 keys (capabilities) other things implemented using nodes: segment: sequence of pages (think file), impl. using a node meter: explicit CPU time allocation domain: something like a Unix process what does a domain look like? 16 general-purpose key slots ("capability registers") address slot: key to virtual memory segment meter slot: key to CPU meter keeper slot: key to another domain (process) to handle exceptions objects named by keys key is a 12-byte blob, but cannot be manipulated directly (like fd) 1 byte reserved for application use (to store information about key) e.g. "only allow read-only access" special KeyBits service lets you look at the 12-byte blob three system calls: void FORK(key k, msg m): send m to k's domain, continue running msg *CALL(key k, msg m): send m (+ resume key) to k's domain, suspend msg *RETURN(key k, msg m): send m to k's domain, wait for next msg called domain gets the application reserved byte of the caller's key can pass up to 4 keys as part of the message (or more, by using a node) everything else is implemented using messages to domains device access: CALL the device driver memory mapping: include memory key in your address space segment accessing a file: CALL the file system object keepers handle exceptions segment keeper: handles page faults ideally, want memory accesses to translate into IPC messages hardware doesn't quite work this way, so keykos compromises address space is a cache, IPC on cache misses meter keeper: called when meter runs out of CPU time (accounting) domain keeper: other CPU exceptions (divide by zero, Unix syscalls) kernel makes the exception look like a call to the keeper domain keeper gets a "service key" to fix up the faulting object as needed resource allocation space bank: a special domain that holds keys to all pages and nodes can create sub-banks (e.g. give user a sub-bank with 1MB of pages) can revoke allocations special kernel support to zero out keys pointing to allocated objs how does keykos solve the problem of privilege persistence? everything is persistent, so nothing is ephemeral or "lost" what happens if you lose a capability? no way to get it back kernel periodically checkpoints entire system state to disk how do applications use disk? just store things in memory / read from mem problems with persistence? saves lots of extra state need to have a plan for runaway processes (no reboot) explicit resource control through meters and space banks helps using KeyKOS (or predecessor GNOSIS): looks very different from Unix no file system root every user has their own "home directory", which maps names to keys home directory stores both files and processes one user cannot access another user's home dir (unless granted the key) where does the user's home directory come from? each user has a persistently-running shell that has the home dir key login ("receptionist") keeps a password and start key for user's shell at login time, receptionist passes user's terminal to user's shell when invoking commands, must pass all capabilities explicitly (need to specify whether each argument is a string or a capability) KeyNIX design unix keeper emulates unix system calls separate keeper for each process global segment stores shared state process table file descriptors KeyNIX FS design separate domain for each file and directory file is basically a segment to read/write, insert segment into address space and read/write memory separated from the rest of FS code, can implement optimizations store small files together (in inode itself) compressed files? directory supports lookup, insert, unlink messages what happens on a crash? can you get an inconsistent directory? access control unix model: uid used to make access control decisions explicitly at odds with capabilities/keykos paper doesn't say how perms worked in keynix (likely not very much) simple version: Unix keeper tracks uid, makes access control checks better version: special keys for file owner vs. everyone else file owner might be able to write, while everyone else is read-only user would get special key for home dir (not via /home/user) kept by login service, or by dir, with a "dirlookup-with-pw" op does keynix avoid the confused deputy problem? not really: that was all about changing the application to use capabilities keykos/gnosis shell probably did, though fixing would require changing all unix applications what's good or bad about KeyNIX? fault isolation between unix keeper domains what happens if a kernel is compromised? can corrupt shared state segment user can decide to run an application in a separate KeyNIX universe just create a new shared state segment can we do better with a single KeyNIX "universe"? maybe store each file descriptor in a separate segment processes are a bit trickier: need to locate process given its PID maybe solvable -- partition processes into per-user process tables? can we implement some of flume's examples with capabilities? how about the shell/editor example? probably so -- only give editor access to the file & terminal caps even better than before: no need for the shell to be in the data path can give editor access to just one file, without a tag per file upfront how about the web server? might not know what capabilities wiki.py needs ahead of time e.g. one wiki page includes/inlines another wiki page wiki.py needs to open another page by name -- how to do this? (a) have a component that looks up capability for a named page and does access control checks at the same time (b) give pages capability-like names intrusive: user-visible, at odds with the idea of a page ACL ambient authority (or at least having names decoupled from privs) is useful users often think of objects separately from access control one big win for capability ideas: distributed systems