[tor-commits] [sandboxed-tor-browser/master] Bug #20782: Use a combined tor + obfs4proxy seccomp whitelist for now.

yawning at torproject.org yawning at torproject.org
Mon Nov 28 19:33:11 UTC 2016


commit 7cf5fba78a7641043454f7f7d24edce4ed938197
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Mon Nov 28 18:40:49 2016 +0000

    Bug #20782: Use a combined tor + obfs4proxy seccomp whitelist for now.
    
    In an ideal world these will live in separate containers and have their
    own rules, but till then this is better than the blacklist.
---
 data/tor-obfs4-whitelist.seccomp                   | 147 +++++++++++++++++++++
 .../internal/sandbox/application.go                |   6 +-
 .../internal/sandbox/seccomp.go                    |  10 +-
 .../internal/sandbox/seccomp_386.go                |   1 +
 .../internal/sandbox/seccomp_amd64.go              |   2 +
 5 files changed, 159 insertions(+), 7 deletions(-)

diff --git a/data/tor-obfs4-whitelist.seccomp b/data/tor-obfs4-whitelist.seccomp
new file mode 100644
index 0000000..773c5b7
--- /dev/null
+++ b/data/tor-obfs4-whitelist.seccomp
@@ -0,0 +1,147 @@
+# tor +obfs4proxy binary seccomp rules based off the tor sandbox and the
+# subgraph tor-browser-launcher rules, along with some quality time with
+# strace.
+
+#
+# WARNING: This is a stopgap.  In an ideal world, tor and obfs4proxy will
+# have separate containers, with their own seccomp rules.
+#
+
+# Constants used for argument comparisons.
+SIG_BLOCK=1
+SIG_SETMASK=2
+MREMAP_MAYMOVE=1
+PF_LOCAL=AF_LOCAL
+POLLIN=1
+
+# The tor stage 1 set.
+access: 1
+brk: 1
+clock_gettime: 1
+close: 1
+clone: 1
+epoll_create: 1
+epoll_wait: 1
+eventfd2: 1
+pipe2: 1
+pipe: 1
+fcntl: 1
+fstat: 1
+# fstat64: 1
+getdents: 1
+getdents64: 1
+getegid: 1
+# getegid32: 1
+geteuid: 1
+# geteuid32: 1
+getgid: 1
+# getgid32: 1
+getrlimit: 1
+gettimeofday: 1
+gettid: 1
+getuid: 1
+# getuid32: 1
+lseek: 1
+#_llseek: 1
+mkdir: 1
+munmap: 1
+prlimit64: 1
+read: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sched_yield: 1
+sendmsg: 1
+set_robust_list: 1
+setrlimit: 1
+sigaltstack: 1
+# sigreturn: 1
+stat: 1
+uname: 1
+wait4: 1
+write: 1
+writev: 1
+exit_group: 1
+exit: 1
+madvise: arg2 == 8
+getrandom: 1
+sysinfo: 1
+bind: 1
+listen: 1
+connect: 1
+getsockname: 1
+recvmsg: 1
+recvfrom: 1
+sendto: 1
+unlink: 1
+
+# System calls that tor restricts by argument.
+rt_sigprocmask: arg0 == SIG_BLOCK || arg0 == SIG_SETMASK
+time: arg0 == 0
+epoll_ctl: arg1 == EPOLL_CTL_ADD || arg1 == EPOLL_CTL_MOD || arg1 == EPOLL_CTL_DEL
+prctl: (arg0 == PR_SET_DUMPABLE && arg1 == 0) || arg0 == PR_SET_PDEATHSIG
+mprotect: arg2 == PROT_READ || arg2 == PROT_NONE || arg2 == PROT_READ | PROT_WRITE
+flock: arg1 == (LOCK_EX | LOCK_NB) || arg1 == LOCK_UN
+# FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME || FUTEX_WAKE_PRIVATE || FUTEX_WAIT_PRIVATE
+futex: arg1 == 393 || arg1 == 128 || arg1 == 129 || arg1 == 1 || arg1 == 0
+mremap: arg3 == MREMAP_MAYMOVE
+poll: arg1 == POLLIN && arg2 == 10
+socket: arg0 == AF_UNIX || arg0 == AF_INET || arg0 == AF_INET6 || arg0 == AF_NETLINK
+setsockopt: (arg1 == SOL_SOCKET && (arg2 == SO_REUSEADDR || arg2 == SO_SNDBUF || arg2 == SO_RCVBUF || arg2 == SO_BROADCAST)) || (arg1 == SOL_TCP && arg2 == TCP_NODELAY) || (arg1 == SOL_IPV6 && arg2 == IPV6_V6ONLY)
+getsockopt: arg1 == SOL_SOCKET && arg2 == SO_ERROR
+# XXX: src/common/compat.c:tor_socketpair looks like it uses SOCK_CLOEXEC,
+# but according to strace, fcntl is used to actually set the flag (6.0.6).
+socketpair: arg0 == PF_LOCAL && (arg1 == SOCK_STREAM || arg1 == SOCK_STREAM | SOCK_CLOEXEC)
+# XXX/yawning: Tor doesn't have filters for this, but does for mmap2, but mmap2
+# is an x86-ism, so can't filter args.
+#
+# (PROT_READ|PROT_EXEC, MAP_PRIVATE | MAP_DENYWRITE) is needed for ld-linux.so
+mmap: (arg2 == PROT_READ && arg3 == MAP_PRIVATE) || (arg2 == PROT_NONE && (arg3 == MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE || arg3 == MAP_PRIVATE | MAP_ANONYMOUS || arg3 == MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS)) || (arg2 == PROT_READ | PROT_WRITE && ((arg3 == MAP_PRIVATE | MAP_ANONYMOUS) || (arg3 == MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK) || (arg3 == MAP_PRIVATE | MAP_FIXED | MAP_DENYWRITE) || (arg3 == MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS) || (arg3 == MAP_PRIVATE | MAP_DENYWRITE))) || (arg2 == PROT_READ | PROT_EXEC && arg3 == MAP_PRIVATE | MAP_DENYWRITE)
+
+# System calls that tor has filters for, that we do not due to:
+#  * Yawning being too dumb/lazy to convert the rules (accept4, mmap2,
+#    rt_sigaction).
+rt_sigaction: 1
+accept4: 1
+# mmap2: 1
+# fcntl64: 1
+
+# System calls that tor restricts by argument, but that need to be done by the
+# tor binary, because the restriction is by pointer.
+chown: 1
+chmod: 1
+open: 1
+openat: 1
+rename: 1
+# stat64: 1
+
+# System calls that tor needs, but doesn't know it needs, because they are made
+# prior to Tor's sandbox enforcement, either by tor, it's dependencies, or even
+# by bubblewrap.
+arch_prctl: 1
+unshare: 1
+getpid: 1
+kill: 1
+execve: 1
+restart_syscall: 1
+set_tid_address: 1
+chdir: 1
+umask: arg0 == 022
+
+# obfs4proxy requires the following:
+#
+# Note that it also requires additional things to be allowed in the various
+# arg filters, which are made at the pre-existing locations.
+# `mprotect` -> `arg2 == PROT_READ | PROT_WRITE`
+# `futex` -> `arg1 == 1 || arg1 == 0` (FUTEX_WAKE, FUTEX_WAIT)
+# `setsockopt` -> `arg1 == SOL_TCP && arg2 == TCP_NODELAY`
+#                 `arg1 == SOL_SOCKET && arg2 == SO_BROADCAST`
+#                 `arg1 == SOL_IPV6 && arg2 == IPV6_V6ONLY`
+# `mmap` -> `arg2 == PROT_NONE && (arg3 == MAP_PRIVATE|MAP_ANONYMOUS || arg3 == MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS)`
+mincore: 1
+dup2: 1
+select: 1
+mkdirat: 1
+fsync: 1
+epoll_create1: arg0 == EPOLL_CLOEXEC
+getpeername: 1
+getppid: 1
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
index 26baeef..a431dac 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
@@ -456,11 +456,7 @@ func RunTor(cfg *config.Config, manif *config.Manifest, torrc []byte) (cmd *exec
 	logger := newConsoleLogger("tor")
 	h.stdout = logger
 	h.stderr = logger
-	if !cfg.Tor.UseBridges {
-		h.seccompFn = installTorSeccompProfile
-	} else {
-		h.seccompFn = installBasicSeccompBlacklist
-	}
+	h.seccompFn = func(fd *os.File) error { return installTorSeccompProfile(fd, cfg.Tor.UseBridges) }
 	h.unshare.net = false // Tor needs host network access.
 
 	// Regarding `/proc`...
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp.go
index dafa279..de625d9 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp.go
@@ -21,6 +21,7 @@ import "os"
 const (
 	torBrowserWhitelist = "torbrowser-launcher-whitelist.seccomp"
 	torWhitelist        = "tor-whitelist.seccomp"
+	torObfs4Whitelist   = "tor-obfs4-whitelist.seccomp"
 	basicBlacklist      = "blacklist.seccomp"
 )
 
@@ -28,8 +29,13 @@ func installTorBrowserSeccompProfile(fd *os.File) error {
 	return installSeccomp(fd, torBrowserSeccompAssets, false)
 }
 
-func installTorSeccompProfile(fd *os.File) error {
-	return installSeccomp(fd, torSeccompAssets, false)
+func installTorSeccompProfile(fd *os.File, useBridges bool) error {
+	assets := torSeccompAssets
+	if useBridges {
+		assets = torObfs4SeccompAssets
+	}
+
+	return installSeccomp(fd, assets, false)
 }
 
 func installBasicSeccompBlacklist(fd *os.File) error {
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_386.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_386.go
index 40e5691..0d3a069 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_386.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_386.go
@@ -37,6 +37,7 @@ const (
 
 var torBrowserSeccompAssets = []string{torBrowserWhitelist, torBrowserExtraWhitelist}
 var torSeccompAssets = []string{torWhitelist, torExtraWhitelist}
+var torObfs4SeccompAssets = []string{torObfs4Whitelist, torExtraWhitelist}
 var blacklistSeccompAssets = []string{basicBlacklist, basicExtraBlacklist}
 
 // installSeccomp on i386 implements a minimal subset of the gosecco
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_amd64.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_amd64.go
index e495103..2ed4cf5 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_amd64.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/seccomp_amd64.go
@@ -55,6 +55,7 @@ var blacklistSettings = &gosecco.SeccompSettings{
 
 var torBrowserSeccompAssets = []string{torBrowserWhitelist}
 var torSeccompAssets = []string{torWhitelist}
+var torObfs4SeccompAssets = []string{torObfs4Whitelist}
 var blacklistSeccompAssets = []string{basicBlacklist}
 
 func installSeccomp(fd *os.File, assets []string, isBlacklist bool) error {
@@ -65,6 +66,7 @@ func installSeccomp(fd *os.File, assets []string, isBlacklist bool) error {
 		settings = blacklistSettings
 	}
 
+	// XXX: This really should support multile assets.
 	if len(assets) != 1 {
 		return fmt.Errorf("seccomp: asset vector length > 1: %d", len(assets))
 	}



More information about the tor-commits mailing list