[tor-commits] [sandboxed-tor-browser/master] Tighten the seccomp rules some more.

yawning at torproject.org yawning at torproject.org
Thu Dec 8 06:40:39 UTC 2016


commit dcc1b9fffe82f55801b90c4ada9c21551e642f62
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Thu Dec 8 05:34:57 2016 +0000

    Tighten the seccomp rules some more.
    
     * Stop being lazy and validate all the socket() flags to allow tor.
    
     * Tighten the rlimit() related calls allowed to firefox.
       ASAN insists on being able to use `setrlimit()`.  I should drop
       support for the "hardened" channel because it increases attack
       surface.
---
 src/cmd/gen-seccomp/seccomp_firefox.go | 34 +++++++++++++++--
 src/cmd/gen-seccomp/seccomp_tor.go     | 69 ++++++++++++++++++++++++++++++++--
 2 files changed, 97 insertions(+), 6 deletions(-)

diff --git a/src/cmd/gen-seccomp/seccomp_firefox.go b/src/cmd/gen-seccomp/seccomp_firefox.go
index 9b25a66..03ed1fb 100644
--- a/src/cmd/gen-seccomp/seccomp_firefox.go
+++ b/src/cmd/gen-seccomp/seccomp_firefox.go
@@ -33,6 +33,9 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 	defer f.Release()
 
 	// TODO; Filter the arguments on more of these calls.
+	//
+	// Maybe draaw inspiration from:
+	// https://github.com/mozilla/gecko-dev/blob/master/security/sandbox/linux/SandboxFilter.cpp
 	allowedNoArgs := []string{
 		"clock_gettime",
 		"clock_getres",
@@ -149,7 +152,6 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 		"rt_sigprocmask",
 		"rt_sigreturn",
 		"sigaltstack",
-		"setrlimit",
 
 		"arch_prctl",
 		"capset",
@@ -175,6 +177,9 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 		"unshare",
 		"wait4",
 
+		// ASAN explodes if this doesn't work.  Sigh.
+		"setrlimit",
+
 		// Firefox uses this, but will take no for an answer.
 		// "quotactl",
 
@@ -198,7 +203,6 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 			"_llseek",
 
 			"mmap2",
-			"prlimit64",
 			"ugetrlimit",
 			"set_thread_area",
 			"waitpid",
@@ -225,10 +229,13 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 			return err
 		}
 
-		// Unrelated to sockets, only i386 needs this, and it can be filtered.
+		// Unrelated to sockets, only i386 needs these, and it can be filtered.
 		if err = allowCmpEq(f, "time", 0, 0); err != nil {
 			return err
 		}
+		if err = ffFilterPrlimit64(f); err != nil {
+			return err
+		}
 	}
 
 	// Because we patch PulseAudio's mutex creation, we can omit all PI futex
@@ -276,3 +283,24 @@ func ffFilterSocketcall(f *seccomp.ScmpFilter) error {
 	}
 	return allowCmpEq(f, "socketcall", 0, allowedCalls...)
 }
+
+func ffFilterPrlimit64(f *seccomp.ScmpFilter) error {
+	scall, err := seccomp.GetSyscallFromName("prlimit64")
+	if err != nil {
+		return err
+	}
+
+	// Per Mozilla's sandbox: only prlimit64(0, resource,  NULL, old_limit)
+	// which is functionally equivalent to getrlimit().  0 instead of the
+	// pid() is a glibc-ism.
+
+	isPid0, err := seccomp.MakeCondition(0, seccomp.CompareEqual, 0)
+	if err != nil {
+		return err
+	}
+	isNoNewLimit, err := seccomp.MakeCondition(2, seccomp.CompareEqual, 9)
+	if err != nil {
+		return err
+	}
+	return f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isPid0, isNoNewLimit})
+}
diff --git a/src/cmd/gen-seccomp/seccomp_tor.go b/src/cmd/gen-seccomp/seccomp_tor.go
index d6ec2ca..7300b64 100644
--- a/src/cmd/gen-seccomp/seccomp_tor.go
+++ b/src/cmd/gen-seccomp/seccomp_tor.go
@@ -23,6 +23,8 @@ import (
 	seccomp "github.com/seccomp/libseccomp-golang"
 )
 
+var maskedCloexecNonblock = ^(uint64(syscall.SOCK_CLOEXEC | syscall.SOCK_NONBLOCK))
+
 func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 	defer fd.Close()
 
@@ -292,7 +294,7 @@ func torFilterAccept4(f *seccomp.ScmpFilter) error {
 		return err
 	}
 
-	cond, err := seccomp.MakeCondition(3, seccomp.CompareMaskedEqual, 0, syscall.SOCK_CLOEXEC|syscall.SOCK_NONBLOCK)
+	cond, err := seccomp.MakeCondition(3, seccomp.CompareMaskedEqual, maskedCloexecNonblock, 0)
 	if err != nil {
 		return nil
 	}
@@ -318,8 +320,69 @@ func torFilterPoll(f *seccomp.ScmpFilter) error {
 }
 
 func torFilterSocket(f *seccomp.ScmpFilter) error {
-	// XXX: Tighten this some more.
-	return allowCmpEq(f, "socket", 0, syscall.AF_UNIX, syscall.AF_INET, syscall.AF_INET6 /*, syscall.AF_NETLINK */)
+	scall, err := seccomp.GetSyscallFromName("socket")
+	if err != nil {
+		return err
+	}
+
+	makeCondType := func(t uint64) (seccomp.ScmpCondition, error) {
+		return seccomp.MakeCondition(1, seccomp.CompareMaskedEqual, maskedCloexecNonblock, t)
+	}
+
+	// tor allows PF_FILE, which is PF_LOCAL on Linux, not sure why.
+
+	for _, d := range []uint64{syscall.AF_INET, syscall.AF_INET6} {
+		isDomain, err := seccomp.MakeCondition(0, seccomp.CompareEqual, d)
+		if err != nil {
+			return err
+		}
+
+		for _, t := range []uint64{syscall.SOCK_STREAM, syscall.SOCK_DGRAM} {
+			protocols := []uint64{syscall.IPPROTO_IP, syscall.IPPROTO_UDP}
+			if t == syscall.SOCK_STREAM {
+				protocols = append(protocols, syscall.IPPROTO_TCP)
+			}
+
+			isType, err := makeCondType(t)
+			if err != nil {
+				return err
+			}
+
+			for _, p := range protocols {
+				isProtocol, err := seccomp.MakeCondition(2, seccomp.CompareEqual, p)
+				if err != nil {
+					return err
+				}
+
+				if err = f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isDomain, isType, isProtocol}); err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	isAfLocal, err := seccomp.MakeCondition(0, seccomp.CompareEqual, syscall.AF_LOCAL)
+	if err != nil {
+		return err
+	}
+	for _, t := range []uint64{syscall.SOCK_STREAM, syscall.SOCK_DGRAM} {
+		isType, err := makeCondType(t)
+		if err != nil {
+			return err
+		}
+		isProtocol, err := seccomp.MakeCondition(2, seccomp.CompareEqual, 0)
+		if err != nil {
+			return err
+		}
+		if err = f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isAfLocal, isType, isProtocol}); err != nil {
+			return err
+		}
+	}
+
+	// tor allows socket(AF_NETLINK, SOCK_RAW, 0), which is used to check it's
+	// IP address, but will take "no".
+
+	return nil
 }
 
 func torFilterSetsockopt(f *seccomp.ScmpFilter) error {



More information about the tor-commits mailing list