【问题标题】:Install seccomp filter in child在孩子中安装 seccomp 过滤器
【发布时间】:2020-12-05 01:56:01
【问题描述】:

我想知道是否可以在 Go 程序的子进程中安装 seccomp 过滤器。目前我正在生成子进程如下:

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 提供了一种在子进程中启用 Ptrace 的机制。但是,似乎不支持在孩子中安装 seccomp 过滤器。我知道https://github.com/elastic/go-seccomp-bpfhttps://github.com/seccomp/libseccomp-golang,但这些库似乎只支持在当前进程(以及从当前进程产生的任何子进程)中安装 seccomp 过滤器。我只想在子级而不是父级中安装过滤器,因为我不希望父级也被沙箱化。

在 C 中,在子进程中安装 seccomp 过滤器的机制是分叉,在当前进程中安装过滤器(从子进程中),然后执行。但是,在 Go 中似乎不支持像这样分离 fork 和 exec。有什么办法可以解决这个问题,还是我需要使用 C 来正确执行此操作?

SysProcAttr 是否可以扩展为允许 seccomp 过滤器,或者允许在 fork 之后和 exec 之前运行任意代码(在某些时候我假设它调用 fork 然后 exec)?我将如何实施?

【问题讨论】:

    标签: linux go ptrace seccomp


    【解决方案1】:

    我通过使用此处的forkexec 包解决了这个问题:https://godoc.org/github.com/criyle/go-sandbox/pkg/forkexecelastic/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
    }
    

    【讨论】:

      猜你喜欢
      • 2023-02-08
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多