Merge remote-tracking branch 'origin/master'

Conflicts:
	oz-init/init.go
master
dma 9 years ago
commit 1b05e93908

6
Godeps/Godeps.json generated

@ -1,6 +1,6 @@
{ {
"ImportPath": "github.com/subgraph/oz", "ImportPath": "github.com/subgraph/oz",
"GoVersion": "go1.4.2", "GoVersion": "go1.3.3",
"Packages": [ "Packages": [
"./..." "./..."
], ],
@ -35,6 +35,10 @@
{ {
"ImportPath": "github.com/op/go-logging", "ImportPath": "github.com/op/go-logging",
"Rev": "e8d5414f0947014548c2334044a0fac13187dfee" "Rev": "e8d5414f0947014548c2334044a0fac13187dfee"
},
{
"ImportPath": "github.com/subgraph/go-seccomp",
"Rev": "2eb74b38c2f37e0f48efa3a0974fd2e4edbd0ef5"
} }
] ]
} }

@ -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.

@ -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 <linux/audit.h>
import "C"
const (
auditArch = C.AUDIT_ARCH_I386
nbits = 32
)

@ -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 <linux/audit.h>
import "C"
const (
auditArch = C.AUDIT_ARCH_X86_64
nbits = 64
)

@ -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 <linux/audit.h>
import "C"
const (
auditArch = C.AUDIT_ARCH_ARM
nbits = 32
)

@ -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 <linux/filter.h>
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 <linux/filter.h>.
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 <linux/filter.h>.
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
}

@ -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)
}
}
}

@ -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 <sys/prctl.h>
// #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 <linux/seccomp.h>.
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 <linux/seccomp.h> 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)
}

@ -0,0 +1,54 @@
#ifndef _UAPI_LINUX_SECCOMP_H
#define _UAPI_LINUX_SECCOMP_H
// #include <linux/compiler.h>
#include <linux/types.h>
/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
#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 <linux/audit.h>.
* @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 */

@ -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: "<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])
}
}
}

@ -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,
}

@ -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,
}

@ -0,0 +1,359 @@
// DO NOT EDIT. Autogenerated by syscalls_gen.go
package seccomp
// #include <asm/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,
"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,
}

@ -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 <asm-generic/unistd_64.h>" | 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 <asm-generic/unistd_64.h>")
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("}")
}

@ -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

