commit dcc1b9fffe82f55801b90c4ada9c21551e642f62 Author: Yawning Angel yawning@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/Sand... 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 {