[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