Tor Capsicum Call For Testing (CFT) ===================================
Capsicum is a capabilities framework for FreeBSD and its derivatives. It's commonly used to implement sandboxing. Tor currently supports sandboxing only on Linux, via seccomp-filter. This CFT presents initial Capsicum support for Tor on FreeBSD and HardenedBSD. The work performed is sponsored by HardenedBSD.
The source for the Capsicum work can be found at https://github.com/lattera/tor. The branch to use is the hardening/capsicum branch. We hope that this implementation, or a future revision of it, will be merged upstream by the Tor Project.
Design and Architecture -----------------------
When capabilities mode (capmode) is entered (ie, the sandbox is enabled), the kernel will prevent Tor from accessing the global namespace. This means that once the sandbox is enabled, Tor will not be able to open files, create sockets, connect outbound, etc.
Naturally, applications like Tor needs to be able to create sockets on-demand and at-will. In these situations, it is common to fork a child process which will perform these "privileged" operations. Only the parent process will enter capmode. Communication between the parent and the child is performed via a socketpair descriptor.
Wrappers in the parent process call into the child process to perform these privileged operations. Thus, open(2) becomes sandbox_open(), rename(2) becomes sandbox_rename(), and so on. A full list of wrapped operations will be provided further on.
When the parent process wants to open a file, it will call sandbox_open. The parent process will tell the child via the socketpair to open the file and limit its capabilities. On success, the child will return the limited file descriptor back to the parent.
We prevent race conditions surrounding the limitation of file descriptors by calling cap_rights_limit(2) on the descriptor in the child before passing the descriptor back to the parent. By the time the parent can make use of the descriptor, the descriptor is fully limited to a minimal set of capabilities.
Tor's existing sandbox abstraction API relies on a filtering-based approach. We've utilized parts of that API to provide a basic whitelist. Once capmode is entered, the whitelist turns read-only and cannot be modified.
Efforts to apply Capsicum in the form of wrappers, such as has been done in this work and others, require ASLR and W^X to be effective. Without ASLR, an attacker could simply craft an exploit to return into the respecive wrapper and bypass any guarantees Capsicum provides. Additionally, Control Flow Integrity (CFI) from clang/llvm will provide forward-edge guarantees. SafeStack from clang/llvm will provide backward-edge guarantees.
Known Issues ------------
Enabling the sandbox while having Tor configured in transparent proxy mode is currently broken. We are researching what causes the breakage. Chances are that either Tor is trying to access the global namespace in transparent proxy mode or one or more file descriptors simply need to be granted one or more extra capabilities.
Future Work -----------
We plan to research and fix, if possible, the known regression regarding transparent proxying.
The read-only nature of the whitelist is only enforced via a logic operation. We plan to relocate the whitelist into a memory mapping that will turn read-only upon entering capmode.
The current implementation should be further abstracted in order for Tor to be able to pick at runtime the appropriate sandbox implementation. This would be similar to how Tor chooses which ed25519 implementation to use, donna or ref10.
Testing and Reporting Back --------------------------
1. Install required development tools:
# pkg install libevent autoconf automake autotools libtool gmake \ git-lite
2. Clone the git repo:
# git clone https://github.com/lattera/tor.git
3. Check out the hardening/capsicum branch:
# cd tor # git checkout -b hardening/capsicum origin/hardening/capsicum
4. Regenerate autoconf magic:
# ./autogen.sh
5. Run the configure script:
# ./configure [custom arguments to configure as you'd prefer]
6. Build and install:
# gmake -j$(sysctl -n hw.ncpu) && gmake install
7. Enable the sandbox in the torrc:
# echo "Sandbox 1" >> [path to torrc]
8. Run Tor:
# tor
9. Report results:
Email shawn.webb@hardenedbsd.org, report back any issues you may have. If your testing succeeds, I'd like to hear about it, too. Please do not open any tickets regarding this work on the Tor Project's Trac instance. Contact me directly.
A sample report back would include a sanitized torrc along with a pass/fail result. A successful result would mean that all features you rely on work as desired. A failed result would mean that enabling a feature results in Tor crashing, erroring out, or exhibiting bugs. If Tor crashes for you, please include a backtrace if possible.
New Sandbox Wrappers --------------------
These APIs will need to be used regardless of operating system. On operating systems outside of FreeBSD and HardenedBSD, they are simply macros that forward to their respective native API call.
* int sandbox_close(int fd): close(2) wrapper * int sandbox_rename(const char *from, const char *to): rename(2) wrapper * int sandbox_stat(const char *path, struct stat *sb): stat(2) wrapper * int sandbox_mkdir(const char *path, mode_t mode): mkdir(2) wrapper * int sandbox_connect(int sockfd, const struct sockaddr *name, socklen_t namelen): connect(2) wrapper * int sandbox_socket(int domain, int type, int protocol, cap_rights_t *rights): socket(2) wrapper * int sandbox_unlink(const char *path): unlink(2) wrapper * int sandbox_open(const char *path, int flags, mode_t mode, cap_rights_t *rights): open(2) wrapper