This setuid helper will allow a process to execute a target executable that will be able to drop privileges: - the setuid sandbox will create a new PID namespace or will switch uid/gid to isolate the process - a helper process, sharing the filesystem view of the existing process, will be created. It will accept a request to chroot() the process to an empty directory This is convenient because an executable can be launched, load libraries and open files and get chroot()-ed to an empty directory when it wants to drop filesystem access. Be sure to check the limitations below, as this can be dangerous. The Chrome/Chromium Linux sandbox is based on this design. Build instructions ------------------ 1. Install libcap2 and the appropriate headers (most likely, your distributions will offer a libcap-dev or libcap-devel package) 2. Use "make" 3. Install sandboxme as setuid root (chown root:root sandboxme && chmod 4511 sandboxme) Dumpable -------- A non dumpable process cannot be ptraced() by a process without CAP_SYS_PTRACE (usually limited to root). There are a couple of ways for a process to become non dumpable: - use a prctl() with PR_SET_DUMPABLE - execve() an executable that can't be read by the current process - Switch from uid 0 to a non 0 uid Please note that the "dumpable" state will be reset on execve() depending on whether or not the target can be read. UID isolation ------------- There are two main checks to take into consideration to assess the security of the pid isolation techniques: - The signal check in Linux is pretty relaxed. You can send a signal to any process with the same uid as you. For SIGCONT and SIGSTOP this is even more relaxed - The ptrace() check in Linux is pretty strict. You need to have the same privileges. Privileges include uid, gid and capabilities. If you don't have the CAP_SYS_PTRACE capability, the target also needs to be "dumpable" With this in mind, here are a few assessments: - If you get a new PID namespace, processes inside the sandbox cannot send signals or ptrace processes outside of the sandbox. However, processes outside of the sandbox can send signals to and ptrace processes inside the sandbox. Processes inside the sandbox can send signals or ptrace processes inside the the sandbox. It's up to processes inside the sandbox to protect themselves from ptrace() by becoming non dumpable if they want to. - If only the gid has been changed (-u1), sandboxed processes cannot ptrace unsandboxed processes, but they can send signals to them. Reciprocally, unsandboxed processes can send signals to sandboxed process but cannot ptrace them. If multiple users on the system are using sandboxme, their sandboxed processes will only share the same gid. - If both gid and uid have been changed (-u2), sandboxed processes from two different users on the system can ptrace and send signals to each other. ptrace() can be restricted by becoming non dumpable. Help: ----- Possible actions: chroot: - No chroot() helper (-c) uids/gids: - Do not switch uid or gid (-u0) - Switch gid to the one of "suidsandbox", but not the uid (-u1) - Switch uid and gid to "suidsandbox" (-u2) - Get a unique uid/gid and switch to it (-u3) - Like -u1 but accept failure as long as we have a new PID namespace (-u4, default) CLONE_NEWNET (-N) CLONE_NEWPID: - Fail if CLONE_NEWPID is not available (-P) - Do not try CLONE_NEWPID (-p) Example : $ /usr/sbin/sandboxme -- /bin/sh Helper: write to 4 ($SBX_D) to chroot the sandboxed process Could not find user suidsandbox Hi from the sandbox! I'm pid=1, uid=90422, gid=5000, dumpable=N Executing /bin/sh Warning: we will become dumpable after execve()! please make /bin/sh non readable sh-4.1$ pwd /home/jln sh-4.1$ echo C>&$SBX_D sh-4.1$ Helper: I chrooted you sh-4.1$ pwd / Limitations: ------------ - allows to escape from chroots if available in a chroot! (keep a FD to /, get chrooted to /something, fchdir to fd, open with relative path) - by design, can allow a process to become impossible to kill by a user (if the administrator created SANDBOXUSER) - sending signals is not prohibited from same uids if no new PID namespace was created - doesn't drop supplementary groups (we lack Windows' DENYONLY SIDs) - clone NEWPID: your process becomes the child reaper (init) of the new namespace. If this process exits, the namespace dies. - environment is not cleaned TODO: ----- - check permissions / ownership on chroot directory. Use /tmp (and chroot to the fd in /proc) ? - support a SAFE_BUNDLED mode with hardcoded target as a security-in-depth measure. - use prctl SECURE_NOROOT ? Note: the setuid bit will not be honored in what we execute next if we use the chroot() trick anyway. - cleanup the environment (XDG_SESSION_COOKIE and other sensitive information) - optimise do_setuid0 so that it doesn't iterate through all used pids first. - Patch ARGV0 so that the process explicitely shows up as sandboxed - reset all signal handlers?