Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit 02e05e0

Browse files
yangshukuicrosbymichael
yangshukui
authored andcommitted
Add seccomp feature
add seccomp feature which is not use third-party add multi arch surport add test case all code use golang this pr is relate to #511 because I close it and find it can not be reopen Signed-off-by: Yang Shukui <[email protected]>
1 parent ce1f2f1 commit 02e05e0

10 files changed

+1949
-0
lines changed

configs/config.go

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ type Config struct {
6161
// All capbilities not specified will be dropped from the processes capability mask
6262
Capabilities []string `json:"capabilities"`
6363

64+
// SysCalls specify the system calls to keep when executing the process inside the container
65+
SysCalls []string `json:"syscalls"`
66+
6467
// Networks specifies the container's network setup to be created
6568
Networks []*Network `json:"networks"`
6669

init_linux.go

+15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/docker/libcontainer/cgroups"
1414
"github.com/docker/libcontainer/configs"
1515
"github.com/docker/libcontainer/netlink"
16+
"github.com/docker/libcontainer/seccomp"
1617
"github.com/docker/libcontainer/system"
1718
"github.com/docker/libcontainer/user"
1819
"github.com/docker/libcontainer/utils"
@@ -259,3 +260,17 @@ func killCgroupProcesses(m cgroups.Manager) error {
259260
}
260261
return nil
261262
}
263+
264+
func finalizeSeccomp(config *initConfig) error {
265+
scmpCtx, _ := seccomp.ScmpInit(seccomp.ScmpActAllow)
266+
if 0 == len(config.Config.SysCalls) {
267+
for key := range seccomp.SyscallMap {
268+
seccomp.ScmpAdd(scmpCtx, key, seccomp.ScmpActAllow)
269+
}
270+
} else {
271+
for _, call := range config.Config.SysCalls {
272+
seccomp.ScmpAdd(scmpCtx, call, seccomp.ScmpActAllow)
273+
}
274+
}
275+
return seccomp.ScmpLoad(scmpCtx)
276+
}

integration/exec_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package integration
22

