Table of Contents
Race condition: connect() on Unix domain sockets presumably follows symlinks, and there is no way to switch this off. This means an adversary could replace a domain socket with a symlink to exploit the race condition and open sockets in the server's namespace. (bind() probably doesn't follow symlinks; it probably behaves like open() with O_CREAT|O_EXCL.) Note that this is a race condition between servers. If there was only one server process providing real filesystem objects, there would be no race condition, because socket_connect() would be atomic. Possible solution: * The server has a private directory in which no server will create symlinks on behalf of a client. The server's socket_connect() method hardlinks the socket file into the private directory, checks that the object that got hardlinked is not a symlink, and then calls connect() on it. * Problem: this doesn't work across devices. We could try creating a hard link in the same directory, but that doesn't work if the server doesn't have write access to the directory. (But then, if the server doesn't have write access *and other servers don't either* the symlink attack cannot be carried out.) Doing this in /tmp/.X11-unix creates a file that is owned by root in a directory owned by root (with the sticky bit set), which then cannot be deleted. (The sticky bit means you can unlink an object only if you own it, or you own the directory.) * We could have a list of directories into which we try to create hard links. These are tried in turn. The user can set these up to cover all the filesystems. Plash would have to create a directory per user ID inside these directories (as in /tmp) -- incidentally, this means the sticky bit isn't necessary, because processes with other user IDs can't delete the directories while they're in use. What should the default be? "/tmp/plash/" This would be enough for opening X11 sockets. How should this be configured? Via an environment variable? We would want to unset this so that programs run under Plash don't see it. Via a configuration file in /etc? /etc/plash/hardlink-dirs could contain a list of directories, each on a separate line. See http://cert.uni-stuttgart.de/archive/bugtraq/1999/10/msg00011.html SSH authentication agent follows symlinks via a UNIX domain socket Race conditions in gc-uid-locks: This race means that run-as-anonymous could assign a process a UID that *is* currently in use. If a process manages to get the same UID as another, it can kill the other process, or worse, ptrace() it and gain its authority. The risk is very low, because a program inside the chroot() environment can't run run-as-anonymous or gc-uid-locks. * If gc-uid-locks runs between run-as-anonymous claiming the lock file and changing its uid, gc-uid-locks will delete the lock file * Solution: run-as-anonymous should set its group before claiming the lock file * gc-uid-locks reads uids first then locks. Consider: * gc-uid-locks reads uids * run-as-anonymous sets uids, claims lock * gc-uid-locks reads lock files -> deletes lock that actually in use Solution: read lock files first. * gc-uid-locks deletes lock file after checks: * gc-uid-locks[1] determines that lock file F is to be deleted * gc-uid-locks[2] deletes F * run-as-anonymous claims lock file F * gc-uid-locks[1] deletes F, but it's actually in use Solution: gc-uid-locks should have its own mutual exclusion lock Assumptions: that /proc/ is a reliable, *atomic* way of reading uid/gids Running as root: /dev/tty is a writable slot; it should be a writable object in a read-only slot * The same applies to /tmp/.X11-unix