在 child 中安装 seccomp 过滤器
Install seccomp filter in child
我想知道是否可以在 Go 程序的 child 进程中安装 seccomp 过滤器。目前我正在生成 child 过程如下:
cmd := exec.Command(target)
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &unix.SysProcAttr{
Ptrace: true,
}
cmd.Start()
cmd.Wait()
这很好用,SysProcAttr
提供了一种在 child 进程中启用 Ptrace 的机制。但是,似乎不支持在 child 中安装 seccomp 过滤器。我知道 https://github.com/elastic/go-seccomp-bpf and https://github.com/seccomp/libseccomp-golang 但这些库似乎只支持在当前进程中安装 seccomp 过滤器(以及从当前进程产生的任何 children)。我只想在 child 中安装过滤器,而不是 parent,因为我不希望 parent 也被沙盒化。
在 C 中,在 child 进程中安装 seccomp 过滤器的机制是 fork,在当前进程(从 child 中)安装过滤器,然后执行。但是,在 Go 中似乎不支持像这样分离 fork 和 exec。有什么办法解决这个问题,还是我需要使用 C 来正确执行此操作?
是否可以扩展 SysProcAttr
以允许 seccomp 过滤器,或者允许 运行 在 fork 之后和 exec 之前的任意代码(在某些时候我假设它调用 fork 然后调用 exec)?我将如何实施它?
我使用此处的 forkexec
包解决了这个问题:https://godoc.org/github.com/criyle/go-sandbox/pkg/forkexec 和 elastic/go-seccomp-bpf
。 Seccomp 过滤器可以这样安装:
import bseccomp "github.com/elastic/go-seccomp-bpf"
import "github.com/criyle/go-sandbox/pkg/forkexec"
// ...
policy := bseccomp.Policy{
DefaultAction: bseccomp.ActionAllow,
Syscalls: []bseccomp.SyscallGroup{
{
Action: bseccomp.ActionTrace,
Names: []string{
"write",
},
},
},
}
program, err := policy.Assemble()
must(err)
filter, err := ExportBPF(program)
must(err)
bin, err := os.Open(args[0])
must(err)
cmd := forkexec.Runner{
Args: args[0:],
ExecFile: bin.Fd(),
Seccomp: filter.SockFprog(),
StopBeforeSeccomp: true,
Ptrace: true,
}
pid, err := cmd.Start()
must(err)
var ws unix.WaitStatus
_, err = unix.Wait4(pid, &ws, 0, nil)
must(err)
这需要使用 criyle/go-sandbox/pkg/seccomp
包的一些额外功能。
// ExportBPF convert libseccomp filter to kernel readable BPF content
func ExportBPF(filter []bpf.Instruction) (seccomp.Filter, error) {
raw, err := bpf.Assemble(filter)
if err != nil {
return nil, err
}
return sockFilter(raw), nil
}
func sockFilter(raw []bpf.RawInstruction) []syscall.SockFilter {
filter := make([]syscall.SockFilter, 0, len(raw))
for _, instruction := range raw {
filter = append(filter, syscall.SockFilter{
Code: instruction.Op,
Jt: instruction.Jt,
Jf: instruction.Jf,
K: instruction.K,
})
}
return filter
}
我想知道是否可以在 Go 程序的 child 进程中安装 seccomp 过滤器。目前我正在生成 child 过程如下:
cmd := exec.Command(target)
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &unix.SysProcAttr{
Ptrace: true,
}
cmd.Start()
cmd.Wait()
这很好用,SysProcAttr
提供了一种在 child 进程中启用 Ptrace 的机制。但是,似乎不支持在 child 中安装 seccomp 过滤器。我知道 https://github.com/elastic/go-seccomp-bpf and https://github.com/seccomp/libseccomp-golang 但这些库似乎只支持在当前进程中安装 seccomp 过滤器(以及从当前进程产生的任何 children)。我只想在 child 中安装过滤器,而不是 parent,因为我不希望 parent 也被沙盒化。
在 C 中,在 child 进程中安装 seccomp 过滤器的机制是 fork,在当前进程(从 child 中)安装过滤器,然后执行。但是,在 Go 中似乎不支持像这样分离 fork 和 exec。有什么办法解决这个问题,还是我需要使用 C 来正确执行此操作?
是否可以扩展 SysProcAttr
以允许 seccomp 过滤器,或者允许 运行 在 fork 之后和 exec 之前的任意代码(在某些时候我假设它调用 fork 然后调用 exec)?我将如何实施它?
我使用此处的 forkexec
包解决了这个问题:https://godoc.org/github.com/criyle/go-sandbox/pkg/forkexec 和 elastic/go-seccomp-bpf
。 Seccomp 过滤器可以这样安装:
import bseccomp "github.com/elastic/go-seccomp-bpf"
import "github.com/criyle/go-sandbox/pkg/forkexec"
// ...
policy := bseccomp.Policy{
DefaultAction: bseccomp.ActionAllow,
Syscalls: []bseccomp.SyscallGroup{
{
Action: bseccomp.ActionTrace,
Names: []string{
"write",
},
},
},
}
program, err := policy.Assemble()
must(err)
filter, err := ExportBPF(program)
must(err)
bin, err := os.Open(args[0])
must(err)
cmd := forkexec.Runner{
Args: args[0:],
ExecFile: bin.Fd(),
Seccomp: filter.SockFprog(),
StopBeforeSeccomp: true,
Ptrace: true,
}
pid, err := cmd.Start()
must(err)
var ws unix.WaitStatus
_, err = unix.Wait4(pid, &ws, 0, nil)
must(err)
这需要使用 criyle/go-sandbox/pkg/seccomp
包的一些额外功能。
// ExportBPF convert libseccomp filter to kernel readable BPF content
func ExportBPF(filter []bpf.Instruction) (seccomp.Filter, error) {
raw, err := bpf.Assemble(filter)
if err != nil {
return nil, err
}
return sockFilter(raw), nil
}
func sockFilter(raw []bpf.RawInstruction) []syscall.SockFilter {
filter := make([]syscall.SockFilter, 0, len(raw))
for _, instruction := range raw {
filter = append(filter, syscall.SockFilter{
Code: instruction.Op,
Jt: instruction.Jt,
Jf: instruction.Jf,
K: instruction.K,
})
}
return filter
}