[tor-commits] [sandboxed-tor-browser/master] Filter socketcall() by argument.

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


commit 1db6b5aeec0983b264469be96690d916e236e314
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Wed Dec 7 07:05:09 2016 +0000

    Filter socketcall() by argument.
    
    This still isn't great, particularly firefox that appears to need all
    the socket calls, but at least this denies calls that neither container
    needs.
---
 src/cmd/gen-seccomp/main.go            |  2 -
 src/cmd/gen-seccomp/seccomp.go         | 28 ++++++++--
 src/cmd/gen-seccomp/seccomp_firefox.go | 57 +++++++++++++++-----
 src/cmd/gen-seccomp/seccomp_tor.go     | 96 +++++++++++++++++++---------------
 4 files changed, 119 insertions(+), 64 deletions(-)

diff --git a/src/cmd/gen-seccomp/main.go b/src/cmd/gen-seccomp/main.go
index 3ad1be5..5dcbbf2 100644
--- a/src/cmd/gen-seccomp/main.go
+++ b/src/cmd/gen-seccomp/main.go
@@ -32,8 +32,6 @@ func main() {
 		log.Fatalf("failed to get absolute path: %v", err)
 	}
 
-	log.Printf("outDir: %v", outDir)
-
 	// Tor Browser (amd64)
 	f, err := os.Create(filepath.Join(outDir, "tor-amd64.bpf"))
 	if err != nil {
diff --git a/src/cmd/gen-seccomp/seccomp.go b/src/cmd/gen-seccomp/seccomp.go
index 9ec17e8..ece1e7e 100644
--- a/src/cmd/gen-seccomp/seccomp.go
+++ b/src/cmd/gen-seccomp/seccomp.go
@@ -66,6 +66,28 @@ const (
 	fionread  = 0x541b
 	tcgets    = 0x5401
 	tiocgpgrp = 0x540f
+
+	// socketcall() call numbers (linux/net.h)
+	sysSocket      = 1  // sys_socket()
+	sysBind        = 2  // sys_bind()
+	sysConnect     = 3  // sys_connect()
+	sysListen      = 4  // sys_listen()
+	sysAccept      = 5  // sys_accept()
+	sysGetsockname = 6  // sys_getsockname()
+	sysGetpeername = 7  // sys_getpeername()
+	sysSocketpair  = 8  // sys_socketpair()
+	sysSend        = 9  // sys_send()
+	sysRecv        = 10 // sys_recv()
+	sysSendto      = 11 // sys_sendto()
+	sysRecvfrom    = 12 // sys_recvfrom()
+	sysShutdown    = 13 // sys_shutdown()
+	sysSetsockopt  = 14 // sys_setsockopt()
+	sysGetsockopt  = 15 // sys_getsockopt()
+	sysSendmsg     = 16 // sys_sendmsg()
+	sysRecvmsg     = 17 // sys_recvmsg()
+	sysAccept4     = 18 // sys_accept4()
+	sysRecvmmsg    = 19 // sys_recvmmsg
+	sysSendmmsg    = 20 // sys_sendmmsg
 )
 
 func newWhitelist(is386 bool) (*seccomp.ScmpFilter, error) {
@@ -95,11 +117,7 @@ func allowSyscalls(f *seccomp.ScmpFilter, calls []string, is386 bool) error {
 	for _, scallName := range calls {
 		scall, err := seccomp.GetSyscallFromName(scallName)
 		if err != nil {
-			if is386 && scallName == "newselect" {
-				scall = seccomp.ScmpSyscall(142)
-			} else {
-				return fmt.Errorf("seccomp: unknown system call: %v", scallName)
-			}
+			return fmt.Errorf("seccomp: unknown system call: %v", scallName)
 		}
 		if err = f.AddRule(scall, seccomp.ActAllow); err != nil {
 			return err
diff --git a/src/cmd/gen-seccomp/seccomp_firefox.go b/src/cmd/gen-seccomp/seccomp_firefox.go
index 22e4bb5..9b25a66 100644
--- a/src/cmd/gen-seccomp/seccomp_firefox.go
+++ b/src/cmd/gen-seccomp/seccomp_firefox.go
@@ -19,6 +19,8 @@ package main
 import (
 	"os"
 	"syscall"
+
+	seccomp "github.com/seccomp/libseccomp-golang"
 )
 
 func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
@@ -30,6 +32,7 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 	}
 	defer f.Release()
 
+	// TODO; Filter the arguments on more of these calls.
 	allowedNoArgs := []string{
 		"clock_gettime",
 		"clock_getres",
@@ -207,11 +210,7 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 
 			"recv",
 			"send",
-			"newselect",
-
-			"socket", // Filtered on amd64.
-
-			"socketcall", // Fuck Debian stable.... :(
+			"_newselect",
 		}
 		allowedNoArgs = append(allowedNoArgs, allowedNoArgs386...)
 	}
@@ -219,6 +218,19 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 		return err
 	}
 
+	// Like with how I do the tor rules, handle socketcall() before everything
+	// else.
+	if is386 {
+		if err = ffFilterSocketcall(f); err != nil {
+			return err
+		}
+
+		// Unrelated to sockets, only i386 needs this, and it can be filtered.
+		if err = allowCmpEq(f, "time", 0, 0); err != nil {
+			return err
+		}
+	}
+
 	// Because we patch PulseAudio's mutex creation, we can omit all PI futex
 	// calls.
 	if err = allowCmpEq(f, "futex", 1, futexWait, futexWaitPrivate, futexWakePrivate, futexCmpRequeuePrivate, futexWakeOpPrivate, futexWaitBitsetPrivate|futexClockRealtime, futexWake, futexWaitBitsetPrivate); err != nil {
@@ -234,16 +246,33 @@ func compileTorBrowserSeccompProfile(fd *os.File, is386 bool) error {
 	if err = allowCmpEq(f, "prctl", 0, syscall.PR_SET_NAME, syscall.PR_GET_NAME, syscall.PR_GET_TIMERSLACK, syscall.PR_SET_SECCOMP); err != nil {
 		return err
 	}
-
-	if is386 {
-		if err = allowCmpEq(f, "time", 0, 0); err != nil {
-			return err
-		}
-	} else {
-		if err = allowCmpEq(f, "socket", 0, syscall.AF_UNIX); err != nil {
-			return err
-		}
+	if err = allowCmpEq(f, "socket", 0, syscall.AF_UNIX); err != nil {
+		return err
 	}
 
 	return f.ExportBPF(fd)
 }
+
+func ffFilterSocketcall(f *seccomp.ScmpFilter) error {
+	// This is kind of pointless because it allows basically all the things.
+	allowedCalls := []uint64{
+		sysSocket,
+		sysBind,
+		sysConnect,
+		sysListen,
+		sysGetsockname,
+		sysGetpeername,
+		sysSocketpair,
+		sysSend,
+		sysRecv,
+		sysSendto,
+		sysRecvfrom,
+		sysShutdown,
+		sysSetsockopt,
+		sysGetsockopt,
+		sysSendmsg,
+		sysRecvmsg,
+		sysAccept4,
+	}
+	return allowCmpEq(f, "socketcall", 0, allowedCalls...)
+}
diff --git a/src/cmd/gen-seccomp/seccomp_tor.go b/src/cmd/gen-seccomp/seccomp_tor.go
index 0a1b8cc..d6ec2ca 100644
--- a/src/cmd/gen-seccomp/seccomp_tor.go
+++ b/src/cmd/gen-seccomp/seccomp_tor.go
@@ -118,14 +118,18 @@ func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 
 			"ugetrlimit",
 			"set_thread_area",
-
-			"socketcall", // I *SHOULDN"T* need this, but Debian stable freaks out.
 		}
 		allowedNoArgs = append(allowedNoArgs, allowedNoArgs386...)
 	}
 	if err = allowSyscalls(f, allowedNoArgs, is386); err != nil {
 		return err
 	}
+	if is386 {
+		// Handle socketcall() before filtering other things.
+		if err = torFilterSocketcall(f, useBridges); err != nil {
+			return err
+		}
+	}
 
 	if err = allowCmpEq(f, "time", 0, 0); err != nil {
 		return err
@@ -157,22 +161,22 @@ func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 	if err = allowCmpEq(f, "mremap", 3, mremapMaymove); err != nil {
 		return err
 	}
-	if err = torFilterAccept4(f, is386); err != nil {
+	if err = torFilterAccept4(f); err != nil {
 		return err
 	}
 	if err = torFilterPoll(f); err != nil {
 		return err
 	}
-	if err = torFilterSocket(f, is386); err != nil {
+	if err = torFilterSocket(f); err != nil {
 		return err
 	}
-	if err = torFilterSetsockopt(f, is386); err != nil {
+	if err = torFilterSetsockopt(f); err != nil {
 		return err
 	}
-	if err = torFilterGetsockopt(f, is386); err != nil {
+	if err = torFilterGetsockopt(f); err != nil {
 		return err
 	}
-	if err = torFilterSocketpair(f, is386); err != nil {
+	if err = torFilterSocketpair(f); err != nil {
 		return err
 	}
 	if err = torFilterMmap(f, is386); err != nil {
@@ -196,7 +200,7 @@ func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 			"getppid",
 		}
 		if is386 {
-			obfsCalls = append(obfsCalls, "newselect")
+			obfsCalls = append(obfsCalls, "_newselect")
 		}
 		if err = allowSyscalls(f, obfsCalls, is386); err != nil {
 			return err
@@ -212,7 +216,7 @@ func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 		if err = allowCmpEq(f, "futex", 1, futexWake, futexWait); err != nil {
 			return err
 		}
-		if err = obfsFilterSetsockopt(f, is386); err != nil {
+		if err = obfsFilterSetsockopt(f); err != nil {
 			return err
 		}
 		if err = obfsFilterMmap(f, is386); err != nil {
@@ -223,6 +227,40 @@ func compileTorSeccompProfile(fd *os.File, useBridges bool, is386 bool) error {
 	return f.ExportBPF(fd)
 }
 
+func torFilterSocketcall(f *seccomp.ScmpFilter, useBridges bool) error {
+	// This interface needs to die in a fire, because it's leaving
+	// gaping attack surface.  It kind of will assuming that things
+	// move on to 4.3 or later.
+	//
+	// Emperically on Fedora 25 getsockopt and setsockopt still are
+	// multiplexed, though that may just be my rules or libseccomp2.
+	//
+	// Re-test after Debian stable moves to a modern kernel.
+
+	allowedCalls := []uint64{
+		sysSocket,
+		sysBind,
+		sysConnect,
+		sysListen,
+		sysGetsockname,
+		sysSocketpair,
+		sysSend,
+		sysRecv,
+		sysSendto,
+		sysRecvfrom,
+		sysSetsockopt,
+		sysGetsockopt,
+		sysSendmsg,
+		sysRecvmsg,
+		sysAccept4,
+	}
+	if useBridges {
+		allowedCalls = append(allowedCalls, sysGetpeername)
+	}
+
+	return allowCmpEq(f, "socketcall", 0, allowedCalls...)
+}
+
 func torFilterPrctl(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("prctl")
 	if err != nil {
@@ -248,17 +286,11 @@ func torFilterPrctl(f *seccomp.ScmpFilter) error {
 	return f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isPrSetDeathsig})
 }
 
-func torFilterAccept4(f *seccomp.ScmpFilter, is386 bool) error {
+func torFilterAccept4(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("accept4")
 	if err != nil {
 		return err
 	}
-	if is386 {
-		// XXX: The tor common/sandbox.c file, explcitly allows socketcall()
-		// by arg for this call, and only this call, when libseccomp should
-		// do the right thing.
-		return f.AddRule(scall, seccomp.ActAllow)
-	}
 
 	cond, err := seccomp.MakeCondition(3, seccomp.CompareMaskedEqual, 0, syscall.SOCK_CLOEXEC|syscall.SOCK_NONBLOCK)
 	if err != nil {
@@ -285,27 +317,16 @@ func torFilterPoll(f *seccomp.ScmpFilter) error {
 	return f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isPollIn, timeoutIsTen})
 }
 
-func torFilterSocket(f *seccomp.ScmpFilter, is386 bool) error {
-	scall, err := seccomp.GetSyscallFromName("socket")
-	if err != nil {
-		return err
-	}
-	if is386 {
-		return f.AddRule(scall, seccomp.ActAllow)
-	}
-
+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 */)
 }
 
-func torFilterSetsockopt(f *seccomp.ScmpFilter, is386 bool) error {
+func torFilterSetsockopt(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("setsockopt")
 	if err != nil {
 		return err
 	}
-	if is386 {
-		return f.AddRule(scall, seccomp.ActAllow)
-	}
 
 	isSolSocket, err := seccomp.MakeCondition(1, seccomp.CompareEqual, syscall.SOL_SOCKET)
 	if err != nil {
@@ -331,14 +352,11 @@ func torFilterSetsockopt(f *seccomp.ScmpFilter, is386 bool) error {
 	return nil
 }
 
-func torFilterGetsockopt(f *seccomp.ScmpFilter, is386 bool) error {
+func torFilterGetsockopt(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("getsockopt")
 	if err != nil {
 		return err
 	}
-	if is386 {
-		return f.AddRule(scall, seccomp.ActAllow)
-	}
 
 	isSolSocket, err := seccomp.MakeCondition(1, seccomp.CompareEqual, syscall.SOL_SOCKET)
 	if err != nil {
@@ -351,14 +369,11 @@ func torFilterGetsockopt(f *seccomp.ScmpFilter, is386 bool) error {
 	return f.AddRuleConditional(scall, seccomp.ActAllow, []seccomp.ScmpCondition{isSolSocket, optIsError})
 }
 
-func torFilterSocketpair(f *seccomp.ScmpFilter, is386 bool) error {
+func torFilterSocketpair(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("socketpair")
 	if err != nil {
 		return err
 	}
-	if is386 {
-		return f.AddRule(scall, seccomp.ActAllow)
-	}
 
 	isPfLocal, err := seccomp.MakeCondition(0, seccomp.CompareEqual, syscall.AF_LOCAL)
 	if err != nil {
@@ -530,12 +545,7 @@ func torFilterFcntl(f *seccomp.ScmpFilter, is386 bool) error {
 	return nil
 }
 
-func obfsFilterSetsockopt(f *seccomp.ScmpFilter, is386 bool) error {
-	// 386 already blindly allows all setsockopt() calls.
-	if is386 {
-		return nil
-	}
-
+func obfsFilterSetsockopt(f *seccomp.ScmpFilter) error {
 	scall, err := seccomp.GetSyscallFromName("setsockopt")
 	if err != nil {
 		return err





More information about the tor-commits mailing list