@ -2,11 +2,8 @@ package oz
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"syscall"
) )
type Config struct { type Config struct {
@ -21,6 +18,7 @@ type Config struct {
AllowRootShell bool `json:"allow_root_shell" desc:"Allow entering a sandbox shell as root"` AllowRootShell bool `json:"allow_root_shell" desc:"Allow entering a sandbox shell as root"`
LogXpra bool `json:"log_xpra" desc:"Log output of Xpra"` LogXpra bool `json:"log_xpra" desc:"Log output of Xpra"`
EnvironmentVars []string `json:"environment_vars" desc:"Default environment variables passed to sandboxes"` 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" const OzVersion = "0.0.1"
@ -28,19 +26,22 @@ const DefaultConfigPath = "/etc/oz/oz.conf"
func NewDefaultConfig() *Config { func NewDefaultConfig() *Config {
return &Config{ return &Config{
ProfileDir: "/var/lib/oz/cells.d", ProfileDir: "/var/lib/oz/cells.d",
ShellPath: "/bin/bash", ShellPath: "/bin/bash",
PrefixPath: "/usr/local", PrefixPath: "/usr/local",
SandboxPath: "/srv/oz", SandboxPath: "/srv/oz",
NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf", NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf",
BridgeMACAddr: "6A:A8:2E:56:E8:9C", BridgeMACAddr: "6A:A8:2E:56:E8:9C",
DivertSuffix: "unsafe", DivertSuffix: "unsafe",
UseFullDev: false, UseFullDev: false,
AllowRootShell: false, AllowRootShell: false,
LogXpra: false, LogXpra: false,
EnvironmentVars: []string{ EnvironmentVars: []string{
"USER", "USERNAME", "LOGNAME", "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 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
}

@ -162,7 +162,7 @@ func (fs *Filesystem) bind(from string, to string, flags int, u *user.User) erro
return bindMount(src, to, mntflags) 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) to = path.Join(fs.Root(), to)
_, err := os.Stat(to) _, err := os.Stat(to)
@ -173,7 +173,7 @@ func (fs *Filesystem) UnbindPath(to string) (error) {
// XXX // XXX
fs.log.Info("unbinding %s", to) 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 return err
} }

@ -2,12 +2,12 @@ package fs
import ( import (
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"os/user" "os/user"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"os"
) )
func resolvePath(p string, u *user.User) ([]string, error) { func resolvePath(p string, u *user.User) ([]string, error) {

@ -13,9 +13,9 @@ import (
//Internal //Internal
//External //External
"github.com/op/go-logging"
"github.com/j-keck/arping" "github.com/j-keck/arping"
"github.com/milosgajdos83/tenus" "github.com/milosgajdos83/tenus"
"github.com/op/go-logging"
) )
func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*HostNetwork, error) { 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))) rand.Seed(time.Now().Unix() ^ int64((os.Getpid() + childPid)))
log.Info("Configuring host veth pair '%s' with: %s", stn.VethHost, stn.Ip+"/"+htn.Class) log.Info("Configuring host veth pair '%s' with: %s", stn.VethHost, stn.Ip+"/"+htn.Class)
/* /*
// Fetch the bridge from the ifname // Fetch the bridge from the ifname
br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge) br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge)
if err != nil { if err != nil {
return fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err) return fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err)
} }
*/ */
// Make sure the bridge is configured and the link is up // Make sure the bridge is configured and the link is up
// This really shouldn't be needed, but Network-Manager is a PITA // This really shouldn't be needed, but Network-Manager is a PITA
// and even if you actualy ignore the interface there's a race // and even if you actualy ignore the interface there's a race

@ -7,8 +7,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/op/go-logging"
"github.com/milosgajdos83/tenus" "github.com/milosgajdos83/tenus"
"github.com/op/go-logging"
) )
const ( const (
@ -21,9 +21,9 @@ const (
type NetType string type NetType string
const( const (
TYPE_HOST NetType = "host" TYPE_HOST NetType = "host"
TYPE_EMPTY NetType = "empty" TYPE_EMPTY NetType = "empty"
TYPE_BRIDGE NetType = "bridge" TYPE_BRIDGE NetType = "bridge"
) )

@ -1,6 +1,6 @@
package network package network
import( import (
//Builtin //Builtin
"fmt" "fmt"
"io" "io"
@ -16,16 +16,16 @@ import(
type ProxyType string type ProxyType string
const( const (
PROXY_CLIENT ProxyType = "client" PROXY_CLIENT ProxyType = "client"
PROXY_SERVER ProxyType = "server" PROXY_SERVER ProxyType = "server"
) )
type ProtoType string type ProtoType string
const( const (
PROTO_TCP ProtoType = "tcp" PROTO_TCP ProtoType = "tcp"
PROTO_UDP ProtoType = "udp" PROTO_UDP ProtoType = "udp"
PROTO_SOCKET ProtoType = "socket" PROTO_SOCKET ProtoType = "socket"
) )
@ -146,7 +146,7 @@ func nsSocketListener(fd uintptr, proto ProtoType, lAddr string) (net.Listener,
/** /**
* Connect/Server * 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) rConn, err := socketConnect(pid, proto, rAddr)
if err != nil { if err != nil {
log.Error("Socket: %+v.", err) log.Error("Socket: %+v.", err)
@ -159,7 +159,7 @@ func proxyServerConn(pid int, conn *net.Conn, proto ProtoType, rAddr string, log
return nil 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 == "" { if dest == "" {
dest = "127.0.0.1" dest = "127.0.0.1"
} }

@ -53,20 +53,28 @@ func ListSandboxes() ([]SandboxInfo, error) {
return body.Sandboxes, nil 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) idx, name, err := parseProfileArg(arg)
if err != nil { if err != nil {
return err return err
} }
pwd, _ := os.Getwd() 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{ resp, err := clientSend(&LaunchMsg{
Index: idx, Index: idx,
Name: name, Name: name,
Path: cpath, Path: cpath,
Pwd: pwd, Pwd: pwd,
Gids: gg,
Args: args, Args: args,
Env: env, Env: os.Environ(),
Noexec: noexec, Noexec: noexec,
}) })
if err != nil { 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}) resp, err := clientSend(&MountFilesMsg{Files: files})
if err != nil { if err != nil {
return err 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}) resp, err := clientSend(&UnmountFileMsg{File: file})
if err != nil { if err != nil {
return err return err

@ -1,11 +1,13 @@
package daemon package daemon
import ( import (
"bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path" "path"
"strconv"
"strings" "strings"
"syscall" "syscall"
@ -16,16 +18,23 @@ import (
"github.com/op/go-logging" "github.com/op/go-logging"
) )
type groupEntry struct {
Name string
Gid uint32
Members []string
}
type daemonState struct { type daemonState struct {
log *logging.Logger log *logging.Logger
config *oz.Config config *oz.Config
profiles oz.Profiles profiles oz.Profiles
sandboxes []*Sandbox sandboxes []*Sandbox
nextSboxId int nextSboxId int
nextDisplay int nextDisplay int
memBackend *logging.ChannelMemoryBackend memBackend *logging.ChannelMemoryBackend
backends []logging.Backend backends []logging.Backend
network *network.HostNetwork network *network.HostNetwork
systemGroups map[string]groupEntry
} }
func Main() { func Main() {
@ -66,6 +75,9 @@ func initialize() *daemonState {
os.Exit(1) os.Exit(1)
} }
d.profiles = ps 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) oz.ReapChildProcs(d.log, d.handleChildExit)
d.nextSboxId = 1 d.nextSboxId = 1
d.nextDisplay = 100 d.nextDisplay = 100
@ -80,9 +92,7 @@ func initialize() *daemonState {
} }
d.network = htn d.network = htn
//network.NetPrint(d.log) //network.NetPrint(d.log)
break 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) { func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
d.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus()) 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{} newEnv := []string{}
for _, EnvItem := range d.config.EnvironmentVars { for _, EnvItem := range d.config.EnvironmentVars {
if strings.Contains(EnvItem, "=") {
newEnv = append(newEnv, EnvItem)
continue
}
for _, OldItem := range oldEnv { for _, OldItem := range oldEnv {
if strings.HasPrefix(OldItem, EnvItem+"=") { if strings.HasPrefix(OldItem, EnvItem+"=") {
newEnv = append(newEnv, EnvItem+"="+strings.Replace(OldItem, EnvItem+"=", "", 1)) 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{}) return m.Respond(&OkMsg{})
} }
func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) error { func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) error {
sbox := d.sandboxById(msg.Id) sbox := d.sandboxById(msg.Id)
if sbox == nil { if sbox == nil {
@ -293,8 +339,6 @@ func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) err
return m.Respond(&OkMsg{}) return m.Respond(&OkMsg{})
} }
func (d *daemonState) sandboxById(id int) *Sandbox { func (d *daemonState) sandboxById(id int) *Sandbox {
for _, sb := range d.sandboxes { for _, sb := range d.sandboxes {
if sb.id == id { if sb.id == id {

@ -2,8 +2,10 @@ package daemon
import ( import (
"bufio" "bufio"
"bytes"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt" "fmt"
"io" "io"
"os" "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 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 := exec.Command(initPath)
cmd.Dir = "/" cmd.Dir = "/"
@ -61,7 +63,7 @@ func createInitCommand(initPath, name string, socketPath string, env []string, u
cloneFlags |= syscall.CLONE_NEWPID cloneFlags |= syscall.CLONE_NEWPID
cloneFlags |= syscall.CLONE_NEWUTS cloneFlags |= syscall.CLONE_NEWUTS
if stn.Nettype != network.TYPE_HOST { if cloneNet {
cloneFlags |= syscall.CLONE_NEWNET cloneFlags |= syscall.CLONE_NEWNET
} }
@ -69,24 +71,6 @@ func createInitCommand(initPath, name string, socketPath string, env []string, u
//Chroot: chroot, //Chroot: chroot,
Cloneflags: cloneFlags, 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 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)) u, err := user.LookupId(strconv.FormatUint(uint64(uid), 10))
if err != nil { if err != nil {
log.Error("Failed to look up user with uid=%ld: %v", uid, err) return nil, fmt.Errorf("Failed to look up user with uid=%ld: %v", uid, err)
os.Exit(1) }
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 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) return nil, fmt.Errorf("Failed to create random socket path: %v", err)
} }
initPath := path.Join(d.config.PrefixPath, "bin", "oz-init") initPath := path.Join(d.config.PrefixPath, "bin", "oz-init")
cmd := createInitCommand(initPath, p.Name, socketPath, msg.Env, uid, display, stn) cmd := createInitCommand(initPath, (stn.Nettype != network.TYPE_HOST))
log.Debug("Command environment: %+v", cmd.Env)
pp, err := cmd.StderrPipe() pp, err := cmd.StderrPipe()
if err != nil { if err != nil {
//fs.Cleanup() //fs.Cleanup()
return nil, fmt.Errorf("error creating stderr pipe for init process: %v", err) 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 { if err := cmd.Start(); err != nil {
//fs.Cleanup() //fs.Cleanup()
return nil, fmt.Errorf("Unable to start process: %+v", err) return nil, fmt.Errorf("Unable to start process: %+v", err)
} }
//rootfs := path.Join(d.config.SandboxPath, "rootfs") //rootfs := path.Join(d.config.SandboxPath, "rootfs")
sbox := &Sandbox{ sbox := &Sandbox{
daemon: d, daemon: d,
@ -152,7 +159,7 @@ func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, uid, gid uint32, log
display: display, display: display,
profile: p, profile: p,
init: cmd, init: cmd,
cred: &syscall.Credential{Uid: uid, Gid: gid}, cred: &syscall.Credential{Uid: uid, Gid: gid, Groups: msg.Gids},
user: u, user: u,
fs: fs.NewFilesystem(d.config, log), fs: fs.NewFilesystem(d.config, log),
//addr: path.Join(rootfs, ozinit.SocketAddress), //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 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) { func (sbox *Sandbox) launchProgram(binpath, cpath, pwd string, args []string, log *logging.Logger) {
if sbox.profile.AllowFiles { if sbox.profile.AllowFiles {
sbox.whitelistArgumentFiles(binpath, pwd, args, log) 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") pmnt := path.Join(binpath, "bin", "oz-mount")
args := files args := files
if readonly { if readonly {
@ -235,12 +274,12 @@ func (sbox *Sandbox) MountFiles(files []string, readonly bool, binpath string,
for _, mfile := range files { for _, mfile := range files {
found := false found := false
for _, mmfile := range sbox.mountedFiles { for _, mmfile := range sbox.mountedFiles {
if (mfile == mmfile) { if mfile == mmfile {
found = true found = true
break; break
} }
} }
if (!found) { if !found {
sbox.mountedFiles = append(sbox.mountedFiles, mfile) sbox.mountedFiles = append(sbox.mountedFiles, mfile)
} }
} }
@ -284,7 +323,7 @@ func (sbox *Sandbox) whitelistArgumentFiles(binpath, pwd string, args []string,
} }
} }
if len(files) > 0 { if len(files) > 0 {
sbox.MountFiles(files, false, binpath, log); sbox.MountFiles(files, false, binpath, log)
} }
} }

@ -39,6 +39,7 @@ type LaunchMsg struct {
Path string Path string
Name string Name string
Pwd string Pwd string
Gids []uint32
Args []string Args []string
Env []string Env []string
Noexec bool Noexec bool
@ -64,13 +65,13 @@ type KillSandboxMsg struct {
} }
type MountFilesMsg struct { type MountFilesMsg struct {
Id int "MountFiles" Id int "MountFiles"
Files []string Files []string
ReadOnly bool ReadOnly bool
} }
type UnmountFileMsg struct { type UnmountFileMsg struct {
Id int "UnmountFile" Id int "UnmountFile"
File string File string
} }

@ -2,10 +2,10 @@ package ozinit
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@ -26,8 +26,6 @@ import (
"github.com/op/go-logging" "github.com/op/go-logging"
) )
const EnvPrefix = "INIT_ENV_"
type initState struct { type initState struct {
log *logging.Logger log *logging.Logger
profile *oz.Profile profile *oz.Profile
@ -36,8 +34,9 @@ type initState struct {
launchEnv []string launchEnv []string
lock sync.Mutex lock sync.Mutex
children map[int]*exec.Cmd children map[int]*exec.Cmd
uid int uid uint32
gid int gid uint32
gids map[string]uint32
user *user.User user *user.User
display int display int
fs *fs.Filesystem fs *fs.Filesystem
@ -47,6 +46,19 @@ type initState struct {
network *network.SandboxNetwork 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 // 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 // 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. // over a pipe by oz-daemon and translated into appropriate log events.
@ -76,108 +88,40 @@ func parseArgs() *initState {
os.Exit(1) os.Exit(1)
} }
getvar := func(name string) string { initData := new(InitData)
val := os.Getenv(name) if err := json.NewDecoder(os.Stdin).Decode(&initData); err != nil {
if val == "" { log.Error("unable to decode init data: %v", err)
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)
os.Exit(1) os.Exit(1)
} }
display := 0 log.Debug("Init state: %+v", initData)
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 (initData.User.Uid != strconv.Itoa(int(initData.Uid))) || (initData.Uid == 0) {
if stnip != "" { log.Error("invalid uid or user passed to init.")
gateway, _, err := net.ParseCIDR(stngateway) os.Exit(1)
if err != nil {
log.Error("Unable to parse network configuration gateway (%s): %v", stngateway, err)
os.Exit(1)
}
stn.Ip = stnip
stn.VethHost = stnvhost
stn.VethGuest = stnvguest
stn.Gateway = gateway
} }
env := []string{} env := []string{}
for _, e := range os.Environ() { env = append(env, initData.LaunchEnv...)
if strings.HasPrefix(e, EnvPrefix) {
e = e[len(EnvPrefix):]
log.Debug("Adding (%s) to launch environment", e)
env = append(env, e)
}
}
env = append(env, "PATH=/usr/bin:/bin") env = append(env, "PATH=/usr/bin:/bin")
if p.XServer.Enabled { if initData.Profile.XServer.Enabled {
env = append(env, "DISPLAY=:"+strconv.Itoa(display)) env = append(env, "DISPLAY=:"+strconv.Itoa(initData.Display))
} }
return &initState{ return &initState{
log: log, log: log,
config: config, config: &initData.Config,
sockaddr: sockaddr, sockaddr: initData.Sockaddr,
launchEnv: env, launchEnv: env,
profile: p, profile: &initData.Profile,
children: make(map[int]*exec.Cmd), children: make(map[int]*exec.Cmd),
uid: uid, uid: initData.Uid,
gid: gid, gid: initData.Gid,
user: u, gids: initData.Gids,
display: display, user: &initData.User,
fs: fs.NewFilesystem(config, log), display: initData.Display,
network: stn, fs: fs.NewFilesystem(&initData.Config, log),
network: &initData.Network,
} }
} }
@ -196,7 +140,7 @@ func (st *initState) runInit() {
os.Exit(1) 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) 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") fsbx := path.Join("/tmp", "oz-sandbox")
err = ioutil.WriteFile(fsbx, []byte(st.profile.Name), 0644) err = ioutil.WriteFile(fsbx, []byte(st.profile.Name), 0644)
// Signal the daemon we are ready
os.Stderr.WriteString("OK\n") os.Stderr.WriteString("OK\n")
go st.processSignals(sigs, s) go st.processSignals(sigs, s)
@ -267,10 +212,22 @@ func (st *initState) startXpraServer() {
xpra.Process.Env = []string{ xpra.Process.Env = []string{
"HOME=" + st.user.HomeDir, "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 = &syscall.SysProcAttr{}
xpra.Process.SysProcAttr.Credential = &syscall.Credential{ xpra.Process.SysProcAttr.Credential = &syscall.Credential{
Uid: uint32(st.uid), Uid: st.uid,
Gid: uint32(st.gid), Gid: st.gid,
Groups: groups,
} }
st.log.Info("Starting xpra server") st.log.Info("Starting xpra server")
if err := xpra.Process.Start(); err != nil { 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) st.log.Warning("Failed to create stderr pipe: %v", err)
return nil, err return nil, err
} }
groups := append([]uint32{}, st.gid)
for _, gid := range st.gids {
groups = append(groups, gid)
}
cmd.SysProcAttr = &syscall.SysProcAttr{} cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{ cmd.SysProcAttr.Credential = &syscall.Credential{
Uid: uint32(st.uid), Uid: st.uid,
Gid: uint32(st.gid), Gid: st.gid,
Groups: groups,
} }
cmd.Env = append(cmd.Env, st.launchEnv...) 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...) cmd.Args = append(cmd.Args, cmdArgs...)
if pwd == "" {
pwd = st.user.HomeDir
}
if _, err := os.Stat(pwd); err == nil { if _, err := os.Stat(pwd); err == nil {
cmd.Dir = pwd 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 { if (msg.Ucred.Uid == 0 || msg.Ucred.Gid == 0) && st.config.AllowRootShell != true {
return msg.Respond(&ErrorMsg{"Cannot open shell because allowRootShell is disabled"}) 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) st.log.Info("Starting shell with uid = %d, gid = %d", msg.Ucred.Uid, msg.Ucred.Gid)
cmd := exec.Command(st.config.ShellPath, "-i") cmd := exec.Command(st.config.ShellPath, "-i")
cmd.SysProcAttr = &syscall.SysProcAttr{} cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{ cmd.SysProcAttr.Credential = &syscall.Credential{
Uid: msg.Ucred.Uid, Uid: msg.Ucred.Uid,
Gid: msg.Ucred.Gid, Gid: msg.Ucred.Gid,
Groups: groups,
} }
cmd.Env = append(cmd.Env, st.launchEnv...) cmd.Env = append(cmd.Env, st.launchEnv...)
if rs.Term != "" { if rs.Term != "" {
@ -578,6 +550,9 @@ func (st *initState) bindWhitelist(fsys *fs.Filesystem, wlist []oz.WhitelistItem
if wl.ReadOnly { if wl.ReadOnly {
flags |= fs.BindReadOnly flags |= fs.BindReadOnly
} }
if wl.Path == "" {
continue
}
if err := fsys.BindPath(wl.Path, flags, st.user); err != nil { if err := fsys.BindPath(wl.Path, flags, st.user); err != nil {
return err return err
} }
@ -590,6 +565,9 @@ func (st *initState) applyBlacklist(fsys *fs.Filesystem, blist []oz.BlacklistIte
return nil return nil
} }
for _, bl := range blist { for _, bl := range blist {
if bl.Path == "" {
continue
}
if err := fsys.BlacklistPath(bl.Path, st.user); err != nil { if err := fsys.BlacklistPath(bl.Path, st.user); err != nil {
return err return err
} }

@ -107,7 +107,7 @@ func setupRootfs(fsys *fs.Filesystem, useFullDev bool) error {
return err return err
} }
if (!useFullDev) { if !useFullDev {
for _, d := range basicDevices { for _, d := range basicDevices {
if err := fsys.CreateDevice(d.path, d.dev, d.mode); err != nil { if err := fsys.CreateDevice(d.path, d.dev, d.mode); err != nil {
return err return err

@ -1,5 +1,6 @@
// +build linux,!gccgo // +build linux,!gccgo
package mount package mount
// extern int enter_mount_namespace(void); // extern int enter_mount_namespace(void);
/* /*
#include <stdlib.h> #include <stdlib.h>
@ -45,7 +46,7 @@ func Main(mode int) {
os.Exit(1) os.Exit(1)
} }
fsys := fs.NewFilesystem(config, log) fsys := fs.NewFilesystem(config, log)
homedir := os.Getenv("_OZ_HOMEDIR") homedir := os.Getenv("_OZ_HOMEDIR")
if homedir == "" { if homedir == "" {
log.Error("Homedir must be set!") log.Error("Homedir must be set!")
os.Exit(1) os.Exit(1)
@ -60,7 +61,7 @@ func Main(mode int) {
} }
for _, fpath := range os.Args[start:] { for _, fpath := range os.Args[start:] {
cpath, err := cleanPath(fpath, homedir) cpath, err := cleanPath(fpath, homedir)
if (err != nil || cpath == "") { if err != nil || cpath == "" {
log.Error("%v", err) log.Error("%v", err)
os.Exit(1) os.Exit(1)
} }

@ -27,6 +27,11 @@ func Main() {
os.Exit(1) 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 { var getvar = func(name string) string {
val := os.Getenv(name) val := os.Getenv(name)
if val == "" { if val == "" {

@ -49,7 +49,7 @@ func runSandboxed() {
os.Exit(1) 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) fmt.Fprintf(os.Stderr, "launch command failed: %v.\n", err)
os.Exit(1) os.Exit(1)
} }
@ -128,7 +128,7 @@ func handleLaunch(c *cli.Context) {
fmt.Println("Argument needed to launch command") fmt.Println("Argument needed to launch command")
os.Exit(1) 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 { if err != nil {
fmt.Printf("launch command failed: %v\n", err) fmt.Printf("launch command failed: %v\n", err)
os.Exit(1) os.Exit(1)
@ -177,7 +177,7 @@ func handleShell(c *cli.Context) {
fmt.Printf("start shell command failed: %v\n", err) fmt.Printf("start shell command failed: %v\n", err)
os.Exit(1) os.Exit(1)
} }
fmt.Println("Entering interactive shell?\n") fmt.Printf("Entering interactive shell in `%s`\n\n", sb.Profile)
st, err := SetRawTerminal(0) st, err := SetRawTerminal(0)
HandleResize(fd) HandleResize(fd)
f := os.NewFile(uintptr(fd), "") f := os.NewFile(uintptr(fd), "")

@ -33,6 +33,7 @@ type Profile struct {
NoDefaults bool NoDefaults bool
// Allow bind mounting of files passed as arguments inside the sandbox // Allow bind mounting of files passed as arguments inside the sandbox
AllowFiles bool `json:"allow_files"` AllowFiles bool `json:"allow_files"`
AllowedGroups []string `json:"allowed_groups"`
// List of paths to bind mount inside jail // List of paths to bind mount inside jail
Whitelist []WhitelistItem Whitelist []WhitelistItem
// List of paths to blacklist inside jail // List of paths to blacklist inside jail
@ -61,9 +62,9 @@ type XServerConf struct {
WindowIcon string `json:"window_icon"` WindowIcon string `json:"window_icon"`
EnableTray bool `json:"enable_tray"` EnableTray bool `json:"enable_tray"`
EnableNotifications bool `json:"enable_notifications"` EnableNotifications bool `json:"enable_notifications"`
UsePulseAudio bool `json:"use_pulse_audio"`
DisableClipboard bool `json:"disable_clipboard"` DisableClipboard bool `json:"disable_clipboard"`
AudioMode AudioMode `json:"audio_mode"` AudioMode AudioMode `json:"audio_mode"`
Border bool `json:"border"`
} }
type SeccompMode string type SeccompMode string
@ -118,12 +119,13 @@ func NewDefaultProfile() *Profile {
return &Profile{ return &Profile{
Multi: false, Multi: false,
AllowFiles: false, AllowFiles: false,
AllowedGroups: []string{},
XServer: XServerConf{ XServer: XServerConf{
Enabled: true, Enabled: true,
EnableTray: false, EnableTray: false,
EnableNotifications: false, EnableNotifications: false,
UsePulseAudio: false,
AudioMode: PROFILE_AUDIO_NONE, AudioMode: PROFILE_AUDIO_NONE,
Border: false,
}, },
} }
} }
@ -191,6 +193,10 @@ func LoadProfiles(dir string) (Profiles, error) {
} }
func loadProfileFile(file string) (*Profile, error) { func loadProfileFile(file string) (*Profile, error) {
if err := checkConfigPermissions(file); err != nil {
return nil, err
}
bs, err := ioutil.ReadFile(file) bs, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
return nil, err return nil, err

@ -1,6 +1,7 @@
{ {
"path": "/usr/bin/torbrowser-launcher" "path": "/usr/bin/torbrowser-launcher"
, "watchdog": "start-tor-browser" , "watchdog": "start-tor-browser"
, "allowed_groups": ["debian-tor"]
, "xserver": { , "xserver": {
"enabled": true "enabled": true
, "enable_tray": true , "enable_tray": true
@ -21,8 +22,12 @@
, "blacklist": [ , "blacklist": [
] ]
, "environment": [ , "environment": [
{"name":"TOR_SKIP_LAUNCH"} {"name":"TOR_SKIP_LAUNCH"}
, {"name":"TOR_SOCKS_HOST"} , {"name":"TOR_SOCKS_HOST"}
, {"name":"TOR_SOCKS_PORT"} , {"name":"TOR_SOCKS_PORT"}
, {"name":"TOR_CONTROL_PORT"}
, {"name":"TOR_CONTROL_PASSWD"}
, {"name":"TOR_CONTROL_AUTHENTICATE"}
, {"name":"TOR_CONTROL_COOKIE_AUTH_FILE"}
] ]
} }

@ -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
}

@ -1,12 +1,16 @@
package xpra package xpra
import ( import (
"crypto/md5"
"fmt" "fmt"
"github.com/op/go-logging" "io"
"github.com/subgraph/oz"
"os" "os"
"os/exec" "os/exec"
"syscall" "syscall"
"github.com/subgraph/oz"
"github.com/op/go-logging"
) )
var xpraClientDefaultArgs = []string{ var xpraClientDefaultArgs = []string{
@ -40,13 +44,20 @@ func prepareClientArgs(config *oz.XServerConf, display uint64, workdir string, l
args = append(args, xpraClientDefaultArgs...) args = append(args, xpraClientDefaultArgs...)
if !config.EnableTray { if !config.EnableTray {
args = append(args, "--no-tray") args = append(args, "--no-tray")
} } else {
if exists(config.TrayIcon, "Tray icon", log) { args = append(args, "--tray")
args = append(args, fmt.Sprintf("--tray-icon=%s", config.TrayIcon)) if exists(config.TrayIcon, "Tray icon", log) {
args = append(args, fmt.Sprintf("--tray-icon=%s", config.TrayIcon))
}
} }
if exists(config.WindowIcon, "Window icon", log) { if exists(config.WindowIcon, "Window icon", log) {
args = append(args, fmt.Sprintf("--window-icon=%s", config.WindowIcon)) 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, args = append(args,
fmt.Sprintf("--socket-dir=%s", workdir), fmt.Sprintf("--socket-dir=%s", workdir),
"attach", "attach",

@ -10,7 +10,6 @@ import (
var xpraServerDefaultArgs = []string{ var xpraServerDefaultArgs = []string{
"--no-mdns", "--no-mdns",
//"--pulseaudio", //"--pulseaudio",
"--no-pulseaudio",
"--input-method=keep", "--input-method=keep",
} }
@ -36,5 +35,10 @@ func prepareServerArgs(config *oz.XServerConf, display uint64, workdir string) [
"start", "start",
fmt.Sprintf(":%d", display), 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 return args
} }

@ -38,7 +38,6 @@ var xpraDefaultArgs = []string{
//"--no-xsettings", //"--no-xsettings",
"--cursors", "--cursors",
"--encoding=rgb", "--encoding=rgb",
"--no-pulseaudio",
} }
func getDefaultArgs(config *oz.XServerConf) []string { func getDefaultArgs(config *oz.XServerConf) []string {

Loading…
Cancel
Save