33
import (
44
"bytes"
5+
"fmt"
56
"io/ioutil"
67
"os"
78
"path/filepath"
@@ -13,6 +14,7 @@ import (
1314
"github.com/docker/libcontainer"
1415
"github.com/docker/libcontainer/cgroups/systemd"
1516
"github.com/docker/libcontainer/configs"
17+
"github.com/docker/libcontainer/seccomp"
1618
)
1719

1820
func TestExecPS(t *testing.T) {
@@ -714,3 +716,66 @@ func TestSystemProperties(t *testing.T) {
714716
t.Fatalf("kernel.shmmni property expected to be 8192, but is %s", shmmniOutput)
715717
}
716718
}
719+
720+
func allExcept(calls []string) []string {
721+
num := len(seccomp.SyscallMap) - len(calls)
722+
filter := make([]string, num)
723+
i := 0
724+
for key := range seccomp.SyscallMap {
725+
j := 0
726+
for _, key1 := range calls {
727+
if strings.EqualFold(key, key1) {
728+
break
729+
}
730+
j++
731+
}
732+
if j == len(calls) {
733+
filter[i] = key
734+
i++
735+
}
736+
}
737+
return filter
738+
}
739+
740+
func TestSeccompNotStat(t *testing.T) {
741+
if testing.Short() {
742+
return
743+
}
744+
745+
rootfs, err := newRootfs()
746+
if err != nil {
747+
t.Fatal(err)
748+
}
749+
defer remove(rootfs)
750+
751+
config := newTemplateConfig(rootfs)
752+
exceptCall := []string{"STAT"}
753+
config.SysCalls = allExcept(exceptCall)
754+
out, _, err := runContainer(config, "", "/bin/sh", "-c", "ls / -l")
755+
if err == nil {
756+
t.Fatal("runContainer should be failed")
757+
} else {
758+
fmt.Println(out)
759+
}
760+
}
761+
762+
func TestSeccompStat(t *testing.T) {
763+
if testing.Short() {
764+
return
765+
}
766+
767+
rootfs, err := newRootfs()
768+
if err != nil {
769+
t.Fatal(err)
770+
}
771+
defer remove(rootfs)
772+
773+
config := newTemplateConfig(rootfs)
774+
exceptCall := []string{}
775+
config.SysCalls = allExcept(exceptCall)
776+
out, _, err := runContainer(config, "", "/bin/sh", "-c", "ls / -l")
777+
if err != nil {
778+
t.Fatal(err)
779+
}
780+
fmt.Println(out)
781+
}

seccomp/seccomp.go

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package seccomp
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"syscall"
7+
"unsafe"
8+
)
9+
10+
type sockFilter struct {
11+
code uint16
12+
jt uint8
13+
jf uint8
14+
k uint32
15+
}
16+
17+
type sockFprog struct {
18+
len uint16
19+
filt []sockFilter
20+
}
21+
22+
type Action struct {
23+
syscall uint32
24+
action int
25+
args []string
26+
}
27+
28+
type ScmpCtx struct {
29+
CallMap map[string]Action
30+
act int
31+
}
32+
33+
var ScmpActAllow = 0
34+
35+
func ScmpInit(action int) (*ScmpCtx, error) {
36+
ctx := ScmpCtx{
37+
CallMap: make(map[string]Action),
38+
act: action,
39+
}
40+
return &ctx, nil
41+
}
42+
43+
func ScmpAdd(ctx *ScmpCtx, call string, action int, args ...string) error {
44+
_, exists := ctx.CallMap[call]
45+
if exists {
46+
return errors.New("syscall exist")
47+
}
48+
49+
//fmt.Printf("%s\n", call)
50+
51+
sysCall, sysExists := SyscallMap[call]
52+
if sysExists {
53+
ctx.CallMap[call] = Action{sysCall, action, args}
54+
return nil
55+
}
56+
return errors.New("syscall not surport")
57+
}
58+
59+
func ScmpDel(ctx *ScmpCtx, call string) error {
60+
_, exists := ctx.CallMap[call]
61+
if exists {
62+
delete(ctx.CallMap, call)
63+
return nil
64+
}
65+
66+
return errors.New("syscall not exist")
67+
}
68+
69+
func ScmpBpfStmt(code uint16, k uint32) sockFilter {
70+
return sockFilter{code, 0, 0, k}
71+
}
72+
73+
func ScmpBpfJump(code uint16, k uint32, jt, jf uint8) sockFilter {
74+
return sockFilter{code, jt, jf, k}
75+
}
76+
77+
func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
78+
_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
79+
if e1 != 0 {
80+
err = e1
81+
}
82+
return nil
83+
}
84+
85+
func scmpfilter(prog *sockFprog) (err error) {
86+
_, _, e1 := syscall.Syscall(syscall.SYS_PRCTL, uintptr(syscall.PR_SET_SECCOMP),
87+
uintptr(SECCOMP_MODE_FILTER), uintptr(unsafe.Pointer(prog)))
88+
if e1 != 0 {
89+
err = e1
90+
}
91+
return nil
92+
}
93+
94+
func ScmpLoad(ctx *ScmpCtx) error {
95+
for key := range SyscallMapMin {
96+
ScmpAdd(ctx, key, ScmpActAllow)
97+
}
98+
99+
num := len(ctx.CallMap)
100+
filter := make([]sockFilter, num*2+3)
101+
102+
i := 0
103+
filter[i] = ScmpBpfStmt(syscall.BPF_LD+syscall.BPF_W+syscall.BPF_ABS, 0)
104+
i++
105+
106+
for _, value := range ctx.CallMap {
107+
filter[i] = ScmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, value.syscall, 0, 1)
108+
i++
109+
filter[i] = ScmpBpfStmt(syscall.BPF_RET+syscall.BPF_K, SECCOMP_RET_ALLOW)
110+
i++
111+
}
112+
113+
filter[i] = ScmpBpfStmt(syscall.BPF_RET+syscall.BPF_K, SECCOMP_RET_TRAP)
114+
i++
115+
filter[i] = ScmpBpfStmt(syscall.BPF_RET+syscall.BPF_K, SECCOMP_RET_KILL)
116+
i++
117+
118+
prog := sockFprog{
119+
len: uint16(i),
120+
filt: filter,
121+
}
122+
123+
if nil != prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) {
124+
fmt.Println("prctl PR_SET_NO_NEW_PRIVS error")
125+
return errors.New("prctl PR_SET_NO_NEW_PRIVS error")
126+
}
127+
128+
if nil != scmpfilter(&prog) {
129+
fmt.Println("scmpfilter error")
130+
return errors.New("scmpfilter error")
131+
}
132+
return nil
133+
}

0 commit comments

Comments
 (0)