diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index cc8bf3d..ee9ca30 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,6 @@ { "ImportPath": "github.com/subgraph/oz", - "GoVersion": "go1.4.2", + "GoVersion": "go1.3.3", "Packages": [ "./..." ], @@ -35,6 +35,10 @@ { "ImportPath": "github.com/op/go-logging", "Rev": "e8d5414f0947014548c2334044a0fac13187dfee" + }, + { + "ImportPath": "github.com/subgraph/go-seccomp", + "Rev": "2eb74b38c2f37e0f48efa3a0974fd2e4edbd0ef5" } ] } diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/LICENSE b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/LICENSE new file mode 100644 index 0000000..972bb2e --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_386.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_386.go new file mode 100644 index 0000000..ac1fc54 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_386.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +// #include +import "C" + +const ( + auditArch = C.AUDIT_ARCH_I386 + nbits = 32 +) diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_amd64.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_amd64.go new file mode 100644 index 0000000..90b5e6c --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_amd64.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +// #include +import "C" + +const ( + auditArch = C.AUDIT_ARCH_X86_64 + nbits = 64 +) diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_arm.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_arm.go new file mode 100644 index 0000000..d720ec4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/audit_arm.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +// #include +import "C" + +const ( + auditArch = C.AUDIT_ARCH_ARM + nbits = 32 +) diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/bpf.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/bpf.go new file mode 100644 index 0000000..ebd6f23 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/bpf.go @@ -0,0 +1,107 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +import ( + "fmt" +) + +// #include +import "C" + +// BPF machine opcodes. These are the only ones we use. +const ( + opLOAD = C.BPF_LD + C.BPF_W + C.BPF_ABS + opJEQ = C.BPF_JMP + C.BPF_JEQ + C.BPF_K + opJSET = C.BPF_JMP + C.BPF_JSET + C.BPF_K + opJUMP = C.BPF_JMP + C.BPF_JA + opRET = C.BPF_RET + C.BPF_K +) + +// SockFilter encodes one BPF machine instruction. +// This struct mirrors struct sock_filter from . +type SockFilter struct { + Code uint16 // Actual filter code. + JT uint8 // Jump true. + JF uint8 // Jump false. + K uint32 // Generic multiuse field. +} + +// SockFprog encodes a BPF machine program. +// This struct mirrors struct sock_fprog from . +type SockFprog struct { + Len uint16 // Number of BPF machine instructions. + Filter *SockFilter // Pointer to the first instruction. +} + +// C versions of the structs used for sanity checking. +type sock_filter C.struct_sock_filter +type sock_fprog C.struct_sock_fprog + +// bpfInsn constructs one BPF machine instruction. +func bpfInsn(code uint16, k uint32, jt, jf uint8) SockFilter { + return SockFilter{code, jt, jf, k} +} + +// bpfStmt constructs one BPF machine statement. +func bpfStmt(code uint16, k uint32) SockFilter { + return bpfInsn(code, k, 0, 0) +} + +// bpfLoad returns the instruction to load the word at the given offset. +func bpfLoad(offset uintptr) SockFilter { + return bpfStmt(opLOAD, uint32(offset)) +} + +// bpfJeq returns an instruction encoding "jump-if-equal". +// Register A is compared with val. +// Both jt and jf are relative offsets. Offset 0 means fallthrough. +func bpfJeq(val uint32, jt, jf uint8) SockFilter { + return bpfInsn(opJEQ, val, jt, jf) +} + +// bpfJset returns an instruction encoding "jump-if-set". +// Register A is bitwise anded with val and result compared with zero. +// Both jt and jf are relative offsets. Offset 0 means fallthrough. +func bpfJset(val uint32, jt, jf uint8) SockFilter { + return bpfInsn(opJSET, val, jt, jf) +} + +// bpfJump returns an instruction encoding an unconditional jump to a relative offset. +// Offset 0 means fallthrough (NOP). +func bpfJump(offset int) SockFilter { + return bpfStmt(opJUMP, uint32(offset)) +} + +// bpfRet returns the instruction to return the value val. +func bpfRet(val uint32) SockFilter { + return bpfStmt(opRET, val) +} + +// String returns a readable representation of a BPF machine instruction. +func (f SockFilter) String() string { + var code string + switch f.Code { + case opLOAD: + code = "Load" + case opJEQ: + code = "Jeq" + case opJSET: + code = "Jset" + case opJUMP: + code = "Jump" + case opRET: + code = "Return" + default: + code = fmt.Sprintf("%04x", f.Code) + } + return fmt.Sprintf("%8s %08x, %02x, %02x\n", code, f.K, f.JT, f.JF) +} + +// ptr returns a pointer to a copy of the argument, useful in cases +// where the & syntax isn't allowed. e.g. ptr(bpfInsn(...)). +func ptr(f SockFilter) *SockFilter { + return &f +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/sanity_test.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/sanity_test.go new file mode 100644 index 0000000..5f5741e --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/sanity_test.go @@ -0,0 +1,175 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +import ( + "testing" + "unsafe" +) + +func TestSockFilter(t *testing.T) { + var f SockFilter + var cf sock_filter + tests := []struct { + desc string + g, c uintptr + }{ + { + "Sizeof(SockFilter)", + unsafe.Sizeof(f), + unsafe.Sizeof(cf), + }, + { + "Sizeof(SockFilter.Code)", + unsafe.Sizeof(f.Code), + unsafe.Sizeof(cf.code), + }, + { + "Offsetof(SockFilter.Code)", + unsafe.Offsetof(f.Code), + unsafe.Offsetof(cf.code), + }, + { + "Sizeof(SockFilter.Jt)", + unsafe.Sizeof(f.JT), + unsafe.Sizeof(cf.jt), + }, + { + "Offsetof(SockFilter.Jt)", + unsafe.Offsetof(f.JT), + unsafe.Offsetof(cf.jt), + }, + { + "Sizeof(SockFilter.Jf)", + unsafe.Sizeof(f.JF), + unsafe.Sizeof(cf.jf), + }, + { + "Offsetof(SockFilter.Jf)", + unsafe.Offsetof(f.JF), + unsafe.Offsetof(cf.jf), + }, + { + "Sizeof(SockFilter.K)", + unsafe.Sizeof(f.K), + unsafe.Sizeof(cf.k), + }, + { + "Offsetof(SockFilter.K)", + unsafe.Offsetof(f.K), + unsafe.Offsetof(cf.k), + }, + } + for _, test := range tests { + if test.g != test.c { + t.Errorf("%s = %v; want %v", test.desc, test.g, test.c) + } + } +} + +func TestSockFprog(t *testing.T) { + var p SockFprog + var cp sock_fprog + tests := []struct { + desc string + g, c uintptr + }{ + { + "Sizeof(SockFprog)", + unsafe.Sizeof(p), + unsafe.Sizeof(cp), + }, + { + "Sizeof(SockFprog.Len)", + unsafe.Sizeof(p.Len), + unsafe.Sizeof(cp.len), + }, + { + "Offsetof(SockFprog.Len)", + unsafe.Offsetof(p.Len), + unsafe.Offsetof(cp.len), + }, + { + "Sizeof(SockFprog.Filter)", + unsafe.Sizeof(p.Filter), + unsafe.Sizeof(cp.filter), + }, + { + "Offsetof(SockFprog.Filter)", + unsafe.Offsetof(p.Filter), + unsafe.Offsetof(cp.filter), + }, + } + for _, test := range tests { + if test.g != test.c { + t.Errorf("%s = %v; want %v", test.desc, test.g, test.c) + } + } +} + +func TestSeccompData(t *testing.T) { + var d SeccompData + var cd seccomp_data + tests := []struct { + desc string + g, c uintptr + }{ + { + "Sizeof(SeccompData)", + unsafe.Sizeof(d), + unsafe.Sizeof(cd), + }, + { + "Sizeof(SeccompData.NR)", + unsafe.Sizeof(d.NR), + unsafe.Sizeof(cd.nr), + }, + { + "Offsetof(SeccompData.NR)", + unsafe.Offsetof(d.NR), + unsafe.Offsetof(cd.nr), + }, + { + "Sizeof(SeccompData.Arch)", + unsafe.Sizeof(d.Arch), + unsafe.Sizeof(cd.arch), + }, + { + "Offsetof(SeccompData.Arch)", + unsafe.Offsetof(d.Arch), + unsafe.Offsetof(cd.arch), + }, + { + "Sizeof(SeccompData.InstructionPointer)", + unsafe.Sizeof(d.InstructionPointer), + unsafe.Sizeof(cd.instruction_pointer), + }, + { + "Offsetof(SeccompData.InstructionPointer)", + unsafe.Offsetof(d.InstructionPointer), + unsafe.Offsetof(cd.instruction_pointer), + }, + { + "Sizeof(SeccompData.Args)", + unsafe.Sizeof(d.Args), + unsafe.Sizeof(cd.args), + }, + { + "Offsetof(SeccompData.Args)", + unsafe.Offsetof(d.Args), + unsafe.Offsetof(cd.args), + }, + { + "Sizeof(SeccompData.Args[0])", + unsafe.Sizeof(d.Args[0]), + unsafe.Sizeof(cd.args[0]), + }, + } + for _, test := range tests { + if test.g != test.c { + t.Errorf("%s = %v; want %v", test.desc, test.g, test.c) + } + } +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.go new file mode 100644 index 0000000..eda7f34 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.go @@ -0,0 +1,494 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package seccomp implements support for compiling and installing Seccomp-BPF policy files. +// - http://www.chromium.org/chromium-os/developer-guide/chromium-os-sandboxing +// +// Typical usage: +// // Check for the required kernel support for seccomp. +// if err := seccomp.CheckSupport(); err != nil { +// log.Fatal(err) +// } +// +// // Compile BPF program from a Chromium-OS policy file. +// bpf, err := seccomp.Compile(path) +// if err != nil { +// log.Fatal(err) +// } +// +// // Install Seccomp-BPF filter program with the kernel. +// if err := seccomp.Install(bpf); err != nil { +// log.Fatal(err) +// } +// +// For background and more information: +// - http://www.tcpdump.org/papers/bpf-usenix93.pdf +// - http://en.wikipedia.org/wiki/Seccomp +// - http://lwn.net/Articles/475043/ +// - http://outflux.net/teach-seccomp/ +// - http://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt +// - http://github.com/torvalds/linux/blob/master/kernel/seccomp.c +// +// TODO: +// - Exit the program if any thread is killed because of seccomp violation. +// - Provide a debug mode to log system calls used during normal operation. +package seccomp + +import ( + "bytes" + "fmt" + "io/ioutil" + "regexp" + "runtime" + "strconv" + "strings" + "syscall" + "unsafe" +) + +// #include +// #include "unistd_64.h" +// #include "seccomp.h" +import "C" + +// SeccompData is the format the BPF program executes over. +// This struct mirrors struct seccomp_data from . +type SeccompData struct { + NR int32 // The system call number. + Arch uint32 // System call convention as an AUDIT_ARCH_* value. + InstructionPointer uint64 // At the time of the system call. + Args [6]uint64 // System call arguments (always stored as 64-bit values). +} + +// C version of the struct used for sanity checking. +type seccomp_data C.struct_seccomp_data + +// bpfLoadNR returns the instruction to load the NR field in SeccompData. +func bpfLoadNR() SockFilter { + return bpfLoad(unsafe.Offsetof(SeccompData{}.NR)) +} + +// bpfLoadArch returns the instruction to load the Arch field in SeccompData. +func bpfLoadArch() SockFilter { + return bpfLoad(unsafe.Offsetof(SeccompData{}.Arch)) +} + +// bpfLoadArg returns the instruction to load one word of an argument in SeccompData. +func bpfLoadArg(arg, word int) SockFilter { + return bpfLoad(unsafe.Offsetof(SeccompData{}.Args) + uintptr(((2*arg)+word)*4)) +} + +// retKill returns the code for seccomp kill action. +func retKill() uint32 { + return C.SECCOMP_RET_KILL +} + +// retTrap returns the code for seccomp trap action. +func retTrap() uint32 { + return C.SECCOMP_RET_TRAP +} + +// retErrno returns the code for seccomp errno action with the specified errno embedded. +func retErrno(errno syscall.Errno) uint32 { + return C.SECCOMP_RET_ERRNO | (uint32(errno) & C.SECCOMP_RET_DATA) +} + +// retAllow returns the code for seccomp allow action. +func retAllow() uint32 { + return C.SECCOMP_RET_ALLOW +} + +// policy represents the seccomp policy for a single syscall. +type policy struct { + // name of the syscall. + name string + + // expr is evaluated on the syscall arguments. + // nil expr evaluates to false. + expr orExpr + + // then is executed if the expr evaluates to true. + // (cannot be specified in policy file, used in tests only). + then SockFilter + + // default action (else) if the expr evaluates to false. + // nil means jump to end of program for the overall default. + def *SockFilter +} + +// orExpr is a list of and expressions. +type orExpr []andExpr + +// andExpr is a list of arg comparisons. +type andExpr []argComp + +// argComp represents a basic argument comparison in the policy. +type argComp struct { + idx int // 0..5 for indexing into SeccompData.Args. + oper string // comparison operator: "==", "!=", or "&". + val uint64 // upper 32 bits compared only if nbits>32. +} + +// String converts the internal policy representation back to policy file syntax. +func (p policy) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "%s: ", p.name) + + for i, and := range p.expr { + if i > 0 { + fmt.Fprintf(&buf, " || ") + } + for j, arg := range and { + if j > 0 { + fmt.Fprintf(&buf, " && ") + } + fmt.Fprintf(&buf, "arg%d %s %#x", arg.idx, arg.oper, arg.val) + } + } + + pret := func(f SockFilter) { + if f.Code == opRET { + switch f.K & C.SECCOMP_RET_ACTION { + case C.SECCOMP_RET_ALLOW: + fmt.Fprintf(&buf, "1") + return + case C.SECCOMP_RET_ERRNO: + fmt.Fprintf(&buf, "return %d", f.K&C.SECCOMP_RET_DATA) + return + } + } + fmt.Fprintf(&buf, "%s", f) + } + if p.then != bpfRet(retAllow()) { + fmt.Fprintf(&buf, " ? ") + pret(p.then) + } + if p.def != nil { + if p.expr != nil { + fmt.Fprintf(&buf, "; ") + } + pret(*p.def) + } + + return buf.String() +} + +// Syntax of policy line for a single syscall. +var ( + allowRE = regexp.MustCompile(`^([[:word:]]+) *: *1$`) + returnRE = regexp.MustCompile(`^([[:word:]]+) *: *return *([[:word:]]+)$`) + exprRE = regexp.MustCompile(`^([[:word:]]+) *:([^;]+)$`) + exprReturnRE = regexp.MustCompile(`^([[:word:]]+) *:([^;]+); *return *([[:word:]]+)$`) + + argRE = regexp.MustCompile(`^arg([0-5]) *(==|!=|&) *([[:word:]]+)$`) +) + +// parseLine parses the policy line for a single syscall. +func parseLine(line string) (policy, error) { + var name, expr, ret string + var then SockFilter + var def *SockFilter + + line = strings.TrimSpace(line) + if match := allowRE.FindStringSubmatch(line); match != nil { + name = match[1] + def = ptr(bpfRet(retAllow())) + } else if match = returnRE.FindStringSubmatch(line); match != nil { + name = match[1] + ret = match[2] + } else if match = exprRE.FindStringSubmatch(line); match != nil { + name = match[1] + expr = match[2] + } else if match = exprReturnRE.FindStringSubmatch(line); match != nil { + name = match[1] + expr = match[2] + ret = match[3] + } else { + return policy{}, fmt.Errorf("invalid syntax") + } + + if _, ok := syscallNum[name]; !ok { + return policy{}, fmt.Errorf("unknown syscall: %s", name) + } + + var or orExpr + if expr != "" { + for _, sub := range strings.Split(expr, "||") { + var and andExpr + for _, arg := range strings.Split(sub, "&&") { + arg = strings.TrimSpace(arg) + match := argRE.FindStringSubmatch(arg) + if match == nil { + return policy{}, fmt.Errorf("invalid expression: %s", arg) + } + idx, err := strconv.Atoi(match[1]) + if err != nil { + return policy{}, fmt.Errorf("invalid arg: %s", arg) + } + oper := match[2] + val, err := strconv.ParseUint(match[3], 0, 64) + if err != nil { + return policy{}, fmt.Errorf("invalid value: %s", arg) + } + and = append(and, argComp{idx, oper, val}) + } + or = append(or, and) + } + } + + then = bpfRet(retAllow()) + + if ret != "" { + errno, err := strconv.ParseUint(ret, 0, 16) + if err != nil { + return policy{}, fmt.Errorf("invalid errno: %s", ret) + } + def = ptr(bpfRet(retErrno(syscall.Errno(errno)))) + } + + return policy{name, or, then, def}, nil +} + +// parseLines parses multiple policy lines, each one for a single syscall. +// Empty lines and lines beginning with "#" are ignored. +// Multiple policies for a syscall are detected and reported as error. +func parseLines(lines []string) ([]policy, error) { + var ps []policy + seen := make(map[string]int) + for i, line := range lines { + lineno := i + 1 + if line == "" || strings.HasPrefix(line, "#") { + continue + } + p, err := parseLine(line) + if err != nil { + return nil, fmt.Errorf("line %d: %v", lineno, err) + } + if seen[p.name] > 0 { + return nil, fmt.Errorf("lines %d,%d: multiple policies for %s", + seen[p.name], lineno, p.name) + } + seen[p.name] = lineno + ps = append(ps, p) + } + return ps, nil +} + +// parseFile reads a Chromium-OS Seccomp-BPF policy file and parses its contents. +func parseFile(path string) ([]policy, error) { + file, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return parseLines(strings.Split(string(file), "\n")) +} + +// compile compiles a Seccomp-BPF program implementing the syscall policies. +// long specifies whether to generate 32-bit or 64-bit argument comparisons. +// def is the overall default action to take when the syscall does not match +// any policy in the filter. +func compile(ps []policy, long bool, def SockFilter) ([]SockFilter, error) { + var bpf []SockFilter + do := func(insn SockFilter) { + bpf = append(bpf, insn) + } + + // ref maps a label to addresses of all the instructions that jump to it. + ref := make(map[string][]int) + jump := func(name string) { + // jump to a label with unresolved address: insert a placeholder instruction. + ref[name] = append(ref[name], len(bpf)) + do(SockFilter{}) + } + label := func(name string) { + // label address resolved: replace placeholder instructions with actual jumps. + for _, i := range ref[name] { + bpf[i] = bpfJump(len(bpf) - (i + 1)) + } + delete(ref, name) + } + + // Conditional jumps: jump if condition is true, fall through otherwise. + jeq := func(val uint32, target string) { + // if A == val { goto target } + do(bpfJeq(val, 0, 1)) + jump(target) + } + jne := func(val uint32, target string) { + // if A != val { goto target } + do(bpfJeq(val, 1, 0)) + jump(target) + } + jset := func(val uint32, target string) { + // if A&val != 0 { goto target } + do(bpfJset(val, 0, 1)) + jump(target) + } + jnset := func(val uint32, target string) { + // if A&val == 0 { goto target } + do(bpfJset(val, 1, 0)) + jump(target) + } + + do(bpfLoadArch()) + do(bpfJeq(auditArch, 1, 0)) + do(bpfRet(retKill())) + + do(bpfLoadNR()) + for _, p := range ps { + nr, ok := syscallNum[p.name] + if !ok { + return nil, fmt.Errorf("unknown syscall: %s", p.name) + } + jne(uint32(nr), "nextcall") + for _, and := range p.expr { + for _, arg := range and { + val := struct{ high, low uint32 }{uint32(arg.val >> 32), uint32(arg.val)} + switch arg.oper { + case "==": + if long { + do(bpfLoadArg(arg.idx, 1)) + jne(val.high, "nextor") + } + do(bpfLoadArg(arg.idx, 0)) + jne(val.low, "nextor") + case "!=": + if long { + do(bpfLoadArg(arg.idx, 1)) + jne(val.high, "nextand") + } + do(bpfLoadArg(arg.idx, 0)) + jeq(val.low, "nextor") + case "&": + if long { + do(bpfLoadArg(arg.idx, 1)) + jset(val.high, "nextand") + } + do(bpfLoadArg(arg.idx, 0)) + jnset(val.low, "nextor") + default: + return nil, fmt.Errorf("unknown operator: %q", arg.oper) + } + + // Comparison was satisfied. Move on to the next comparison in &&. + label("nextand") + } + + // All comparisons in && were satisfied. + do(p.then) + + // Some comparison in && was false. Move on to the next expression in ||. + label("nextor") + } + + // All expressions in || evaluated to false (or expr was nil). + if p.def != nil { + do(*p.def) + } else { + jump("default") + } + + label("nextcall") + } + + label("default") + do(def) + + if len(ref) > 0 { + return nil, fmt.Errorf("unresolved labels: %v\n%v", ref, bpf) + } + return bpf, nil +} + +// Compile reads a Chromium-OS policy file and compiles a +// Seccomp-BPF filter program implementing the policies. +func Compile(path string) ([]SockFilter, error) { + ps, err := parseFile(path) + if err != nil { + return nil, err + } + return compile(ps, nbits > 32, bpfRet(retKill())) +} + +// prctl is a wrapper for the 'prctl' system call. +// See 'man prctl' for details. +func prctl(option uintptr, args ...uintptr) error { + if len(args) > 4 { + return syscall.E2BIG + } + var arg [4]uintptr + copy(arg[:], args) + _, _, e := syscall.Syscall6(C.__NR_prctl, option, arg[0], arg[1], arg[2], arg[3], 0) + if e != 0 { + return e + } + return nil +} + +// seccomp is a wrapper for the 'seccomp' system call. +// See for valid op and flag values. +// uargs is typically a pointer to struct sock_fprog. +func seccomp(op, flags uintptr, uargs unsafe.Pointer) error { + _, _, e := syscall.Syscall(C.__NR_seccomp, op, flags, uintptr(uargs)) + if e != 0 { + return e + } + return nil +} + +// CheckSupport checks for the required seccomp support in the kernel. +func CheckSupport() error { + // This is based on http://outflux.net/teach-seccomp/autodetect.html. + if err := prctl(C.PR_GET_SECCOMP); err != nil { + return fmt.Errorf("seccomp not available: %v", err) + } + if err := prctl(C.PR_SET_SECCOMP, C.SECCOMP_MODE_FILTER, 0); err != syscall.EFAULT { + return fmt.Errorf("seccomp filter not available: %v", err) + } + if err := seccomp(C.SECCOMP_SET_MODE_FILTER, 0, nil); err != syscall.EFAULT { + return fmt.Errorf("seccomp syscall not available: %v", err) + } + if err := seccomp(C.SECCOMP_SET_MODE_FILTER, C.SECCOMP_FILTER_FLAG_TSYNC, nil); err != syscall.EFAULT { + return fmt.Errorf("seccomp tsync not available: %v", err) + } + return nil +} + +// Load makes the seccomp system call to install the bpf filter for +// all threads (with tsync). prctl(set_no_new_privs, 1) must have +// been called (from the same thread) before calling Load for the +// first time. +// Most users of this library should use Install instead of calling +// Load directly. There are a couple of situations where it may be +// necessary to use Load instead of Install: +// - If a previous call to Install has disabled the 'prctl' system +// call, Install cannot be called again. In that case, it is safe +// to add additional filters directly with Load. +// - If the process is running as a priviledged user, and you want +// to load the seccomp filter without setting no_new_privs. +func Load(bpf []SockFilter) error { + if size, limit := len(bpf), 0xffff; size > limit { + return fmt.Errorf("filter program too big: %d bpf instructions (limit = %d)", size, limit) + } + prog := &SockFprog{ + Filter: &bpf[0], + Len: uint16(len(bpf)), + } + return seccomp(C.SECCOMP_SET_MODE_FILTER, C.SECCOMP_FILTER_FLAG_TSYNC, unsafe.Pointer(prog)) +} + +// Install makes the necessary system calls to install the Seccomp-BPF +// filter for the current process (all threads). Install can be called +// multiple times to install additional filters. +func Install(bpf []SockFilter) error { + // prctl(set_no_new_privs, 1) must be called (from the same thread) + // before a seccomp filter can be installed by an unprivileged user: + // - http://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if err := prctl(C.PR_SET_NO_NEW_PRIVS, 1); err != nil { + return err + } + return Load(bpf) +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.h b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.h new file mode 100644 index 0000000..df94ea0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp.h @@ -0,0 +1,54 @@ +#ifndef _UAPI_LINUX_SECCOMP_H +#define _UAPI_LINUX_SECCOMP_H + +// #include +#include + + +/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) */ +#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ +#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ +#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ + +/* Valid operations for seccomp syscall. */ +#define SECCOMP_SET_MODE_STRICT 0 +#define SECCOMP_SET_MODE_FILTER 1 + +/* Valid flags for SECCOMP_SET_MODE_FILTER */ +#define SECCOMP_FILTER_FLAG_TSYNC 1 + +/* + * All BPF programs must return a 32-bit value. + * The bottom 16-bits are for optional return data. + * The upper 16-bits are ordered from least permissive values to most. + * + * The ordering ensures that a min_t() over composed return values always + * selects the least permissive choice. + */ +#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ +#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ +#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ +#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ +#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ + +/* Masks for the return value sections. */ +#define SECCOMP_RET_ACTION 0x7fff0000U +#define SECCOMP_RET_DATA 0x0000ffffU + +/** + * struct seccomp_data - the format the BPF program executes over. + * @nr: the system call number + * @arch: indicates system call convention as an AUDIT_ARCH_* value + * as defined in . + * @instruction_pointer: at the time of the system call. + * @args: up to 6 system call arguments always stored as 64-bit values + * regardless of the architecture. + */ +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; + +#endif /* _UAPI_LINUX_SECCOMP_H */ diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp_test.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp_test.go new file mode 100644 index 0000000..a5b90ab --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/seccomp_test.go @@ -0,0 +1,529 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package seccomp + +import ( + "flag" + "os" + "runtime" + "syscall" + "testing" + "unsafe" +) + +var ( + parseFilePath = flag.String("parse_file", "", "path for TestParseFile") + testInstall = flag.Bool("test_install", false, "enable TestInstall (use with -cpu=N)") + testEndian = flag.Bool("test_endian", false, "enable TestEndian") +) + +func TestParseLine(t *testing.T) { + tests := []struct { + policy string + want string + err string + }{ + {policy: "read: 1"}, + {policy: "open: return 1"}, + {policy: "prctl: arg0 == 0xf"}, + {policy: "prctl: arg0 != 0xf"}, + {policy: "ioctl: arg1 & 0x5401"}, + {policy: "ioctl: arg1 == 0x4024700a || arg1 == 0x541b"}, + {policy: "ioctl: arg1 == 0x4024700a && arg1 == 0x541b"}, + {policy: "ioctl: arg1 == 0x5401 || arg1 == 0x700a || arg2 & 0x541b"}, + {policy: "ioctl: arg1 == 0x5401 && arg1 == 0x700a && arg3 & 0x541b"}, + {policy: "ioctl: arg1 == 0x5401 || arg1 == 0x700a && arg4 & 0x541b"}, + {policy: "ioctl: arg1 == 0x5401 && arg1 == 0x700a || arg5 & 0x541b"}, + {policy: "ioctl: arg1 == 0x5401 && arg1 == 0x700a || arg5 & 0x541b; return 1"}, + { + // different spacing around colon. + policy: "read :1", + want: "read: 1", + }, + { + // leading and trailing whitespace. + policy: " open : return 1 ", + want: "open: return 1", + }, + { + // return hexadecimal errno. + policy: "open: return 0x10", + want: "open: return 16", + }, + { + // return octal errno. + policy: "open: return 010", + want: "open: return 8", + }, + { + // return highest errno. + policy: "open: return 0xffff", + want: "open: return 65535", + }, + { + // expression with no spaces. + policy: "ioctl:arg1==0x5401&&arg1==0x700a||arg2&0x541b", + want: "ioctl: arg1 == 0x5401 && arg1 == 0x700a || arg2 & 0x541b", + }, + { + // compare with decimal value. + policy: "ioctl: arg1 == 5401 && arg1 == 0x700a || arg2 & 0x541b", + want: "ioctl: arg1 == 0x1519 && arg1 == 0x700a || arg2 & 0x541b", + }, + { + // compare with octal value. + policy: "ioctl: arg1 == 05401 && arg1 == 0x700a || arg2 & 0x541b", + want: "ioctl: arg1 == 0xb01 && arg1 == 0x700a || arg2 & 0x541b", + }, + { + // all decimal comparisons. + policy: "clone: arg0 == 1 || arg0 == 2 || arg0 == 16", + want: "clone: arg0 == 0x1 || arg0 == 0x2 || arg0 == 0x10", + }, + { + // missing syscall name. + policy: ": 1", + err: "invalid syntax", + }, + { + // malformed syscall name. + policy: "two words: 1", + err: "invalid syntax", + }, + { + // missing colon. + policy: "read = 1", + err: "invalid syntax", + }, + { + // trailing semicolon after return. + policy: "open: return 1;", + err: "invalid syntax", + }, + { + // trailing semicolon after expression. + policy: "prctl: arg0 == 0xf;", + err: "invalid syntax", + }, + { + // missing return after semicolon. + policy: "prctl: arg0 == 0xf; 1", + err: "invalid syntax", + }, + { + // bad syscall name. + policy: "bad: 1", + err: "unknown syscall: bad", + }, + { + // symbolic errno is not supported. + policy: "open: return EPERM", + err: "invalid errno: EPERM", + }, + { + // errno must fit in 16 bits. + policy: "open: return 0x10000", + err: "invalid errno: 0x10000", + }, + { + // missing argument index. + policy: "prctl: arg == 0xf", + err: "invalid expression: arg == 0xf", + }, + { + // arg index out of range. + policy: "prctl: arg6 == 0xf", + err: "invalid expression: arg6 == 0xf", + }, + { + // bitwise and with argument not supported. + policy: "prctl: arg0 & 0xf == 0xf", + err: "invalid expression: arg0 & 0xf == 0xf", + }, + { + // unknown operator. + policy: "prctl: arg0 !== 0xf", + err: "invalid expression: arg0 !== 0xf", + }, + { + // invalid hexadecimal value. + policy: "prctl: arg0 == 0xfdx", + err: "invalid value: arg0 == 0xfdx", + }, + { + // invalid decimal value. + policy: "prctl: arg0 == 123a", + err: "invalid value: arg0 == 123a", + }, + { + // invalid octal value. + policy: "prctl: arg0 == 0129", + err: "invalid value: arg0 == 0129", + }, + { + // invalid subexpression. + policy: "prctl: arg0 == 0x100 && arg1 = 0x101 || arg2 == 0x102", + err: "invalid expression: arg1 = 0x101", + }, + } + for _, test := range tests { + var err string + p, e := parseLine(test.policy) + if e != nil { + err = e.Error() + } + if err != "" || test.err != "" { + if err != test.err { + t.Errorf("parseLine(%q): error = %q; want %q", test.policy, err, test.err) + } + continue + } + want := test.want + if want == "" { + want = test.policy + } + if got := p.String(); got != want { + t.Errorf("parseLine(%q) = %q; want %q", test.policy, got, test.want) + } + } +} + +func TestParseLines(t *testing.T) { + tests := []struct { + file []string + err string + }{ + { + // simple policy file. + file: []string{ + "read: 1", + "write: 1", + "open: return 1", + }, + }, + { + // comment lines are ignored. + file: []string{ + "read: 1", + "write: 1", + "# open: return EPERM", + "open: return 1", + }, + }, + { + // blank lines are ignored. + file: []string{ + "read: 1", + "write: 1", + "", + "open: return 1", + }, + }, + { + // leading space on comment line. + file: []string{ + "read: 1", + "write: 1", + " # open: return EPERM", + "open: return 1", + }, + err: "line 3: invalid syntax", + }, + { + // line consisting of whitespace only. + file: []string{ + "read: 1", + "write: 1", + " ", + "open: return 1", + }, + err: "line 3: invalid syntax", + }, + { + // parse error on one line. + file: []string{ + "read: 1", + "write: return 019", + "open: return 1", + }, + err: "line 2: invalid errno: 019", + }, + { + // multiple policies for a syscall. + file: []string{ + "read: 1", + "write: 1", + "read: return 1", + "open: return 1", + }, + err: "lines 1,3: multiple policies for read", + }, + } + for _, test := range tests { + var err string + _, e := parseLines(test.file) + if e != nil { + err = e.Error() + } + if err != "" || test.err != "" { + if err != test.err { + t.Errorf("parseLines(%q): error = %q; want %q", test.file, err, test.err) + } + } + } +} + +func TestParseFile(t *testing.T) { + if *parseFilePath == "" { + t.Skip("use -parse_file to enable.") + } + + if _, err := parseFile(*parseFilePath); err != nil { + t.Errorf("parseFile(%q): %v", *parseFilePath, err) + } +} + +func TestCompile(t *testing.T) { + syscallName := make(map[int32]string) + for name, nr := range syscallNum { + syscallName[int32(nr)] = name + } + + call := func(name string, args ...uint64) SeccompData { + nr, ok := syscallNum[name] + if !ok { + t.Fatalf("unknown syscall: %s", name) + } + data := SeccompData{ + NR: int32(nr), + Arch: auditArch, + } + copy(data.Args[:], args) + return data + } + + eval := func(bpf []SockFilter, data SeccompData) uint32 { + var A uint32 + IP := 0 + for { + Insn := bpf[IP] + IP++ + switch Insn.Code { + case opLOAD: + A = *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&data)) + uintptr(Insn.K))) + case opJEQ: + if A == Insn.K { + IP += int(Insn.JT) + } else { + IP += int(Insn.JF) + } + case opJSET: + if A&Insn.K != 0 { + IP += int(Insn.JT) + } else { + IP += int(Insn.JF) + } + case opJUMP: + IP += int(Insn.K) + case opRET: + return Insn.K + default: + t.Fatalf("unsupported instruction: %v", Insn) + } + } + } + + file := []string{ + "read: 1", + "open: return 1", + "write: arg0 == 1", + "close: arg0 == 2; return 9", + "dup: arg0 == 1 || arg0 == 2", + "pipe: arg0 == 1 && arg1 == 2", + "link: arg0 != 1 && arg1 != 2 || arg2 == 3", + "unlink: arg0 != 1 || arg1 != 2 && arg2 == 3", + "creat: arg0 & 0xf00 && arg1 & 0x0f0 && arg2 & 0x00f", + "lseek: arg0 & 0x0f000f000f000f00 && arg1 & 0x00f000f000f000f0 && arg2 & 0x000f000f000f000f", + "stat: arg0 != 0x0123456789abcdef && arg1 != 0x123456789abcdef0 || arg2 == 0x00f000f000000000", + "fstat: arg0 != 0x0123456789abcdef || arg1 != 0x123456789abcdef0 && arg2 == 0x00f000f000000000", + } + tests := []struct { + data SeccompData + want uint32 + }{ + {call("fork"), retKill()}, + {call("read"), retAllow()}, + {call("open"), retErrno(1)}, + {call("write", 0), retKill()}, + {call("write", 1), retAllow()}, + {call("close", 1), retErrno(9)}, + {call("close", 2), retAllow()}, + {call("dup", 0), retKill()}, + {call("dup", 1), retAllow()}, + {call("dup", 2), retAllow()}, + {call("dup", 3), retKill()}, + {call("pipe", 1, 1), retKill()}, + {call("pipe", 1, 2), retAllow()}, + {call("pipe", 2, 1), retKill()}, + {call("pipe", 2, 2), retKill()}, + {call("link", 1, 2, 3), retAllow()}, + {call("link", 1, 2, 2), retKill()}, + {call("link", 2, 2, 2), retKill()}, + {call("link", 2, 1, 2), retAllow()}, + {call("unlink", 2, 1, 2), retAllow()}, + {call("unlink", 1, 1, 2), retKill()}, + {call("unlink", 1, 1, 3), retAllow()}, + {call("unlink", 1, 2, 3), retKill()}, + {call("creat", 0x100, 0x100, 0x101), retKill()}, + {call("creat", 0x200, 0x110, 0x101), retAllow()}, + {call("creat", 0x400, 0x110, 0x110), retKill()}, + {call("creat", 0x800, 0x110, 0x007), retAllow()}, + {call("lseek", 0x0100, 0x0100, 0x0101), retKill()}, + {call("lseek", 0x0200, 0x0110, 0x0101), retAllow()}, + {call("lseek", 0x0400, 0x0110, 0x0110), retKill()}, + {call("lseek", 0x0800, 0x0110, 0x0007), retAllow()}, + {call("lseek", 0x0100000000000000, 0x0100000000000000, 0x0101000000000000), retKill()}, + {call("lseek", 0x0200000000000000, 0x0110000000000000, 0x0101000000000000), retAllow()}, + {call("lseek", 0x0400000000000000, 0x0110000000000000, 0x0110000000000000), retKill()}, + {call("lseek", 0x0800000000000000, 0x0110000000000000, 0x0007000000000000), retAllow()}, + {call("stat", 0x0123456789abcdef, 0x123456789abcdef0, 0x00f000f000000000), retAllow()}, + {call("stat", 0x0123456789abcdef, 0x123456789abcdef0, 0x007000f000000000), retKill()}, + {call("stat", 0x0133456789abcdef, 0x123457789abcdef0, 0x007000f000000000), retAllow()}, + {call("stat", 0x0133456789abcdef, 0x123456789abcdef0, 0x007000f000000000), retKill()}, + {call("fstat", 0x0123456789abcdef, 0x123456789abcdef0, 0x00f000f000000000), retKill()}, + {call("fstat", 0x0133456789abcdef, 0x123456789abcdef0, 0x00f000f000000000), retAllow()}, + {call("fstat", 0x0123456789abcdef, 0x123457789abcdef0, 0x00f000f000000000), retAllow()}, + {call("fstat", 0x0123456789abcdef, 0x123457789abcdef0, 0x007000f000000000), retKill()}, + } + + ps, err := parseLines(file) + if err != nil { + t.Fatalf("parse failed: %v", err) + } + bpf, err := compile(ps, true, bpfRet(retKill())) + if err != nil { + t.Fatalf("compile failed: %v", err) + } + t.Logf("len(bpf) = %d", len(bpf)) + for _, test := range tests { + if got := eval(bpf, test.data); got != test.want { + t.Errorf("%s%#x = %#08x; want %#08x", syscallName[test.data.NR], test.data.Args, got, test.want) + } + } +} + +func TestSupport(t *testing.T) { + if err := CheckSupport(); err != nil { + t.Error(err) + } +} + +func TestInstall(t *testing.T) { + if !*testInstall { + t.Skip("use -test_install (with -cpu=N) to enable.") + } + + file := []string{ + "# open: return EPERM", + "open: return 1", + "# default: ALLOW", + } + + ps, err := parseLines(file) + if err != nil { + t.Fatalf("parse failed: %v", err) + } + bpf, err := compile(ps, nbits > 32, bpfRet(retAllow())) + if err != nil { + t.Fatalf("compile failed: %v", err) + } + if err = Install(bpf); err != nil { + t.Fatalf("install failed: %v", err) + } + + N := runtime.GOMAXPROCS(0) + opened := make(chan bool) + for i := 0; i < N; i++ { + go func() { + if f, err := os.Open("/dev/null"); err != nil { + t.Logf("open() failed: %v", err) + opened <- false + } else { + t.Logf("open() succeeded") + f.Close() + opened <- true + } + }() + } + for i := 0; i < N; i++ { + if <-opened { + t.Fail() + } + } +} + +func TestEndian(t *testing.T) { + if !*testEndian { + t.Skip("use -test_endian to enable.") + } + + pass := syscall.EDOM + fail := syscall.ERANGE + name := map[error]string{ + pass: "pass", + fail: "fail", + nil: "", + } + + type seccomp [3]uintptr + ps := []policy{ + { + name: "seccomp", + expr: orExpr{ + andExpr{ + argComp{0, "==", 0x0123456789abcdef}, + }, + andExpr{ + argComp{1, "!=", 0x01234567}, + argComp{2, "&", 0x01010101}, + }, + }, + then: bpfRet(retErrno(pass)), + def: ptr(bpfRet(retErrno(fail))), + }, + } + tests := []struct { + args seccomp + want error + }{ + {seccomp{0x01234567, 0, 0}, fail}, + {seccomp{0x89abcdef, 0, 0}, pass}, + {seccomp{0, 0x01234567, 0}, fail}, + {seccomp{0, 0x12345678, 0}, fail}, + {seccomp{0, 0x01234567, 1}, fail}, + {seccomp{0, 0x12345678, 1}, pass}, + } + call := func(args seccomp) error { + if nr, ok := syscallNum["seccomp"]; ok { + if _, _, e := syscall.Syscall(uintptr(nr), args[0], args[1], args[2]); e != 0 { + return e + } + } + return nil + } + + bpf, err := compile(ps, false, bpfRet(retAllow())) + if err != nil { + t.Fatalf("compile failed: %v", err) + } + if err = Install(bpf); err != nil { + t.Fatalf("install failed: %v", err) + } + for _, test := range tests { + if got := call(test.args); got != test.want { + t.Errorf("seccomp%#x = %v; want %v", test.args, name[got], name[test.want]) + } + } +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_386.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_386.go new file mode 100644 index 0000000..152634d --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_386.go @@ -0,0 +1,365 @@ +// DO NOT EDIT. Autogenerated by syscalls_gen.go + +package seccomp + +// #include "unistd.h" +import "C" + +// syscallNum maps system call names to numbers. +var syscallNum = map[string]int{ + "restart_syscall": C.__NR_restart_syscall, + "exit": C.__NR_exit, + "fork": C.__NR_fork, + "read": C.__NR_read, + "write": C.__NR_write, + "open": C.__NR_open, + "close": C.__NR_close, + "waitpid": C.__NR_waitpid, + "creat": C.__NR_creat, + "link": C.__NR_link, + "unlink": C.__NR_unlink, + "execve": C.__NR_execve, + "chdir": C.__NR_chdir, + "time": C.__NR_time, + "mknod": C.__NR_mknod, + "chmod": C.__NR_chmod, + "lchown": C.__NR_lchown, + "break": C.__NR_break, + "oldstat": C.__NR_oldstat, + "lseek": C.__NR_lseek, + "getpid": C.__NR_getpid, + "mount": C.__NR_mount, + "umount": C.__NR_umount, + "setuid": C.__NR_setuid, + "getuid": C.__NR_getuid, + "stime": C.__NR_stime, + "ptrace": C.__NR_ptrace, + "alarm": C.__NR_alarm, + "oldfstat": C.__NR_oldfstat, + "pause": C.__NR_pause, + "utime": C.__NR_utime, + "stty": C.__NR_stty, + "gtty": C.__NR_gtty, + "access": C.__NR_access, + "nice": C.__NR_nice, + "ftime": C.__NR_ftime, + "sync": C.__NR_sync, + "kill": C.__NR_kill, + "rename": C.__NR_rename, + "mkdir": C.__NR_mkdir, + "rmdir": C.__NR_rmdir, + "dup": C.__NR_dup, + "pipe": C.__NR_pipe, + "times": C.__NR_times, + "prof": C.__NR_prof, + "brk": C.__NR_brk, + "setgid": C.__NR_setgid, + "getgid": C.__NR_getgid, + "signal": C.__NR_signal, + "geteuid": C.__NR_geteuid, + "getegid": C.__NR_getegid, + "acct": C.__NR_acct, + "umount2": C.__NR_umount2, + "lock": C.__NR_lock, + "ioctl": C.__NR_ioctl, + "fcntl": C.__NR_fcntl, + "mpx": C.__NR_mpx, + "setpgid": C.__NR_setpgid, + "ulimit": C.__NR_ulimit, + "oldolduname": C.__NR_oldolduname, + "umask": C.__NR_umask, + "chroot": C.__NR_chroot, + "ustat": C.__NR_ustat, + "dup2": C.__NR_dup2, + "getppid": C.__NR_getppid, + "getpgrp": C.__NR_getpgrp, + "setsid": C.__NR_setsid, + "sigaction": C.__NR_sigaction, + "sgetmask": C.__NR_sgetmask, + "ssetmask": C.__NR_ssetmask, + "setreuid": C.__NR_setreuid, + "setregid": C.__NR_setregid, + "sigsuspend": C.__NR_sigsuspend, + "sigpending": C.__NR_sigpending, + "sethostname": C.__NR_sethostname, + "setrlimit": C.__NR_setrlimit, + "getrlimit": C.__NR_getrlimit, + "getrusage": C.__NR_getrusage, + "gettimeofday": C.__NR_gettimeofday, + "settimeofday": C.__NR_settimeofday, + "getgroups": C.__NR_getgroups, + "setgroups": C.__NR_setgroups, + "select": C.__NR_select, + "symlink": C.__NR_symlink, + "oldlstat": C.__NR_oldlstat, + "readlink": C.__NR_readlink, + "uselib": C.__NR_uselib, + "swapon": C.__NR_swapon, + "reboot": C.__NR_reboot, + "readdir": C.__NR_readdir, + "mmap": C.__NR_mmap, + "munmap": C.__NR_munmap, + "truncate": C.__NR_truncate, + "ftruncate": C.__NR_ftruncate, + "fchmod": C.__NR_fchmod, + "fchown": C.__NR_fchown, + "getpriority": C.__NR_getpriority, + "setpriority": C.__NR_setpriority, + "profil": C.__NR_profil, + "statfs": C.__NR_statfs, + "fstatfs": C.__NR_fstatfs, + "ioperm": C.__NR_ioperm, + "socketcall": C.__NR_socketcall, + "syslog": C.__NR_syslog, + "setitimer": C.__NR_setitimer, + "getitimer": C.__NR_getitimer, + "stat": C.__NR_stat, + "lstat": C.__NR_lstat, + "fstat": C.__NR_fstat, + "olduname": C.__NR_olduname, + "iopl": C.__NR_iopl, + "vhangup": C.__NR_vhangup, + "idle": C.__NR_idle, + "vm86old": C.__NR_vm86old, + "wait4": C.__NR_wait4, + "swapoff": C.__NR_swapoff, + "sysinfo": C.__NR_sysinfo, + "ipc": C.__NR_ipc, + "fsync": C.__NR_fsync, + "sigreturn": C.__NR_sigreturn, + "clone": C.__NR_clone, + "setdomainname": C.__NR_setdomainname, + "uname": C.__NR_uname, + "modify_ldt": C.__NR_modify_ldt, + "adjtimex": C.__NR_adjtimex, + "mprotect": C.__NR_mprotect, + "sigprocmask": C.__NR_sigprocmask, + "create_module": C.__NR_create_module, + "init_module": C.__NR_init_module, + "delete_module": C.__NR_delete_module, + "get_kernel_syms": C.__NR_get_kernel_syms, + "quotactl": C.__NR_quotactl, + "getpgid": C.__NR_getpgid, + "fchdir": C.__NR_fchdir, + "bdflush": C.__NR_bdflush, + "sysfs": C.__NR_sysfs, + "personality": C.__NR_personality, + "afs_syscall": C.__NR_afs_syscall, + "setfsuid": C.__NR_setfsuid, + "setfsgid": C.__NR_setfsgid, + "_llseek": C.__NR__llseek, + "getdents": C.__NR_getdents, + "_newselect": C.__NR__newselect, + "flock": C.__NR_flock, + "msync": C.__NR_msync, + "readv": C.__NR_readv, + "writev": C.__NR_writev, + "getsid": C.__NR_getsid, + "fdatasync": C.__NR_fdatasync, + "_sysctl": C.__NR__sysctl, + "mlock": C.__NR_mlock, + "munlock": C.__NR_munlock, + "mlockall": C.__NR_mlockall, + "munlockall": C.__NR_munlockall, + "sched_setparam": C.__NR_sched_setparam, + "sched_getparam": C.__NR_sched_getparam, + "sched_setscheduler": C.__NR_sched_setscheduler, + "sched_getscheduler": C.__NR_sched_getscheduler, + "sched_yield": C.__NR_sched_yield, + "sched_get_priority_max": C.__NR_sched_get_priority_max, + "sched_get_priority_min": C.__NR_sched_get_priority_min, + "sched_rr_get_interval": C.__NR_sched_rr_get_interval, + "nanosleep": C.__NR_nanosleep, + "mremap": C.__NR_mremap, + "setresuid": C.__NR_setresuid, + "getresuid": C.__NR_getresuid, + "vm86": C.__NR_vm86, + "query_module": C.__NR_query_module, + "poll": C.__NR_poll, + "nfsservctl": C.__NR_nfsservctl, + "setresgid": C.__NR_setresgid, + "getresgid": C.__NR_getresgid, + "prctl": C.__NR_prctl, + "rt_sigreturn": C.__NR_rt_sigreturn, + "rt_sigaction": C.__NR_rt_sigaction, + "rt_sigprocmask": C.__NR_rt_sigprocmask, + "rt_sigpending": C.__NR_rt_sigpending, + "rt_sigtimedwait": C.__NR_rt_sigtimedwait, + "rt_sigqueueinfo": C.__NR_rt_sigqueueinfo, + "rt_sigsuspend": C.__NR_rt_sigsuspend, + "pread64": C.__NR_pread64, + "pwrite64": C.__NR_pwrite64, + "chown": C.__NR_chown, + "getcwd": C.__NR_getcwd, + "capget": C.__NR_capget, + "capset": C.__NR_capset, + "sigaltstack": C.__NR_sigaltstack, + "sendfile": C.__NR_sendfile, + "getpmsg": C.__NR_getpmsg, + "putpmsg": C.__NR_putpmsg, + "vfork": C.__NR_vfork, + "ugetrlimit": C.__NR_ugetrlimit, + "mmap2": C.__NR_mmap2, + "truncate64": C.__NR_truncate64, + "ftruncate64": C.__NR_ftruncate64, + "stat64": C.__NR_stat64, + "lstat64": C.__NR_lstat64, + "fstat64": C.__NR_fstat64, + "lchown32": C.__NR_lchown32, + "getuid32": C.__NR_getuid32, + "getgid32": C.__NR_getgid32, + "geteuid32": C.__NR_geteuid32, + "getegid32": C.__NR_getegid32, + "setreuid32": C.__NR_setreuid32, + "setregid32": C.__NR_setregid32, + "getgroups32": C.__NR_getgroups32, + "setgroups32": C.__NR_setgroups32, + "fchown32": C.__NR_fchown32, + "setresuid32": C.__NR_setresuid32, + "getresuid32": C.__NR_getresuid32, + "setresgid32": C.__NR_setresgid32, + "getresgid32": C.__NR_getresgid32, + "chown32": C.__NR_chown32, + "setuid32": C.__NR_setuid32, + "setgid32": C.__NR_setgid32, + "setfsuid32": C.__NR_setfsuid32, + "setfsgid32": C.__NR_setfsgid32, + "pivot_root": C.__NR_pivot_root, + "mincore": C.__NR_mincore, + "madvise": C.__NR_madvise, + "getdents64": C.__NR_getdents64, + "fcntl64": C.__NR_fcntl64, + "gettid": C.__NR_gettid, + "readahead": C.__NR_readahead, + "setxattr": C.__NR_setxattr, + "lsetxattr": C.__NR_lsetxattr, + "fsetxattr": C.__NR_fsetxattr, + "getxattr": C.__NR_getxattr, + "lgetxattr": C.__NR_lgetxattr, + "fgetxattr": C.__NR_fgetxattr, + "listxattr": C.__NR_listxattr, + "llistxattr": C.__NR_llistxattr, + "flistxattr": C.__NR_flistxattr, + "removexattr": C.__NR_removexattr, + "lremovexattr": C.__NR_lremovexattr, + "fremovexattr": C.__NR_fremovexattr, + "tkill": C.__NR_tkill, + "sendfile64": C.__NR_sendfile64, + "futex": C.__NR_futex, + "sched_setaffinity": C.__NR_sched_setaffinity, + "sched_getaffinity": C.__NR_sched_getaffinity, + "set_thread_area": C.__NR_set_thread_area, + "get_thread_area": C.__NR_get_thread_area, + "io_setup": C.__NR_io_setup, + "io_destroy": C.__NR_io_destroy, + "io_getevents": C.__NR_io_getevents, + "io_submit": C.__NR_io_submit, + "io_cancel": C.__NR_io_cancel, + "fadvise64": C.__NR_fadvise64, + "exit_group": C.__NR_exit_group, + "lookup_dcookie": C.__NR_lookup_dcookie, + "epoll_create": C.__NR_epoll_create, + "epoll_ctl": C.__NR_epoll_ctl, + "epoll_wait": C.__NR_epoll_wait, + "remap_file_pages": C.__NR_remap_file_pages, + "set_tid_address": C.__NR_set_tid_address, + "timer_create": C.__NR_timer_create, + "timer_settime": C.__NR_timer_settime, + "timer_gettime": C.__NR_timer_gettime, + "timer_getoverrun": C.__NR_timer_getoverrun, + "timer_delete": C.__NR_timer_delete, + "clock_settime": C.__NR_clock_settime, + "clock_gettime": C.__NR_clock_gettime, + "clock_getres": C.__NR_clock_getres, + "clock_nanosleep": C.__NR_clock_nanosleep, + "statfs64": C.__NR_statfs64, + "fstatfs64": C.__NR_fstatfs64, + "tgkill": C.__NR_tgkill, + "utimes": C.__NR_utimes, + "fadvise64_64": C.__NR_fadvise64_64, + "vserver": C.__NR_vserver, + "mbind": C.__NR_mbind, + "get_mempolicy": C.__NR_get_mempolicy, + "set_mempolicy": C.__NR_set_mempolicy, + "mq_open": C.__NR_mq_open, + "mq_unlink": C.__NR_mq_unlink, + "mq_timedsend": C.__NR_mq_timedsend, + "mq_timedreceive": C.__NR_mq_timedreceive, + "mq_notify": C.__NR_mq_notify, + "mq_getsetattr": C.__NR_mq_getsetattr, + "kexec_load": C.__NR_kexec_load, + "waitid": C.__NR_waitid, + "add_key": C.__NR_add_key, + "request_key": C.__NR_request_key, + "keyctl": C.__NR_keyctl, + "ioprio_set": C.__NR_ioprio_set, + "ioprio_get": C.__NR_ioprio_get, + "inotify_init": C.__NR_inotify_init, + "inotify_add_watch": C.__NR_inotify_add_watch, + "inotify_rm_watch": C.__NR_inotify_rm_watch, + "migrate_pages": C.__NR_migrate_pages, + "openat": C.__NR_openat, + "mkdirat": C.__NR_mkdirat, + "mknodat": C.__NR_mknodat, + "fchownat": C.__NR_fchownat, + "futimesat": C.__NR_futimesat, + "fstatat64": C.__NR_fstatat64, + "unlinkat": C.__NR_unlinkat, + "renameat": C.__NR_renameat, + "linkat": C.__NR_linkat, + "symlinkat": C.__NR_symlinkat, + "readlinkat": C.__NR_readlinkat, + "fchmodat": C.__NR_fchmodat, + "faccessat": C.__NR_faccessat, + "pselect6": C.__NR_pselect6, + "ppoll": C.__NR_ppoll, + "unshare": C.__NR_unshare, + "set_robust_list": C.__NR_set_robust_list, + "get_robust_list": C.__NR_get_robust_list, + "splice": C.__NR_splice, + "sync_file_range": C.__NR_sync_file_range, + "tee": C.__NR_tee, + "vmsplice": C.__NR_vmsplice, + "move_pages": C.__NR_move_pages, + "getcpu": C.__NR_getcpu, + "epoll_pwait": C.__NR_epoll_pwait, + "utimensat": C.__NR_utimensat, + "signalfd": C.__NR_signalfd, + "timerfd_create": C.__NR_timerfd_create, + "eventfd": C.__NR_eventfd, + "fallocate": C.__NR_fallocate, + "timerfd_settime": C.__NR_timerfd_settime, + "timerfd_gettime": C.__NR_timerfd_gettime, + "signalfd4": C.__NR_signalfd4, + "eventfd2": C.__NR_eventfd2, + "epoll_create1": C.__NR_epoll_create1, + "dup3": C.__NR_dup3, + "pipe2": C.__NR_pipe2, + "inotify_init1": C.__NR_inotify_init1, + "preadv": C.__NR_preadv, + "pwritev": C.__NR_pwritev, + "rt_tgsigqueueinfo": C.__NR_rt_tgsigqueueinfo, + "perf_event_open": C.__NR_perf_event_open, + "recvmmsg": C.__NR_recvmmsg, + "fanotify_init": C.__NR_fanotify_init, + "fanotify_mark": C.__NR_fanotify_mark, + "prlimit64": C.__NR_prlimit64, + "name_to_handle_at": C.__NR_name_to_handle_at, + "open_by_handle_at": C.__NR_open_by_handle_at, + "clock_adjtime": C.__NR_clock_adjtime, + "syncfs": C.__NR_syncfs, + "sendmmsg": C.__NR_sendmmsg, + "setns": C.__NR_setns, + "process_vm_readv": C.__NR_process_vm_readv, + "process_vm_writev": C.__NR_process_vm_writev, + "kcmp": C.__NR_kcmp, + "finit_module": C.__NR_finit_module, + "sched_setattr": C.__NR_sched_setattr, + "sched_getattr": C.__NR_sched_getattr, + "renameat2": C.__NR_renameat2, + "seccomp": C.__NR_seccomp, + "getrandom": C.__NR_getrandom, + "memfd_create": C.__NR_memfd_create, + "bpf": C.__NR_bpf, + "execveat": C.__NR_execveat, +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_amd64.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_amd64.go new file mode 100644 index 0000000..c4511c9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_amd64.go @@ -0,0 +1,333 @@ +// DO NOT EDIT. Autogenerated by syscalls_gen.go + +package seccomp + +// #include "unistd_64.h" +import "C" + +// syscallNum maps system call names to numbers. +var syscallNum = map[string]int{ + "read": C.__NR_read, + "write": C.__NR_write, + "open": C.__NR_open, + "close": C.__NR_close, + "stat": C.__NR_stat, + "fstat": C.__NR_fstat, + "lstat": C.__NR_lstat, + "poll": C.__NR_poll, + "lseek": C.__NR_lseek, + "mmap": C.__NR_mmap, + "mprotect": C.__NR_mprotect, + "munmap": C.__NR_munmap, + "brk": C.__NR_brk, + "rt_sigaction": C.__NR_rt_sigaction, + "rt_sigprocmask": C.__NR_rt_sigprocmask, + "rt_sigreturn": C.__NR_rt_sigreturn, + "ioctl": C.__NR_ioctl, + "pread64": C.__NR_pread64, + "pwrite64": C.__NR_pwrite64, + "readv": C.__NR_readv, + "writev": C.__NR_writev, + "access": C.__NR_access, + "pipe": C.__NR_pipe, + "select": C.__NR_select, + "sched_yield": C.__NR_sched_yield, + "mremap": C.__NR_mremap, + "msync": C.__NR_msync, + "mincore": C.__NR_mincore, + "madvise": C.__NR_madvise, + "shmget": C.__NR_shmget, + "shmat": C.__NR_shmat, + "shmctl": C.__NR_shmctl, + "dup": C.__NR_dup, + "dup2": C.__NR_dup2, + "pause": C.__NR_pause, + "nanosleep": C.__NR_nanosleep, + "getitimer": C.__NR_getitimer, + "alarm": C.__NR_alarm, + "setitimer": C.__NR_setitimer, + "getpid": C.__NR_getpid, + "sendfile": C.__NR_sendfile, + "socket": C.__NR_socket, + "connect": C.__NR_connect, + "accept": C.__NR_accept, + "sendto": C.__NR_sendto, + "recvfrom": C.__NR_recvfrom, + "sendmsg": C.__NR_sendmsg, + "recvmsg": C.__NR_recvmsg, + "shutdown": C.__NR_shutdown, + "bind": C.__NR_bind, + "listen": C.__NR_listen, + "getsockname": C.__NR_getsockname, + "getpeername": C.__NR_getpeername, + "socketpair": C.__NR_socketpair, + "setsockopt": C.__NR_setsockopt, + "getsockopt": C.__NR_getsockopt, + "clone": C.__NR_clone, + "fork": C.__NR_fork, + "vfork": C.__NR_vfork, + "execve": C.__NR_execve, + "exit": C.__NR_exit, + "wait4": C.__NR_wait4, + "kill": C.__NR_kill, + "uname": C.__NR_uname, + "semget": C.__NR_semget, + "semop": C.__NR_semop, + "semctl": C.__NR_semctl, + "shmdt": C.__NR_shmdt, + "msgget": C.__NR_msgget, + "msgsnd": C.__NR_msgsnd, + "msgrcv": C.__NR_msgrcv, + "msgctl": C.__NR_msgctl, + "fcntl": C.__NR_fcntl, + "flock": C.__NR_flock, + "fsync": C.__NR_fsync, + "fdatasync": C.__NR_fdatasync, + "truncate": C.__NR_truncate, + "ftruncate": C.__NR_ftruncate, + "getdents": C.__NR_getdents, + "getcwd": C.__NR_getcwd, + "chdir": C.__NR_chdir, + "fchdir": C.__NR_fchdir, + "rename": C.__NR_rename, + "mkdir": C.__NR_mkdir, + "rmdir": C.__NR_rmdir, + "creat": C.__NR_creat, + "link": C.__NR_link, + "unlink": C.__NR_unlink, + "symlink": C.__NR_symlink, + "readlink": C.__NR_readlink, + "chmod": C.__NR_chmod, + "fchmod": C.__NR_fchmod, + "chown": C.__NR_chown, + "fchown": C.__NR_fchown, + "lchown": C.__NR_lchown, + "umask": C.__NR_umask, + "gettimeofday": C.__NR_gettimeofday, + "getrlimit": C.__NR_getrlimit, + "getrusage": C.__NR_getrusage, + "sysinfo": C.__NR_sysinfo, + "times": C.__NR_times, + "ptrace": C.__NR_ptrace, + "getuid": C.__NR_getuid, + "syslog": C.__NR_syslog, + "getgid": C.__NR_getgid, + "setuid": C.__NR_setuid, + "setgid": C.__NR_setgid, + "geteuid": C.__NR_geteuid, + "getegid": C.__NR_getegid, + "setpgid": C.__NR_setpgid, + "getppid": C.__NR_getppid, + "getpgrp": C.__NR_getpgrp, + "setsid": C.__NR_setsid, + "setreuid": C.__NR_setreuid, + "setregid": C.__NR_setregid, + "getgroups": C.__NR_getgroups, + "setgroups": C.__NR_setgroups, + "setresuid": C.__NR_setresuid, + "getresuid": C.__NR_getresuid, + "setresgid": C.__NR_setresgid, + "getresgid": C.__NR_getresgid, + "getpgid": C.__NR_getpgid, + "setfsuid": C.__NR_setfsuid, + "setfsgid": C.__NR_setfsgid, + "getsid": C.__NR_getsid, + "capget": C.__NR_capget, + "capset": C.__NR_capset, + "rt_sigpending": C.__NR_rt_sigpending, + "rt_sigtimedwait": C.__NR_rt_sigtimedwait, + "rt_sigqueueinfo": C.__NR_rt_sigqueueinfo, + "rt_sigsuspend": C.__NR_rt_sigsuspend, + "sigaltstack": C.__NR_sigaltstack, + "utime": C.__NR_utime, + "mknod": C.__NR_mknod, + "uselib": C.__NR_uselib, + "personality": C.__NR_personality, + "ustat": C.__NR_ustat, + "statfs": C.__NR_statfs, + "fstatfs": C.__NR_fstatfs, + "sysfs": C.__NR_sysfs, + "getpriority": C.__NR_getpriority, + "setpriority": C.__NR_setpriority, + "sched_setparam": C.__NR_sched_setparam, + "sched_getparam": C.__NR_sched_getparam, + "sched_setscheduler": C.__NR_sched_setscheduler, + "sched_getscheduler": C.__NR_sched_getscheduler, + "sched_get_priority_max": C.__NR_sched_get_priority_max, + "sched_get_priority_min": C.__NR_sched_get_priority_min, + "sched_rr_get_interval": C.__NR_sched_rr_get_interval, + "mlock": C.__NR_mlock, + "munlock": C.__NR_munlock, + "mlockall": C.__NR_mlockall, + "munlockall": C.__NR_munlockall, + "vhangup": C.__NR_vhangup, + "modify_ldt": C.__NR_modify_ldt, + "pivot_root": C.__NR_pivot_root, + "_sysctl": C.__NR__sysctl, + "prctl": C.__NR_prctl, + "arch_prctl": C.__NR_arch_prctl, + "adjtimex": C.__NR_adjtimex, + "setrlimit": C.__NR_setrlimit, + "chroot": C.__NR_chroot, + "sync": C.__NR_sync, + "acct": C.__NR_acct, + "settimeofday": C.__NR_settimeofday, + "mount": C.__NR_mount, + "umount2": C.__NR_umount2, + "swapon": C.__NR_swapon, + "swapoff": C.__NR_swapoff, + "reboot": C.__NR_reboot, + "sethostname": C.__NR_sethostname, + "setdomainname": C.__NR_setdomainname, + "iopl": C.__NR_iopl, + "ioperm": C.__NR_ioperm, + "create_module": C.__NR_create_module, + "init_module": C.__NR_init_module, + "delete_module": C.__NR_delete_module, + "get_kernel_syms": C.__NR_get_kernel_syms, + "query_module": C.__NR_query_module, + "quotactl": C.__NR_quotactl, + "nfsservctl": C.__NR_nfsservctl, + "getpmsg": C.__NR_getpmsg, + "putpmsg": C.__NR_putpmsg, + "afs_syscall": C.__NR_afs_syscall, + "tuxcall": C.__NR_tuxcall, + "security": C.__NR_security, + "gettid": C.__NR_gettid, + "readahead": C.__NR_readahead, + "setxattr": C.__NR_setxattr, + "lsetxattr": C.__NR_lsetxattr, + "fsetxattr": C.__NR_fsetxattr, + "getxattr": C.__NR_getxattr, + "lgetxattr": C.__NR_lgetxattr, + "fgetxattr": C.__NR_fgetxattr, + "listxattr": C.__NR_listxattr, + "llistxattr": C.__NR_llistxattr, + "flistxattr": C.__NR_flistxattr, + "removexattr": C.__NR_removexattr, + "lremovexattr": C.__NR_lremovexattr, + "fremovexattr": C.__NR_fremovexattr, + "tkill": C.__NR_tkill, + "time": C.__NR_time, + "futex": C.__NR_futex, + "sched_setaffinity": C.__NR_sched_setaffinity, + "sched_getaffinity": C.__NR_sched_getaffinity, + "set_thread_area": C.__NR_set_thread_area, + "io_setup": C.__NR_io_setup, + "io_destroy": C.__NR_io_destroy, + "io_getevents": C.__NR_io_getevents, + "io_submit": C.__NR_io_submit, + "io_cancel": C.__NR_io_cancel, + "get_thread_area": C.__NR_get_thread_area, + "lookup_dcookie": C.__NR_lookup_dcookie, + "epoll_create": C.__NR_epoll_create, + "epoll_ctl_old": C.__NR_epoll_ctl_old, + "epoll_wait_old": C.__NR_epoll_wait_old, + "remap_file_pages": C.__NR_remap_file_pages, + "getdents64": C.__NR_getdents64, + "set_tid_address": C.__NR_set_tid_address, + "restart_syscall": C.__NR_restart_syscall, + "semtimedop": C.__NR_semtimedop, + "fadvise64": C.__NR_fadvise64, + "timer_create": C.__NR_timer_create, + "timer_settime": C.__NR_timer_settime, + "timer_gettime": C.__NR_timer_gettime, + "timer_getoverrun": C.__NR_timer_getoverrun, + "timer_delete": C.__NR_timer_delete, + "clock_settime": C.__NR_clock_settime, + "clock_gettime": C.__NR_clock_gettime, + "clock_getres": C.__NR_clock_getres, + "clock_nanosleep": C.__NR_clock_nanosleep, + "exit_group": C.__NR_exit_group, + "epoll_wait": C.__NR_epoll_wait, + "epoll_ctl": C.__NR_epoll_ctl, + "tgkill": C.__NR_tgkill, + "utimes": C.__NR_utimes, + "vserver": C.__NR_vserver, + "mbind": C.__NR_mbind, + "set_mempolicy": C.__NR_set_mempolicy, + "get_mempolicy": C.__NR_get_mempolicy, + "mq_open": C.__NR_mq_open, + "mq_unlink": C.__NR_mq_unlink, + "mq_timedsend": C.__NR_mq_timedsend, + "mq_timedreceive": C.__NR_mq_timedreceive, + "mq_notify": C.__NR_mq_notify, + "mq_getsetattr": C.__NR_mq_getsetattr, + "kexec_load": C.__NR_kexec_load, + "waitid": C.__NR_waitid, + "add_key": C.__NR_add_key, + "request_key": C.__NR_request_key, + "keyctl": C.__NR_keyctl, + "ioprio_set": C.__NR_ioprio_set, + "ioprio_get": C.__NR_ioprio_get, + "inotify_init": C.__NR_inotify_init, + "inotify_add_watch": C.__NR_inotify_add_watch, + "inotify_rm_watch": C.__NR_inotify_rm_watch, + "migrate_pages": C.__NR_migrate_pages, + "openat": C.__NR_openat, + "mkdirat": C.__NR_mkdirat, + "mknodat": C.__NR_mknodat, + "fchownat": C.__NR_fchownat, + "futimesat": C.__NR_futimesat, + "newfstatat": C.__NR_newfstatat, + "unlinkat": C.__NR_unlinkat, + "renameat": C.__NR_renameat, + "linkat": C.__NR_linkat, + "symlinkat": C.__NR_symlinkat, + "readlinkat": C.__NR_readlinkat, + "fchmodat": C.__NR_fchmodat, + "faccessat": C.__NR_faccessat, + "pselect6": C.__NR_pselect6, + "ppoll": C.__NR_ppoll, + "unshare": C.__NR_unshare, + "set_robust_list": C.__NR_set_robust_list, + "get_robust_list": C.__NR_get_robust_list, + "splice": C.__NR_splice, + "tee": C.__NR_tee, + "sync_file_range": C.__NR_sync_file_range, + "vmsplice": C.__NR_vmsplice, + "move_pages": C.__NR_move_pages, + "utimensat": C.__NR_utimensat, + "epoll_pwait": C.__NR_epoll_pwait, + "signalfd": C.__NR_signalfd, + "timerfd_create": C.__NR_timerfd_create, + "eventfd": C.__NR_eventfd, + "fallocate": C.__NR_fallocate, + "timerfd_settime": C.__NR_timerfd_settime, + "timerfd_gettime": C.__NR_timerfd_gettime, + "accept4": C.__NR_accept4, + "signalfd4": C.__NR_signalfd4, + "eventfd2": C.__NR_eventfd2, + "epoll_create1": C.__NR_epoll_create1, + "dup3": C.__NR_dup3, + "pipe2": C.__NR_pipe2, + "inotify_init1": C.__NR_inotify_init1, + "preadv": C.__NR_preadv, + "pwritev": C.__NR_pwritev, + "rt_tgsigqueueinfo": C.__NR_rt_tgsigqueueinfo, + "perf_event_open": C.__NR_perf_event_open, + "recvmmsg": C.__NR_recvmmsg, + "fanotify_init": C.__NR_fanotify_init, + "fanotify_mark": C.__NR_fanotify_mark, + "prlimit64": C.__NR_prlimit64, + "name_to_handle_at": C.__NR_name_to_handle_at, + "open_by_handle_at": C.__NR_open_by_handle_at, + "clock_adjtime": C.__NR_clock_adjtime, + "syncfs": C.__NR_syncfs, + "sendmmsg": C.__NR_sendmmsg, + "setns": C.__NR_setns, + "getcpu": C.__NR_getcpu, + "process_vm_readv": C.__NR_process_vm_readv, + "process_vm_writev": C.__NR_process_vm_writev, + "kcmp": C.__NR_kcmp, + "finit_module": C.__NR_finit_module, + "sched_setattr": C.__NR_sched_setattr, + "sched_getattr": C.__NR_sched_getattr, + "renameat2": C.__NR_renameat2, + "seccomp": C.__NR_seccomp, + "getrandom": C.__NR_getrandom, + "memfd_create": C.__NR_memfd_create, + "kexec_file_load": C.__NR_kexec_file_load, + "bpf": C.__NR_bpf, + "execveat": C.__NR_execveat, +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_arm.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_arm.go new file mode 100644 index 0000000..829a0ac --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_arm.go @@ -0,0 +1,359 @@ +// DO NOT EDIT. Autogenerated by syscalls_gen.go + +package seccomp + +// #include +import "C" + +// syscallNum maps system call names to numbers. +var syscallNum = map[string]int{ + "restart_syscall": C.__NR_restart_syscall, + "exit": C.__NR_exit, + "fork": C.__NR_fork, + "read": C.__NR_read, + "write": C.__NR_write, + "open": C.__NR_open, + "close": C.__NR_close, + "creat": C.__NR_creat, + "link": C.__NR_link, + "unlink": C.__NR_unlink, + "execve": C.__NR_execve, + "chdir": C.__NR_chdir, + "mknod": C.__NR_mknod, + "chmod": C.__NR_chmod, + "lchown": C.__NR_lchown, + "lseek": C.__NR_lseek, + "getpid": C.__NR_getpid, + "mount": C.__NR_mount, + "setuid": C.__NR_setuid, + "getuid": C.__NR_getuid, + "ptrace": C.__NR_ptrace, + "pause": C.__NR_pause, + "access": C.__NR_access, + "nice": C.__NR_nice, + "sync": C.__NR_sync, + "kill": C.__NR_kill, + "rename": C.__NR_rename, + "mkdir": C.__NR_mkdir, + "rmdir": C.__NR_rmdir, + "dup": C.__NR_dup, + "pipe": C.__NR_pipe, + "times": C.__NR_times, + "brk": C.__NR_brk, + "setgid": C.__NR_setgid, + "getgid": C.__NR_getgid, + "geteuid": C.__NR_geteuid, + "getegid": C.__NR_getegid, + "acct": C.__NR_acct, + "umount2": C.__NR_umount2, + "ioctl": C.__NR_ioctl, + "fcntl": C.__NR_fcntl, + "setpgid": C.__NR_setpgid, + "umask": C.__NR_umask, + "chroot": C.__NR_chroot, + "ustat": C.__NR_ustat, + "dup2": C.__NR_dup2, + "getppid": C.__NR_getppid, + "getpgrp": C.__NR_getpgrp, + "setsid": C.__NR_setsid, + "sigaction": C.__NR_sigaction, + "setreuid": C.__NR_setreuid, + "setregid": C.__NR_setregid, + "sigsuspend": C.__NR_sigsuspend, + "sigpending": C.__NR_sigpending, + "sethostname": C.__NR_sethostname, + "setrlimit": C.__NR_setrlimit, + "getrusage": C.__NR_getrusage, + "gettimeofday": C.__NR_gettimeofday, + "settimeofday": C.__NR_settimeofday, + "getgroups": C.__NR_getgroups, + "setgroups": C.__NR_setgroups, + "symlink": C.__NR_symlink, + "readlink": C.__NR_readlink, + "uselib": C.__NR_uselib, + "swapon": C.__NR_swapon, + "reboot": C.__NR_reboot, + "munmap": C.__NR_munmap, + "truncate": C.__NR_truncate, + "ftruncate": C.__NR_ftruncate, + "fchmod": C.__NR_fchmod, + "fchown": C.__NR_fchown, + "getpriority": C.__NR_getpriority, + "setpriority": C.__NR_setpriority, + "statfs": C.__NR_statfs, + "fstatfs": C.__NR_fstatfs, + "syslog": C.__NR_syslog, + "setitimer": C.__NR_setitimer, + "getitimer": C.__NR_getitimer, + "stat": C.__NR_stat, + "lstat": C.__NR_lstat, + "fstat": C.__NR_fstat, + "vhangup": C.__NR_vhangup, + "wait4": C.__NR_wait4, + "swapoff": C.__NR_swapoff, + "sysinfo": C.__NR_sysinfo, + "fsync": C.__NR_fsync, + "sigreturn": C.__NR_sigreturn, + "clone": C.__NR_clone, + "setdomainname": C.__NR_setdomainname, + "uname": C.__NR_uname, + "adjtimex": C.__NR_adjtimex, + "mprotect": C.__NR_mprotect, + "sigprocmask": C.__NR_sigprocmask, + "init_module": C.__NR_init_module, + "delete_module": C.__NR_delete_module, + "quotactl": C.__NR_quotactl, + "getpgid": C.__NR_getpgid, + "fchdir": C.__NR_fchdir, + "bdflush": C.__NR_bdflush, + "sysfs": C.__NR_sysfs, + "personality": C.__NR_personality, + "setfsuid": C.__NR_setfsuid, + "setfsgid": C.__NR_setfsgid, + "_llseek": C.__NR__llseek, + "getdents": C.__NR_getdents, + "_newselect": C.__NR__newselect, + "flock": C.__NR_flock, + "msync": C.__NR_msync, + "readv": C.__NR_readv, + "writev": C.__NR_writev, + "getsid": C.__NR_getsid, + "fdatasync": C.__NR_fdatasync, + "_sysctl": C.__NR__sysctl, + "mlock": C.__NR_mlock, + "munlock": C.__NR_munlock, + "mlockall": C.__NR_mlockall, + "munlockall": C.__NR_munlockall, + "sched_setparam": C.__NR_sched_setparam, + "sched_getparam": C.__NR_sched_getparam, + "sched_setscheduler": C.__NR_sched_setscheduler, + "sched_getscheduler": C.__NR_sched_getscheduler, + "sched_yield": C.__NR_sched_yield, + "sched_get_priority_max": C.__NR_sched_get_priority_max, + "sched_get_priority_min": C.__NR_sched_get_priority_min, + "sched_rr_get_interval": C.__NR_sched_rr_get_interval, + "nanosleep": C.__NR_nanosleep, + "mremap": C.__NR_mremap, + "setresuid": C.__NR_setresuid, + "getresuid": C.__NR_getresuid, + "poll": C.__NR_poll, + "nfsservctl": C.__NR_nfsservctl, + "setresgid": C.__NR_setresgid, + "getresgid": C.__NR_getresgid, + "prctl": C.__NR_prctl, + "rt_sigreturn": C.__NR_rt_sigreturn, + "rt_sigaction": C.__NR_rt_sigaction, + "rt_sigprocmask": C.__NR_rt_sigprocmask, + "rt_sigpending": C.__NR_rt_sigpending, + "rt_sigtimedwait": C.__NR_rt_sigtimedwait, + "rt_sigqueueinfo": C.__NR_rt_sigqueueinfo, + "rt_sigsuspend": C.__NR_rt_sigsuspend, + "pread64": C.__NR_pread64, + "pwrite64": C.__NR_pwrite64, + "chown": C.__NR_chown, + "getcwd": C.__NR_getcwd, + "capget": C.__NR_capget, + "capset": C.__NR_capset, + "sigaltstack": C.__NR_sigaltstack, + "sendfile": C.__NR_sendfile, + "vfork": C.__NR_vfork, + "ugetrlimit": C.__NR_ugetrlimit, + "mmap2": C.__NR_mmap2, + "truncate64": C.__NR_truncate64, + "ftruncate64": C.__NR_ftruncate64, + "stat64": C.__NR_stat64, + "lstat64": C.__NR_lstat64, + "fstat64": C.__NR_fstat64, + "lchown32": C.__NR_lchown32, + "getuid32": C.__NR_getuid32, + "getgid32": C.__NR_getgid32, + "geteuid32": C.__NR_geteuid32, + "getegid32": C.__NR_getegid32, + "setreuid32": C.__NR_setreuid32, + "setregid32": C.__NR_setregid32, + "getgroups32": C.__NR_getgroups32, + "setgroups32": C.__NR_setgroups32, + "fchown32": C.__NR_fchown32, + "setresuid32": C.__NR_setresuid32, + "getresuid32": C.__NR_getresuid32, + "setresgid32": C.__NR_setresgid32, + "getresgid32": C.__NR_getresgid32, + "chown32": C.__NR_chown32, + "setuid32": C.__NR_setuid32, + "setgid32": C.__NR_setgid32, + "setfsuid32": C.__NR_setfsuid32, + "setfsgid32": C.__NR_setfsgid32, + "getdents64": C.__NR_getdents64, + "pivot_root": C.__NR_pivot_root, + "mincore": C.__NR_mincore, + "madvise": C.__NR_madvise, + "fcntl64": C.__NR_fcntl64, + "gettid": C.__NR_gettid, + "readahead": C.__NR_readahead, + "setxattr": C.__NR_setxattr, + "lsetxattr": C.__NR_lsetxattr, + "fsetxattr": C.__NR_fsetxattr, + "getxattr": C.__NR_getxattr, + "lgetxattr": C.__NR_lgetxattr, + "fgetxattr": C.__NR_fgetxattr, + "listxattr": C.__NR_listxattr, + "llistxattr": C.__NR_llistxattr, + "flistxattr": C.__NR_flistxattr, + "removexattr": C.__NR_removexattr, + "lremovexattr": C.__NR_lremovexattr, + "fremovexattr": C.__NR_fremovexattr, + "tkill": C.__NR_tkill, + "sendfile64": C.__NR_sendfile64, + "futex": C.__NR_futex, + "sched_setaffinity": C.__NR_sched_setaffinity, + "sched_getaffinity": C.__NR_sched_getaffinity, + "io_setup": C.__NR_io_setup, + "io_destroy": C.__NR_io_destroy, + "io_getevents": C.__NR_io_getevents, + "io_submit": C.__NR_io_submit, + "io_cancel": C.__NR_io_cancel, + "exit_group": C.__NR_exit_group, + "lookup_dcookie": C.__NR_lookup_dcookie, + "epoll_create": C.__NR_epoll_create, + "epoll_ctl": C.__NR_epoll_ctl, + "epoll_wait": C.__NR_epoll_wait, + "remap_file_pages": C.__NR_remap_file_pages, + "set_tid_address": C.__NR_set_tid_address, + "timer_create": C.__NR_timer_create, + "timer_settime": C.__NR_timer_settime, + "timer_gettime": C.__NR_timer_gettime, + "timer_getoverrun": C.__NR_timer_getoverrun, + "timer_delete": C.__NR_timer_delete, + "clock_settime": C.__NR_clock_settime, + "clock_gettime": C.__NR_clock_gettime, + "clock_getres": C.__NR_clock_getres, + "clock_nanosleep": C.__NR_clock_nanosleep, + "statfs64": C.__NR_statfs64, + "fstatfs64": C.__NR_fstatfs64, + "tgkill": C.__NR_tgkill, + "utimes": C.__NR_utimes, + "arm_fadvise64_64": C.__NR_arm_fadvise64_64, + "pciconfig_iobase": C.__NR_pciconfig_iobase, + "pciconfig_read": C.__NR_pciconfig_read, + "pciconfig_write": C.__NR_pciconfig_write, + "mq_open": C.__NR_mq_open, + "mq_unlink": C.__NR_mq_unlink, + "mq_timedsend": C.__NR_mq_timedsend, + "mq_timedreceive": C.__NR_mq_timedreceive, + "mq_notify": C.__NR_mq_notify, + "mq_getsetattr": C.__NR_mq_getsetattr, + "waitid": C.__NR_waitid, + "socket": C.__NR_socket, + "bind": C.__NR_bind, + "connect": C.__NR_connect, + "listen": C.__NR_listen, + "accept": C.__NR_accept, + "getsockname": C.__NR_getsockname, + "getpeername": C.__NR_getpeername, + "socketpair": C.__NR_socketpair, + "send": C.__NR_send, + "sendto": C.__NR_sendto, + "recv": C.__NR_recv, + "recvfrom": C.__NR_recvfrom, + "shutdown": C.__NR_shutdown, + "setsockopt": C.__NR_setsockopt, + "getsockopt": C.__NR_getsockopt, + "sendmsg": C.__NR_sendmsg, + "recvmsg": C.__NR_recvmsg, + "semop": C.__NR_semop, + "semget": C.__NR_semget, + "semctl": C.__NR_semctl, + "msgsnd": C.__NR_msgsnd, + "msgrcv": C.__NR_msgrcv, + "msgget": C.__NR_msgget, + "msgctl": C.__NR_msgctl, + "shmat": C.__NR_shmat, + "shmdt": C.__NR_shmdt, + "shmget": C.__NR_shmget, + "shmctl": C.__NR_shmctl, + "add_key": C.__NR_add_key, + "request_key": C.__NR_request_key, + "keyctl": C.__NR_keyctl, + "semtimedop": C.__NR_semtimedop, + "vserver": C.__NR_vserver, + "ioprio_set": C.__NR_ioprio_set, + "ioprio_get": C.__NR_ioprio_get, + "inotify_init": C.__NR_inotify_init, + "inotify_add_watch": C.__NR_inotify_add_watch, + "inotify_rm_watch": C.__NR_inotify_rm_watch, + "mbind": C.__NR_mbind, + "get_mempolicy": C.__NR_get_mempolicy, + "set_mempolicy": C.__NR_set_mempolicy, + "openat": C.__NR_openat, + "mkdirat": C.__NR_mkdirat, + "mknodat": C.__NR_mknodat, + "fchownat": C.__NR_fchownat, + "futimesat": C.__NR_futimesat, + "fstatat64": C.__NR_fstatat64, + "unlinkat": C.__NR_unlinkat, + "renameat": C.__NR_renameat, + "linkat": C.__NR_linkat, + "symlinkat": C.__NR_symlinkat, + "readlinkat": C.__NR_readlinkat, + "fchmodat": C.__NR_fchmodat, + "faccessat": C.__NR_faccessat, + "pselect6": C.__NR_pselect6, + "ppoll": C.__NR_ppoll, + "unshare": C.__NR_unshare, + "set_robust_list": C.__NR_set_robust_list, + "get_robust_list": C.__NR_get_robust_list, + "splice": C.__NR_splice, + "arm_sync_file_range": C.__NR_arm_sync_file_range, + "sync_file_range2": C.__NR_sync_file_range2, + "tee": C.__NR_tee, + "vmsplice": C.__NR_vmsplice, + "move_pages": C.__NR_move_pages, + "getcpu": C.__NR_getcpu, + "epoll_pwait": C.__NR_epoll_pwait, + "kexec_load": C.__NR_kexec_load, + "utimensat": C.__NR_utimensat, + "signalfd": C.__NR_signalfd, + "timerfd_create": C.__NR_timerfd_create, + "eventfd": C.__NR_eventfd, + "fallocate": C.__NR_fallocate, + "timerfd_settime": C.__NR_timerfd_settime, + "timerfd_gettime": C.__NR_timerfd_gettime, + "signalfd4": C.__NR_signalfd4, + "eventfd2": C.__NR_eventfd2, + "epoll_create1": C.__NR_epoll_create1, + "dup3": C.__NR_dup3, + "pipe2": C.__NR_pipe2, + "inotify_init1": C.__NR_inotify_init1, + "preadv": C.__NR_preadv, + "pwritev": C.__NR_pwritev, + "rt_tgsigqueueinfo": C.__NR_rt_tgsigqueueinfo, + "perf_event_open": C.__NR_perf_event_open, + "recvmmsg": C.__NR_recvmmsg, + "accept4": C.__NR_accept4, + "fanotify_init": C.__NR_fanotify_init, + "fanotify_mark": C.__NR_fanotify_mark, + "prlimit64": C.__NR_prlimit64, + "name_to_handle_at": C.__NR_name_to_handle_at, + "open_by_handle_at": C.__NR_open_by_handle_at, + "clock_adjtime": C.__NR_clock_adjtime, + "syncfs": C.__NR_syncfs, + "sendmmsg": C.__NR_sendmmsg, + "setns": C.__NR_setns, + "process_vm_readv": C.__NR_process_vm_readv, + "process_vm_writev": C.__NR_process_vm_writev, + "kcmp": C.__NR_kcmp, + "finit_module": C.__NR_finit_module, + "sched_setattr": C.__NR_sched_setattr, + "sched_getattr": C.__NR_sched_getattr, + "renameat2": C.__NR_renameat2, + "seccomp": C.__NR_seccomp, + "getrandom": C.__NR_getrandom, + "memfd_create": C.__NR_memfd_create, + "bpf": C.__NR_bpf, + "execveat": C.__NR_execveat, + "ARM_breakpoint": C.__ARM_NR_breakpoint, + "ARM_cacheflush": C.__ARM_NR_cacheflush, + "ARM_usr26": C.__ARM_NR_usr26, + "ARM_usr32": C.__ARM_NR_usr32, + "ARM_set_tls": C.__ARM_NR_set_tls, +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_gen.go b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_gen.go new file mode 100644 index 0000000..d75f552 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/syscalls_gen.go @@ -0,0 +1,61 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build ignore + +// syscalls_gen processes system headers and generates a mapping from system call names to numbers. +// Usage: +// $ echo "#include \"unistd_64.h\"" | x86_64-cros-linux-gnu-gcc -E -dD - | go run syscalls_gen.go | gofmt > syscalls_amd64.go +// $ echo "#include \"unistd_64.h\"" | i686-pc-linux-gnu-gcc -E -dD - | go run syscalls_gen.go | gofmt > syscalls_386.go +// $ echo "#include " | armv7a-cros-linux-gnueabi-gcc -E -dD - | go run syscalls_gen.go | gofmt > syscalls_arm.go +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" +) + +func main() { + type syscall struct { + prefix string + name string + } + + define := regexp.MustCompile(`^#define __([A-Z]+_)?NR_([a-z0-9_]+)`) + undef := regexp.MustCompile(`^#undef __([A-Z]+_)?NR_([a-z0-9_]+)`) + + defined := []syscall{} + undefed := map[syscall]bool{} + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := scanner.Text() + if match := define.FindStringSubmatch(line); match != nil { + defined = append(defined, syscall{match[1], match[2]}) + } + if match := undef.FindStringSubmatch(line); match != nil { + undefed[syscall{match[1], match[2]}] = true + } + } + if err := scanner.Err(); err != nil { + log.Fatalf("Error reading standard input: %v", err) + } + + fmt.Println("// DO NOT EDIT. Autogenerated by syscalls_gen.go") + fmt.Println() + fmt.Println("package seccomp") + fmt.Println("// #include ") + fmt.Println("import \"C\"") + fmt.Println("// syscallNum maps system call names to numbers.") + fmt.Println("var syscallNum = map[string]int{") + for _, call := range defined { + if !undefed[call] { + fmt.Printf("%q: C.__%sNR_%s,\n", call.prefix+call.name, call.prefix, call.name) + } + } + fmt.Println("}") +} diff --git a/Godeps/_workspace/src/github.com/subgraph/go-seccomp/unistd_64.h b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/unistd_64.h new file mode 100644 index 0000000..0ffa105 --- /dev/null +++ b/Godeps/_workspace/src/github.com/subgraph/go-seccomp/unistd_64.h @@ -0,0 +1,325 @@ + +#define __NR_read 0 +#define __NR_write 1 +#define __NR_open 2 +#define __NR_close 3 +#define __NR_stat 4 +#define __NR_fstat 5 +#define __NR_lstat 6 +#define __NR_poll 7 +#define __NR_lseek 8 +#define __NR_mmap 9 +#define __NR_mprotect 10 +#define __NR_munmap 11 +#define __NR_brk 12 +#define __NR_rt_sigaction 13 +#define __NR_rt_sigprocmask 14 +#define __NR_rt_sigreturn 15 +#define __NR_ioctl 16 +#define __NR_pread64 17 +#define __NR_pwrite64 18 +#define __NR_readv 19 +#define __NR_writev 20 +#define __NR_access 21 +#define __NR_pipe 22 +#define __NR_select 23 +#define __NR_sched_yield 24 +#define __NR_mremap 25 +#define __NR_msync 26 +#define __NR_mincore 27 +#define __NR_madvise 28 +#define __NR_shmget 29 +#define __NR_shmat 30 +#define __NR_shmctl 31 +#define __NR_dup 32 +#define __NR_dup2 33 +#define __NR_pause 34 +#define __NR_nanosleep 35 +#define __NR_getitimer 36 +#define __NR_alarm 37 +#define __NR_setitimer 38 +#define __NR_getpid 39 +#define __NR_sendfile 40 +#define __NR_socket 41 +#define __NR_connect 42 +#define __NR_accept 43 +#define __NR_sendto 44 +#define __NR_recvfrom 45 +#define __NR_sendmsg 46 +#define __NR_recvmsg 47 +#define __NR_shutdown 48 +#define __NR_bind 49 +#define __NR_listen 50 +#define __NR_getsockname 51 +#define __NR_getpeername 52 +#define __NR_socketpair 53 +#define __NR_setsockopt 54 +#define __NR_getsockopt 55 +#define __NR_clone 56 +#define __NR_fork 57 +#define __NR_vfork 58 +#define __NR_execve 59 +#define __NR_exit 60 +#define __NR_wait4 61 +#define __NR_kill 62 +#define __NR_uname 63 +#define __NR_semget 64 +#define __NR_semop 65 +#define __NR_semctl 66 +#define __NR_shmdt 67 +#define __NR_msgget 68 +#define __NR_msgsnd 69 +#define __NR_msgrcv 70 +#define __NR_msgctl 71 +#define __NR_fcntl 72 +#define __NR_flock 73 +#define __NR_fsync 74 +#define __NR_fdatasync 75 +#define __NR_truncate 76 +#define __NR_ftruncate 77 +#define __NR_getdents 78 +#define __NR_getcwd 79 +#define __NR_chdir 80 +#define __NR_fchdir 81 +#define __NR_rename 82 +#define __NR_mkdir 83 +#define __NR_rmdir 84 +#define __NR_creat 85 +#define __NR_link 86 +#define __NR_unlink 87 +#define __NR_symlink 88 +#define __NR_readlink 89 +#define __NR_chmod 90 +#define __NR_fchmod 91 +#define __NR_chown 92 +#define __NR_fchown 93 +#define __NR_lchown 94 +#define __NR_umask 95 +#define __NR_gettimeofday 96 +#define __NR_getrlimit 97 +#define __NR_getrusage 98 +#define __NR_sysinfo 99 +#define __NR_times 100 +#define __NR_ptrace 101 +#define __NR_getuid 102 +#define __NR_syslog 103 +#define __NR_getgid 104 +#define __NR_setuid 105 +#define __NR_setgid 106 +#define __NR_geteuid 107 +#define __NR_getegid 108 +#define __NR_setpgid 109 +#define __NR_getppid 110 +#define __NR_getpgrp 111 +#define __NR_setsid 112 +#define __NR_setreuid 113 +#define __NR_setregid 114 +#define __NR_getgroups 115 +#define __NR_setgroups 116 +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#define __NR_getpgid 121 +#define __NR_setfsuid 122 +#define __NR_setfsgid 123 +#define __NR_getsid 124 +#define __NR_capget 125 +#define __NR_capset 126 +#define __NR_rt_sigpending 127 +#define __NR_rt_sigtimedwait 128 +#define __NR_rt_sigqueueinfo 129 +#define __NR_rt_sigsuspend 130 +#define __NR_sigaltstack 131 +#define __NR_utime 132 +#define __NR_mknod 133 +#define __NR_uselib 134 +#define __NR_personality 135 +#define __NR_ustat 136 +#define __NR_statfs 137 +#define __NR_fstatfs 138 +#define __NR_sysfs 139 +#define __NR_getpriority 140 +#define __NR_setpriority 141 +#define __NR_sched_setparam 142 +#define __NR_sched_getparam 143 +#define __NR_sched_setscheduler 144 +#define __NR_sched_getscheduler 145 +#define __NR_sched_get_priority_max 146 +#define __NR_sched_get_priority_min 147 +#define __NR_sched_rr_get_interval 148 +#define __NR_mlock 149 +#define __NR_munlock 150 +#define __NR_mlockall 151 +#define __NR_munlockall 152 +#define __NR_vhangup 153 +#define __NR_modify_ldt 154 +#define __NR_pivot_root 155 +#define __NR__sysctl 156 +#define __NR_prctl 157 +#define __NR_arch_prctl 158 +#define __NR_adjtimex 159 +#define __NR_setrlimit 160 +#define __NR_chroot 161 +#define __NR_sync 162 +#define __NR_acct 163 +#define __NR_settimeofday 164 +#define __NR_mount 165 +#define __NR_umount2 166 +#define __NR_swapon 167 +#define __NR_swapoff 168 +#define __NR_reboot 169 +#define __NR_sethostname 170 +#define __NR_setdomainname 171 +#define __NR_iopl 172 +#define __NR_ioperm 173 +#define __NR_create_module 174 +#define __NR_init_module 175 +#define __NR_delete_module 176 +#define __NR_get_kernel_syms 177 +#define __NR_query_module 178 +#define __NR_quotactl 179 +#define __NR_nfsservctl 180 +#define __NR_getpmsg 181 +#define __NR_putpmsg 182 +#define __NR_afs_syscall 183 +#define __NR_tuxcall 184 +#define __NR_security 185 +#define __NR_gettid 186 +#define __NR_readahead 187 +#define __NR_setxattr 188 +#define __NR_lsetxattr 189 +#define __NR_fsetxattr 190 +#define __NR_getxattr 191 +#define __NR_lgetxattr 192 +#define __NR_fgetxattr 193 +#define __NR_listxattr 194 +#define __NR_llistxattr 195 +#define __NR_flistxattr 196 +#define __NR_removexattr 197 +#define __NR_lremovexattr 198 +#define __NR_fremovexattr 199 +#define __NR_tkill 200 +#define __NR_time 201 +#define __NR_futex 202 +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#define __NR_set_thread_area 205 +#define __NR_io_setup 206 +#define __NR_io_destroy 207 +#define __NR_io_getevents 208 +#define __NR_io_submit 209 +#define __NR_io_cancel 210 +#define __NR_get_thread_area 211 +#define __NR_lookup_dcookie 212 +#define __NR_epoll_create 213 +#define __NR_epoll_ctl_old 214 +#define __NR_epoll_wait_old 215 +#define __NR_remap_file_pages 216 +#define __NR_getdents64 217 +#define __NR_set_tid_address 218 +#define __NR_restart_syscall 219 +#define __NR_semtimedop 220 +#define __NR_fadvise64 221 +#define __NR_timer_create 222 +#define __NR_timer_settime 223 +#define __NR_timer_gettime 224 +#define __NR_timer_getoverrun 225 +#define __NR_timer_delete 226 +#define __NR_clock_settime 227 +#define __NR_clock_gettime 228 +#define __NR_clock_getres 229 +#define __NR_clock_nanosleep 230 +#define __NR_exit_group 231 +#define __NR_epoll_wait 232 +#define __NR_epoll_ctl 233 +#define __NR_tgkill 234 +#define __NR_utimes 235 +#define __NR_vserver 236 +#define __NR_mbind 237 +#define __NR_set_mempolicy 238 +#define __NR_get_mempolicy 239 +#define __NR_mq_open 240 +#define __NR_mq_unlink 241 +#define __NR_mq_timedsend 242 +#define __NR_mq_timedreceive 243 +#define __NR_mq_notify 244 +#define __NR_mq_getsetattr 245 +#define __NR_kexec_load 246 +#define __NR_waitid 247 +#define __NR_add_key 248 +#define __NR_request_key 249 +#define __NR_keyctl 250 +#define __NR_ioprio_set 251 +#define __NR_ioprio_get 252 +#define __NR_inotify_init 253 +#define __NR_inotify_add_watch 254 +#define __NR_inotify_rm_watch 255 +#define __NR_migrate_pages 256 +#define __NR_openat 257 +#define __NR_mkdirat 258 +#define __NR_mknodat 259 +#define __NR_fchownat 260 +#define __NR_futimesat 261 +#define __NR_newfstatat 262 +#define __NR_unlinkat 263 +#define __NR_renameat 264 +#define __NR_linkat 265 +#define __NR_symlinkat 266 +#define __NR_readlinkat 267 +#define __NR_fchmodat 268 +#define __NR_faccessat 269 +#define __NR_pselect6 270 +#define __NR_ppoll 271 +#define __NR_unshare 272 +#define __NR_set_robust_list 273 +#define __NR_get_robust_list 274 +#define __NR_splice 275 +#define __NR_tee 276 +#define __NR_sync_file_range 277 +#define __NR_vmsplice 278 +#define __NR_move_pages 279 +#define __NR_utimensat 280 +#define __NR_epoll_pwait 281 +#define __NR_signalfd 282 +#define __NR_timerfd_create 283 +#define __NR_eventfd 284 +#define __NR_fallocate 285 +#define __NR_timerfd_settime 286 +#define __NR_timerfd_gettime 287 +#define __NR_accept4 288 +#define __NR_signalfd4 289 +#define __NR_eventfd2 290 +#define __NR_epoll_create1 291 +#define __NR_dup3 292 +#define __NR_pipe2 293 +#define __NR_inotify_init1 294 +#define __NR_preadv 295 +#define __NR_pwritev 296 +#define __NR_rt_tgsigqueueinfo 297 +#define __NR_perf_event_open 298 +#define __NR_recvmmsg 299 +#define __NR_fanotify_init 300 +#define __NR_fanotify_mark 301 +#define __NR_prlimit64 302 +#define __NR_name_to_handle_at 303 +#define __NR_open_by_handle_at 304 +#define __NR_clock_adjtime 305 +#define __NR_syncfs 306 +#define __NR_sendmmsg 307 +#define __NR_setns 308 +#define __NR_getcpu 309 +#define __NR_process_vm_readv 310 +#define __NR_process_vm_writev 311 +#define __NR_kcmp 312 +#define __NR_finit_module 313 +#define __NR_sched_setattr 314 +#define __NR_sched_getattr 315 +#define __NR_renameat2 316 +#define __NR_seccomp 317 +#define __NR_getrandom 318 +#define __NR_memfd_create 319 +#define __NR_kexec_file_load 320 +#define __NR_bpf 321 +#define __NR_execveat 322 + diff --git a/config.go b/config.go index 1bf14eb..2b195e7 100644 --- a/config.go +++ b/config.go @@ -2,11 +2,8 @@ package oz import ( "encoding/json" - "fmt" "io/ioutil" "os" - "path" - "syscall" ) type Config struct { @@ -21,6 +18,7 @@ type Config struct { AllowRootShell bool `json:"allow_root_shell" desc:"Allow entering a sandbox shell as root"` LogXpra bool `json:"log_xpra" desc:"Log output of Xpra"` EnvironmentVars []string `json:"environment_vars" desc:"Default environment variables passed to sandboxes"` + DefaultGroups []string `json:"default_groups" desc:"List of default group names that can be used inside the sandbox"` } const OzVersion = "0.0.1" @@ -28,19 +26,22 @@ const DefaultConfigPath = "/etc/oz/oz.conf" func NewDefaultConfig() *Config { return &Config{ - ProfileDir: "/var/lib/oz/cells.d", - ShellPath: "/bin/bash", - PrefixPath: "/usr/local", - SandboxPath: "/srv/oz", - NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf", - BridgeMACAddr: "6A:A8:2E:56:E8:9C", - DivertSuffix: "unsafe", - UseFullDev: false, - AllowRootShell: false, - LogXpra: false, + ProfileDir: "/var/lib/oz/cells.d", + ShellPath: "/bin/bash", + PrefixPath: "/usr/local", + SandboxPath: "/srv/oz", + NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf", + BridgeMACAddr: "6A:A8:2E:56:E8:9C", + DivertSuffix: "unsafe", + UseFullDev: false, + AllowRootShell: false, + LogXpra: false, EnvironmentVars: []string{ "USER", "USERNAME", "LOGNAME", - "LANG", "LANGUAGE", "_", + "LANG", "LANGUAGE", "_", "TZ=UTC", + }, + DefaultGroups: []string{ + "audio", "video", }, } } @@ -63,27 +64,3 @@ func LoadConfig(cpath string) (*Config, error) { } return c, nil } - -func checkConfigPermissions(fpath string) error { - pd := path.Dir(fpath) - for _, fp := range []string{pd, fpath} { - if err := checkPathRootPermissions(fp); err != nil { - return fmt.Errorf("file (%s) is %s", fp, err) - } - } - return nil -} - -func checkPathRootPermissions(fpath string) error { - fstat, err := os.Stat(fpath) - if err != nil { - return err - } - if (fstat.Mode().Perm() & syscall.S_IWOTH) != 0 { - return fmt.Errorf("writable by everyone!", fpath) - } - if (fstat.Mode().Perm()&syscall.S_IWGRP) != 0 && fstat.Sys().(*syscall.Stat_t).Gid != 0 { - return fmt.Errorf("writable by someone else than root!", err) - } - return nil -} diff --git a/fs/fs.go b/fs/fs.go index fbf73a6..5e14eab 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -162,7 +162,7 @@ func (fs *Filesystem) bind(from string, to string, flags int, u *user.User) erro return bindMount(src, to, mntflags) } -func (fs *Filesystem) UnbindPath(to string) (error) { +func (fs *Filesystem) UnbindPath(to string) error { to = path.Join(fs.Root(), to) _, err := os.Stat(to) @@ -173,7 +173,7 @@ func (fs *Filesystem) UnbindPath(to string) (error) { // XXX fs.log.Info("unbinding %s", to) - if err := syscall.Unmount(to, syscall.MNT_DETACH/* | syscall.MNT_FORCE*/); err != nil { + if err := syscall.Unmount(to, syscall.MNT_DETACH /* | syscall.MNT_FORCE*/); err != nil { return err } diff --git a/fs/resolve.go b/fs/resolve.go index 3d628a7..e35ff19 100644 --- a/fs/resolve.go +++ b/fs/resolve.go @@ -2,12 +2,12 @@ package fs import ( "fmt" + "os" "os/exec" "os/user" "path" "path/filepath" "strings" - "os" ) func resolvePath(p string, u *user.User) ([]string, error) { diff --git a/network/daemon.go b/network/daemon.go index 9802103..074417f 100644 --- a/network/daemon.go +++ b/network/daemon.go @@ -13,9 +13,9 @@ import ( //Internal //External - "github.com/op/go-logging" "github.com/j-keck/arping" "github.com/milosgajdos83/tenus" + "github.com/op/go-logging" ) func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*HostNetwork, error) { @@ -100,13 +100,13 @@ func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.L rand.Seed(time.Now().Unix() ^ int64((os.Getpid() + childPid))) log.Info("Configuring host veth pair '%s' with: %s", stn.VethHost, stn.Ip+"/"+htn.Class) -/* - // Fetch the bridge from the ifname - br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge) - if err != nil { - return fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err) - } -*/ + /* + // Fetch the bridge from the ifname + br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge) + if err != nil { + return fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err) + } + */ // Make sure the bridge is configured and the link is up // This really shouldn't be needed, but Network-Manager is a PITA // and even if you actualy ignore the interface there's a race diff --git a/network/network.go b/network/network.go index f5914bb..f85e03c 100644 --- a/network/network.go +++ b/network/network.go @@ -7,8 +7,8 @@ import ( "strconv" "strings" - "github.com/op/go-logging" "github.com/milosgajdos83/tenus" + "github.com/op/go-logging" ) const ( @@ -21,9 +21,9 @@ const ( type NetType string -const( - TYPE_HOST NetType = "host" - TYPE_EMPTY NetType = "empty" +const ( + TYPE_HOST NetType = "host" + TYPE_EMPTY NetType = "empty" TYPE_BRIDGE NetType = "bridge" ) diff --git a/network/proxy.go b/network/proxy.go index 77fa55f..799482c 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -1,6 +1,6 @@ package network -import( +import ( //Builtin "fmt" "io" @@ -16,16 +16,16 @@ import( type ProxyType string -const( +const ( PROXY_CLIENT ProxyType = "client" PROXY_SERVER ProxyType = "server" ) type ProtoType string -const( - PROTO_TCP ProtoType = "tcp" - PROTO_UDP ProtoType = "udp" +const ( + PROTO_TCP ProtoType = "tcp" + PROTO_UDP ProtoType = "udp" PROTO_SOCKET ProtoType = "socket" ) @@ -146,7 +146,7 @@ func nsSocketListener(fd uintptr, proto ProtoType, lAddr string) (net.Listener, /** * Connect/Server **/ -func proxyServerConn(pid int, conn *net.Conn, proto ProtoType, rAddr string, log *logging.Logger, ready sync.WaitGroup) (error) { +func proxyServerConn(pid int, conn *net.Conn, proto ProtoType, rAddr string, log *logging.Logger, ready sync.WaitGroup) error { rConn, err := socketConnect(pid, proto, rAddr) if err != nil { log.Error("Socket: %+v.", err) @@ -159,7 +159,7 @@ func proxyServerConn(pid int, conn *net.Conn, proto ProtoType, rAddr string, log return nil } -func newProxyServer(pid int, proto ProtoType, dest string, port int, log *logging.Logger, ready sync.WaitGroup) (error) { +func newProxyServer(pid int, proto ProtoType, dest string, port int, log *logging.Logger, ready sync.WaitGroup) error { if dest == "" { dest = "127.0.0.1" } diff --git a/oz-daemon/client.go b/oz-daemon/client.go index 393cc10..977c6b9 100644 --- a/oz-daemon/client.go +++ b/oz-daemon/client.go @@ -53,20 +53,28 @@ func ListSandboxes() ([]SandboxInfo, error) { return body.Sandboxes, nil } -func Launch(arg, cpath string, args, env []string, noexec bool) error { +func Launch(arg, cpath string, args []string, noexec bool) error { idx, name, err := parseProfileArg(arg) if err != nil { return err } pwd, _ := os.Getwd() - + groups, _ := os.Getgroups() + gg := []uint32{} + if len(groups) > 0 { + gg = make([]uint32, len(groups)) + for i, v := range groups { + gg[i] = uint32(v) + } + } resp, err := clientSend(&LaunchMsg{ Index: idx, Name: name, Path: cpath, Pwd: pwd, + Gids: gg, Args: args, - Env: env, + Env: os.Environ(), Noexec: noexec, }) if err != nil { @@ -102,7 +110,7 @@ func KillSandbox(id int) error { } } -func MountFiles(files []string) (error) { +func MountFiles(files []string) error { resp, err := clientSend(&MountFilesMsg{Files: files}) if err != nil { return err @@ -117,7 +125,7 @@ func MountFiles(files []string) (error) { } } -func UnmountFile(file string) (error) { +func UnmountFile(file string) error { resp, err := clientSend(&UnmountFileMsg{File: file}) if err != nil { return err diff --git a/oz-daemon/daemon.go b/oz-daemon/daemon.go index 96a12ee..ca9783e 100644 --- a/oz-daemon/daemon.go +++ b/oz-daemon/daemon.go @@ -1,11 +1,13 @@ package daemon import ( + "bufio" "encoding/json" "fmt" "os" "os/signal" "path" + "strconv" "strings" "syscall" @@ -16,16 +18,23 @@ import ( "github.com/op/go-logging" ) +type groupEntry struct { + Name string + Gid uint32 + Members []string +} + type daemonState struct { - log *logging.Logger - config *oz.Config - profiles oz.Profiles - sandboxes []*Sandbox - nextSboxId int - nextDisplay int - memBackend *logging.ChannelMemoryBackend - backends []logging.Backend - network *network.HostNetwork + log *logging.Logger + config *oz.Config + profiles oz.Profiles + sandboxes []*Sandbox + nextSboxId int + nextDisplay int + memBackend *logging.ChannelMemoryBackend + backends []logging.Backend + network *network.HostNetwork + systemGroups map[string]groupEntry } func Main() { @@ -66,6 +75,9 @@ func initialize() *daemonState { os.Exit(1) } d.profiles = ps + if err := d.cacheSystemGroups(); err != nil { + d.log.Fatalf("Unable to cache list of system groups: %v", err) + } oz.ReapChildProcs(d.log, d.handleChildExit) d.nextSboxId = 1 d.nextDisplay = 100 @@ -80,9 +92,7 @@ func initialize() *daemonState { } d.network = htn - //network.NetPrint(d.log) - break } } @@ -140,6 +150,39 @@ func (d *daemonState) processSignals(c <-chan os.Signal) { } } +func (d *daemonState) cacheSystemGroups() error { + fg, err := os.Open("/etc/group") + if err != nil { + return err + } + defer fg.Close() + + sg := bufio.NewScanner(fg) + newGroups := make(map[string]groupEntry) + for sg.Scan() { + gd := strings.Split(sg.Text(), ":") + if len(gd) < 4 { + continue + } + gid, err := strconv.ParseUint(gd[2], 10, 32) + if err != nil { + continue + } + newGroups[gd[0]] = groupEntry{ + Name: gd[0], + Gid: uint32(gid), + Members: strings.Split(gd[3], ","), + } + } + + if err := sg.Err(); err != nil { + return err + } + d.systemGroups = newGroups + return nil +} + + func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) { d.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus()) @@ -217,6 +260,10 @@ func (d *daemonState) sanitizeEnvironment(p *oz.Profile, oldEnv []string) []stri newEnv := []string{} for _, EnvItem := range d.config.EnvironmentVars { + if strings.Contains(EnvItem, "=") { + newEnv = append(newEnv, EnvItem) + continue + } for _, OldItem := range oldEnv { if strings.HasPrefix(OldItem, EnvItem+"=") { newEnv = append(newEnv, EnvItem+"="+strings.Replace(OldItem, EnvItem+"=", "", 1)) @@ -281,7 +328,6 @@ func (d *daemonState) handleMountFiles(msg *MountFilesMsg, m *ipc.Message) error return m.Respond(&OkMsg{}) } - func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) error { sbox := d.sandboxById(msg.Id) if sbox == nil { @@ -293,8 +339,6 @@ func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) err return m.Respond(&OkMsg{}) } - - func (d *daemonState) sandboxById(id int) *Sandbox { for _, sb := range d.sandboxes { if sb.id == id { diff --git a/oz-daemon/launch.go b/oz-daemon/launch.go index fb7c81c..7b5c08e 100644 --- a/oz-daemon/launch.go +++ b/oz-daemon/launch.go @@ -2,8 +2,10 @@ package daemon import ( "bufio" + "bytes" "crypto/rand" "encoding/hex" + "encoding/json" "fmt" "io" "os" @@ -52,7 +54,7 @@ func createSocketPath(base string) (string, error) { return path.Join(base, fmt.Sprintf("oz-init-control-%s", hex.EncodeToString(bs))), nil } -func createInitCommand(initPath, name string, socketPath string, env []string, uid uint32, display int, stn *network.SandboxNetwork) *exec.Cmd { +func createInitCommand(initPath string, cloneNet bool) *exec.Cmd { cmd := exec.Command(initPath) cmd.Dir = "/" @@ -61,7 +63,7 @@ func createInitCommand(initPath, name string, socketPath string, env []string, u cloneFlags |= syscall.CLONE_NEWPID cloneFlags |= syscall.CLONE_NEWUTS - if stn.Nettype != network.TYPE_HOST { + if cloneNet { cloneFlags |= syscall.CLONE_NEWNET } @@ -69,25 +71,7 @@ func createInitCommand(initPath, name string, socketPath string, env []string, u //Chroot: chroot, Cloneflags: cloneFlags, } - cmd.Env = []string{ - "INIT_PROFILE=" + name, - "INIT_SOCKET=" + socketPath, - fmt.Sprintf("INIT_UID=%d", uid), - } - - if stn.Ip != "" { - cmd.Env = append(cmd.Env, "INIT_ADDR="+stn.Ip) - cmd.Env = append(cmd.Env, "INIT_VHOST="+stn.VethHost) - cmd.Env = append(cmd.Env, "INIT_VGUEST="+stn.VethGuest) - cmd.Env = append(cmd.Env, "INIT_GATEWAY="+stn.Gateway.String()+"/"+stn.Class) - } - - cmd.Env = append(cmd.Env, fmt.Sprintf("INIT_DISPLAY=%d", display)) - - for _, e := range env { - cmd.Env = append(cmd.Env, ozinit.EnvPrefix+e) - } - + return cmd } @@ -107,8 +91,11 @@ func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, uid, gid uint32, log */ u, err := user.LookupId(strconv.FormatUint(uint64(uid), 10)) if err != nil { - log.Error("Failed to look up user with uid=%ld: %v", uid, err) - os.Exit(1) + return nil, fmt.Errorf("Failed to look up user with uid=%ld: %v", uid, err) + } + groups, err := d.sanitizeGroups(p, u.Username, msg.Gids) + if err != nil { + return nil, fmt.Errorf("Unable to sanitize user groups: %v", err) } display := 0 @@ -131,20 +118,40 @@ func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, uid, gid uint32, log return nil, fmt.Errorf("Failed to create random socket path: %v", err) } initPath := path.Join(d.config.PrefixPath, "bin", "oz-init") - cmd := createInitCommand(initPath, p.Name, socketPath, msg.Env, uid, display, stn) - log.Debug("Command environment: %+v", cmd.Env) + cmd := createInitCommand(initPath, (stn.Nettype != network.TYPE_HOST)) pp, err := cmd.StderrPipe() if err != nil { //fs.Cleanup() return nil, fmt.Errorf("error creating stderr pipe for init process: %v", err) - } + pi, err := cmd.StdinPipe() + if err != nil { + //fs.Cleanup() + return nil, fmt.Errorf("error creating stdin pipe for init process: %v", err) + } + + jdata, err := json.Marshal(ozinit.InitData{ + Display: display, + User: *u, + Uid: uid, + Gid: gid, + Gids: groups, + Network: *stn, + Profile: *p, + Config: *d.config, + Sockaddr: socketPath, + LaunchEnv: msg.Env, + }) + if err != nil { + return nil, fmt.Errorf("Unable to marshal init state: %+v", err) + } + io.Copy(pi, bytes.NewBuffer(jdata)) + pi.Close() if err := cmd.Start(); err != nil { //fs.Cleanup() return nil, fmt.Errorf("Unable to start process: %+v", err) } - //rootfs := path.Join(d.config.SandboxPath, "rootfs") sbox := &Sandbox{ daemon: d, @@ -152,7 +159,7 @@ func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, uid, gid uint32, log display: display, profile: p, init: cmd, - cred: &syscall.Credential{Uid: uid, Gid: gid}, + cred: &syscall.Credential{Uid: uid, Gid: gid, Groups: msg.Gids}, user: u, fs: fs.NewFilesystem(d.config, log), //addr: path.Join(rootfs, ozinit.SocketAddress), @@ -205,6 +212,38 @@ func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, uid, gid uint32, log return sbox, nil } +func (d *daemonState) sanitizeGroups(p *oz.Profile, username string, gids []uint32) (map[string]uint32, error) { + allowedGroups := d.config.DefaultGroups + allowedGroups = append(allowedGroups, p.AllowedGroups...) + if len(d.systemGroups) == 0 { + if err := d.cacheSystemGroups(); err != nil { + return nil, err + } + } + groups := map[string]uint32{} + for _, sg := range d.systemGroups { + for _, gg := range allowedGroups { + if sg.Name == gg { + found := false + for _, uname := range sg.Members { + if uname == username { + found = true + break + } + } + if !found { + continue + } + d.log.Debug("Allowing user: %s (%d)", gg, sg.Gid) + groups[sg.Name] = sg.Gid + break + } + } + } + + return groups, nil +} + func (sbox *Sandbox) launchProgram(binpath, cpath, pwd string, args []string, log *logging.Logger) { if sbox.profile.AllowFiles { sbox.whitelistArgumentFiles(binpath, pwd, args, log) @@ -215,7 +254,7 @@ func (sbox *Sandbox) launchProgram(binpath, cpath, pwd string, args []string, lo } } -func (sbox *Sandbox) MountFiles(files []string, readonly bool, binpath string, log *logging.Logger) error { +func (sbox *Sandbox) MountFiles(files []string, readonly bool, binpath string, log *logging.Logger) error { pmnt := path.Join(binpath, "bin", "oz-mount") args := files if readonly { @@ -235,12 +274,12 @@ func (sbox *Sandbox) MountFiles(files []string, readonly bool, binpath string, for _, mfile := range files { found := false for _, mmfile := range sbox.mountedFiles { - if (mfile == mmfile) { + if mfile == mmfile { found = true - break; + break } } - if (!found) { + if !found { sbox.mountedFiles = append(sbox.mountedFiles, mfile) } } @@ -284,7 +323,7 @@ func (sbox *Sandbox) whitelistArgumentFiles(binpath, pwd string, args []string, } } if len(files) > 0 { - sbox.MountFiles(files, false, binpath, log); + sbox.MountFiles(files, false, binpath, log) } } diff --git a/oz-daemon/protocol.go b/oz-daemon/protocol.go index d76fd79..85e6d45 100644 --- a/oz-daemon/protocol.go +++ b/oz-daemon/protocol.go @@ -39,6 +39,7 @@ type LaunchMsg struct { Path string Name string Pwd string + Gids []uint32 Args []string Env []string Noexec bool @@ -64,13 +65,13 @@ type KillSandboxMsg struct { } type MountFilesMsg struct { - Id int "MountFiles" - Files []string + Id int "MountFiles" + Files []string ReadOnly bool } type UnmountFileMsg struct { - Id int "UnmountFile" + Id int "UnmountFile" File string } diff --git a/oz-init/init.go b/oz-init/init.go index 775b592..0457eca 100644 --- a/oz-init/init.go +++ b/oz-init/init.go @@ -2,10 +2,10 @@ package ozinit import ( "bufio" + "encoding/json" "fmt" "io" "io/ioutil" - "net" "os" "os/exec" "os/signal" @@ -26,8 +26,6 @@ import ( "github.com/op/go-logging" ) -const EnvPrefix = "INIT_ENV_" - type initState struct { log *logging.Logger profile *oz.Profile @@ -36,8 +34,9 @@ type initState struct { launchEnv []string lock sync.Mutex children map[int]*exec.Cmd - uid int - gid int + uid uint32 + gid uint32 + gids map[string]uint32 user *user.User display int fs *fs.Filesystem @@ -47,6 +46,19 @@ type initState struct { network *network.SandboxNetwork } +type InitData struct { + Profile oz.Profile + Config oz.Config + Sockaddr string + LaunchEnv []string + Uid uint32 + Gid uint32 + Gids map[string]uint32 + User user.User + Network network.SandboxNetwork + Display int +} + // By convention oz-init writes log messages to stderr with a single character // prefix indicating the logging level. These messages are read one line at a time // over a pipe by oz-daemon and translated into appropriate log events. @@ -76,108 +88,40 @@ func parseArgs() *initState { os.Exit(1) } - getvar := func(name string) string { - val := os.Getenv(name) - if val == "" { - log.Error("Error: missing required '%s' argument", name) - os.Exit(1) - } - return val - } - pname := getvar("INIT_PROFILE") - sockaddr := getvar("INIT_SOCKET") - uidval := getvar("INIT_UID") - dispval := os.Getenv("INIT_DISPLAY") - - stnip := os.Getenv("INIT_ADDR") - stnvhost := os.Getenv("INIT_VHOST") - stnvguest := os.Getenv("INIT_VGUEST") - stngateway := os.Getenv("INIT_GATEWAY") - - var config *oz.Config - config, err := oz.LoadConfig(oz.DefaultConfigPath) - if err != nil { - if os.IsNotExist(err) { - log.Info("Configuration file (%s) is missing, using defaults.", oz.DefaultConfigPath) - config = oz.NewDefaultConfig() - } else { - log.Error("Could not load configuration: %s", oz.DefaultConfigPath, err) - os.Exit(1) - } - } - - p, err := loadProfile(config.ProfileDir, pname) - if err != nil { - log.Error("Could not load profile %s: %v", pname, err) - os.Exit(1) - } - uid, err := strconv.Atoi(uidval) - if err != nil { - log.Error("Could not parse INIT_UID argument (%s) into an integer: %v", uidval, err) - os.Exit(1) - } - u, err := user.LookupId(uidval) - if err != nil { - log.Error("Failed to look up user with uid=%s: %v", uidval, err) - os.Exit(1) - } - gid, err := strconv.Atoi(u.Gid) - if err != nil { - log.Error("Failed to parse gid value (%s) from user struct: %v", u.Gid, err) + initData := new(InitData) + if err := json.NewDecoder(os.Stdin).Decode(&initData); err != nil { + log.Error("unable to decode init data: %v", err) os.Exit(1) } - display := 0 - if dispval != "" { - d, err := strconv.Atoi(dispval) - if err != nil { - log.Error("Unable to parse display (%s) into an integer: %v", dispval, err) - os.Exit(1) - } - display = d - } - - stn := new(network.SandboxNetwork) - if stnip != "" { - gateway, _, err := net.ParseCIDR(stngateway) - if err != nil { - log.Error("Unable to parse network configuration gateway (%s): %v", stngateway, err) - os.Exit(1) - } + log.Debug("Init state: %+v", initData) - stn.Ip = stnip - stn.VethHost = stnvhost - stn.VethGuest = stnvguest - stn.Gateway = gateway + if (initData.User.Uid != strconv.Itoa(int(initData.Uid))) || (initData.Uid == 0) { + log.Error("invalid uid or user passed to init.") + os.Exit(1) } env := []string{} - for _, e := range os.Environ() { - if strings.HasPrefix(e, EnvPrefix) { - e = e[len(EnvPrefix):] - log.Debug("Adding (%s) to launch environment", e) - env = append(env, e) - } - } - + env = append(env, initData.LaunchEnv...) env = append(env, "PATH=/usr/bin:/bin") - if p.XServer.Enabled { - env = append(env, "DISPLAY=:"+strconv.Itoa(display)) + if initData.Profile.XServer.Enabled { + env = append(env, "DISPLAY=:"+strconv.Itoa(initData.Display)) } return &initState{ log: log, - config: config, - sockaddr: sockaddr, + config: &initData.Config, + sockaddr: initData.Sockaddr, launchEnv: env, - profile: p, + profile: &initData.Profile, children: make(map[int]*exec.Cmd), - uid: uid, - gid: gid, - user: u, - display: display, - fs: fs.NewFilesystem(config, log), - network: stn, + uid: initData.Uid, + gid: initData.Gid, + gids: initData.Gids, + user: &initData.User, + display: initData.Display, + fs: fs.NewFilesystem(&initData.Config, log), + network: &initData.Network, } } @@ -196,7 +140,7 @@ func (st *initState) runInit() { os.Exit(1) } - if err := os.Chown(st.sockaddr, st.uid, st.gid); err != nil { + if err := os.Chown(st.sockaddr, int(st.uid), int(st.gid)); err != nil { st.log.Warning("Failed to chown oz-init control socket: %v", err) } @@ -238,6 +182,7 @@ func (st *initState) runInit() { fsbx := path.Join("/tmp", "oz-sandbox") err = ioutil.WriteFile(fsbx, []byte(st.profile.Name), 0644) + // Signal the daemon we are ready os.Stderr.WriteString("OK\n") go st.processSignals(sigs, s) @@ -267,10 +212,22 @@ func (st *initState) startXpraServer() { xpra.Process.Env = []string{ "HOME=" + st.user.HomeDir, } + + groups := append([]uint32{}, st.gid) + if gid, gexists := st.gids["video"]; gexists { + groups = append(groups, gid) + } + if st.profile.XServer.AudioMode != "" && st.profile.XServer.AudioMode != oz.PROFILE_AUDIO_NONE { + if gid, gexists := st.gids["audio"]; gexists { + groups = append(groups, gid) + } + } + xpra.Process.SysProcAttr = &syscall.SysProcAttr{} xpra.Process.SysProcAttr.Credential = &syscall.Credential{ - Uid: uint32(st.uid), - Gid: uint32(st.gid), + Uid: st.uid, + Gid: st.gid, + Groups: groups, } st.log.Info("Starting xpra server") if err := xpra.Process.Start(); err != nil { @@ -329,10 +286,15 @@ func (st *initState) launchApplication(cpath, pwd string, cmdArgs []string) (*ex st.log.Warning("Failed to create stderr pipe: %v", err) return nil, err } + groups := append([]uint32{}, st.gid) + for _, gid := range st.gids { + groups = append(groups, gid) + } cmd.SysProcAttr = &syscall.SysProcAttr{} cmd.SysProcAttr.Credential = &syscall.Credential{ - Uid: uint32(st.uid), - Gid: uint32(st.gid), + Uid: st.uid, + Gid: st.gid, + Groups: groups, } cmd.Env = append(cmd.Env, st.launchEnv...) @@ -343,6 +305,9 @@ func (st *initState) launchApplication(cpath, pwd string, cmdArgs []string) (*ex cmd.Args = append(cmd.Args, cmdArgs...) + if pwd == "" { + pwd = st.user.HomeDir + } if _, err := os.Stat(pwd); err == nil { cmd.Dir = pwd } @@ -403,12 +368,19 @@ func (st *initState) handleRunShell(rs *RunShellMsg, msg *ipc.Message) error { if (msg.Ucred.Uid == 0 || msg.Ucred.Gid == 0) && st.config.AllowRootShell != true { return msg.Respond(&ErrorMsg{"Cannot open shell because allowRootShell is disabled"}) } + groups := append([]uint32{}, st.gid) + if (msg.Ucred.Uid != 0 && msg.Ucred.Gid != 0) { + for _, gid := range st.gids { + groups = append(groups, gid) + } + } st.log.Info("Starting shell with uid = %d, gid = %d", msg.Ucred.Uid, msg.Ucred.Gid) cmd := exec.Command(st.config.ShellPath, "-i") cmd.SysProcAttr = &syscall.SysProcAttr{} cmd.SysProcAttr.Credential = &syscall.Credential{ - Uid: msg.Ucred.Uid, - Gid: msg.Ucred.Gid, + Uid: msg.Ucred.Uid, + Gid: msg.Ucred.Gid, + Groups: groups, } cmd.Env = append(cmd.Env, st.launchEnv...) if rs.Term != "" { @@ -578,6 +550,9 @@ func (st *initState) bindWhitelist(fsys *fs.Filesystem, wlist []oz.WhitelistItem if wl.ReadOnly { flags |= fs.BindReadOnly } + if wl.Path == "" { + continue + } if err := fsys.BindPath(wl.Path, flags, st.user); err != nil { return err } @@ -590,6 +565,9 @@ func (st *initState) applyBlacklist(fsys *fs.Filesystem, blist []oz.BlacklistIte return nil } for _, bl := range blist { + if bl.Path == "" { + continue + } if err := fsys.BlacklistPath(bl.Path, st.user); err != nil { return err } diff --git a/oz-init/rootfs.go b/oz-init/rootfs.go index 18e84ba..b4822d6 100644 --- a/oz-init/rootfs.go +++ b/oz-init/rootfs.go @@ -107,7 +107,7 @@ func setupRootfs(fsys *fs.Filesystem, useFullDev bool) error { return err } - if (!useFullDev) { + if !useFullDev { for _, d := range basicDevices { if err := fsys.CreateDevice(d.path, d.dev, d.mode); err != nil { return err diff --git a/oz-mount/mount.go b/oz-mount/mount.go index bd6a666..fdac966 100644 --- a/oz-mount/mount.go +++ b/oz-mount/mount.go @@ -1,5 +1,6 @@ // +build linux,!gccgo package mount + // extern int enter_mount_namespace(void); /* #include @@ -45,13 +46,13 @@ func Main(mode int) { os.Exit(1) } fsys := fs.NewFilesystem(config, log) - homedir := os.Getenv("_OZ_HOMEDIR") + homedir := os.Getenv("_OZ_HOMEDIR") if homedir == "" { log.Error("Homedir must be set!") os.Exit(1) } os.Setenv("_OZ_HOMEDIR", "") - + start := 1 readonly := false if os.Args[1] == "--readonly" { @@ -60,7 +61,7 @@ func Main(mode int) { } for _, fpath := range os.Args[start:] { cpath, err := cleanPath(fpath, homedir) - if (err != nil || cpath == "") { + if err != nil || cpath == "" { log.Error("%v", err) os.Exit(1) } diff --git a/oz-seccomp/seccomp.go b/oz-seccomp/seccomp.go index 4799e7a..d2c7a0d 100644 --- a/oz-seccomp/seccomp.go +++ b/oz-seccomp/seccomp.go @@ -27,6 +27,11 @@ func Main() { os.Exit(1) } + if os.Getppid() != 1 { + log.Error("oz-seccomp wrapper must be called from oz-init!") + os.Exit(1) + } + var getvar = func(name string) string { val := os.Getenv(name) if val == "" { diff --git a/oz/main.go b/oz/main.go index 0c75ecf..21ed788 100644 --- a/oz/main.go +++ b/oz/main.go @@ -49,7 +49,7 @@ func runSandboxed() { os.Exit(1) } } - if err := daemon.Launch("0", apath, os.Args[1:], os.Environ(), false); err != nil { + if err := daemon.Launch("0", apath, os.Args[1:], false); err != nil { fmt.Fprintf(os.Stderr, "launch command failed: %v.\n", err) os.Exit(1) } @@ -128,7 +128,7 @@ func handleLaunch(c *cli.Context) { fmt.Println("Argument needed to launch command") os.Exit(1) } - err := daemon.Launch(c.Args()[0], "", c.Args()[1:], os.Environ(), noexec) + err := daemon.Launch(c.Args()[0], "", c.Args()[1:], noexec) if err != nil { fmt.Printf("launch command failed: %v\n", err) os.Exit(1) @@ -177,7 +177,7 @@ func handleShell(c *cli.Context) { fmt.Printf("start shell command failed: %v\n", err) os.Exit(1) } - fmt.Println("Entering interactive shell?\n") + fmt.Printf("Entering interactive shell in `%s`\n\n", sb.Profile) st, err := SetRawTerminal(0) HandleResize(fd) f := os.NewFile(uintptr(fd), "") diff --git a/profile.go b/profile.go index 41b82a7..982fba2 100644 --- a/profile.go +++ b/profile.go @@ -33,6 +33,7 @@ type Profile struct { NoDefaults bool // Allow bind mounting of files passed as arguments inside the sandbox AllowFiles bool `json:"allow_files"` + AllowedGroups []string `json:"allowed_groups"` // List of paths to bind mount inside jail Whitelist []WhitelistItem // List of paths to blacklist inside jail @@ -61,9 +62,9 @@ type XServerConf struct { WindowIcon string `json:"window_icon"` EnableTray bool `json:"enable_tray"` EnableNotifications bool `json:"enable_notifications"` - UsePulseAudio bool `json:"use_pulse_audio"` DisableClipboard bool `json:"disable_clipboard"` AudioMode AudioMode `json:"audio_mode"` + Border bool `json:"border"` } type SeccompMode string @@ -118,12 +119,13 @@ func NewDefaultProfile() *Profile { return &Profile{ Multi: false, AllowFiles: false, + AllowedGroups: []string{}, XServer: XServerConf{ Enabled: true, EnableTray: false, EnableNotifications: false, - UsePulseAudio: false, AudioMode: PROFILE_AUDIO_NONE, + Border: false, }, } } @@ -191,6 +193,10 @@ func LoadProfiles(dir string) (Profiles, error) { } func loadProfileFile(file string) (*Profile, error) { + if err := checkConfigPermissions(file); err != nil { + return nil, err + } + bs, err := ioutil.ReadFile(file) if err != nil { return nil, err diff --git a/profiles/torbrowser-launcher.json b/profiles/torbrowser-launcher.json index c4e3269..65d1550 100644 --- a/profiles/torbrowser-launcher.json +++ b/profiles/torbrowser-launcher.json @@ -1,6 +1,7 @@ { "path": "/usr/bin/torbrowser-launcher" , "watchdog": "start-tor-browser" +, "allowed_groups": ["debian-tor"] , "xserver": { "enabled": true , "enable_tray": true @@ -21,8 +22,12 @@ , "blacklist": [ ] , "environment": [ - {"name":"TOR_SKIP_LAUNCH"} - , {"name":"TOR_SOCKS_HOST"} - , {"name":"TOR_SOCKS_PORT"} + {"name":"TOR_SKIP_LAUNCH"} + , {"name":"TOR_SOCKS_HOST"} + , {"name":"TOR_SOCKS_PORT"} + , {"name":"TOR_CONTROL_PORT"} + , {"name":"TOR_CONTROL_PASSWD"} + , {"name":"TOR_CONTROL_AUTHENTICATE"} + , {"name":"TOR_CONTROL_COOKIE_AUTH_FILE"} ] } diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..495fa35 --- /dev/null +++ b/utils.go @@ -0,0 +1,32 @@ +package oz + +import( + "fmt" + "os" + "path" + "syscall" +) + +func checkConfigPermissions(fpath string) error { + pd := path.Dir(fpath) + for _, fp := range []string{pd, fpath} { + if err := checkPathRootPermissions(fp); err != nil { + return fmt.Errorf("file `%s` is %s", fp, err) + } + } + return nil +} + +func checkPathRootPermissions(fpath string) error { + fstat, err := os.Stat(fpath) + if err != nil { + return err + } + if (fstat.Mode().Perm() & syscall.S_IWOTH) != 0 { + return fmt.Errorf("writable by everyone!") + } + if (fstat.Mode().Perm()&syscall.S_IWGRP) != 0 && fstat.Sys().(*syscall.Stat_t).Gid != 0 { + return fmt.Errorf("writable by someone else than root!") + } + return nil +} diff --git a/xpra/client.go b/xpra/client.go index 1a20156..b57e653 100644 --- a/xpra/client.go +++ b/xpra/client.go @@ -1,12 +1,16 @@ package xpra import ( + "crypto/md5" "fmt" - "github.com/op/go-logging" - "github.com/subgraph/oz" + "io" "os" "os/exec" "syscall" + + "github.com/subgraph/oz" + + "github.com/op/go-logging" ) var xpraClientDefaultArgs = []string{ @@ -40,13 +44,20 @@ func prepareClientArgs(config *oz.XServerConf, display uint64, workdir string, l args = append(args, xpraClientDefaultArgs...) if !config.EnableTray { args = append(args, "--no-tray") - } - if exists(config.TrayIcon, "Tray icon", log) { - args = append(args, fmt.Sprintf("--tray-icon=%s", config.TrayIcon)) + } else { + args = append(args, "--tray") + if exists(config.TrayIcon, "Tray icon", log) { + args = append(args, fmt.Sprintf("--tray-icon=%s", config.TrayIcon)) + } } if exists(config.WindowIcon, "Window icon", log) { args = append(args, fmt.Sprintf("--window-icon=%s", config.WindowIcon)) } + if config.Border { + h := md5.New() + io.WriteString(h, workdir) + args = append(args, "--border=#" + fmt.Sprintf("%x", h.Sum(nil)[0:3])) + } args = append(args, fmt.Sprintf("--socket-dir=%s", workdir), "attach", diff --git a/xpra/server.go b/xpra/server.go index 0290adf..26c4b9d 100644 --- a/xpra/server.go +++ b/xpra/server.go @@ -10,7 +10,6 @@ import ( var xpraServerDefaultArgs = []string{ "--no-mdns", //"--pulseaudio", - "--no-pulseaudio", "--input-method=keep", } @@ -36,5 +35,10 @@ func prepareServerArgs(config *oz.XServerConf, display uint64, workdir string) [ "start", fmt.Sprintf(":%d", display), ) + if config.AudioMode == oz.PROFILE_AUDIO_FULL || config.AudioMode == oz.PROFILE_AUDIO_SPEAKER { + args = append(args, "--pulseaudio") + } else { + args = append(args, "--no-pulseaudio") + } return args } diff --git a/xpra/xpra.go b/xpra/xpra.go index 66b0f81..745c6ae 100644 --- a/xpra/xpra.go +++ b/xpra/xpra.go @@ -38,7 +38,6 @@ var xpraDefaultArgs = []string{ //"--no-xsettings", "--cursors", "--encoding=rgb", - "--no-pulseaudio", } func getDefaultArgs(config *oz.XServerConf) []string {