Add command-line tool to quickly dump the Sentry BPF program.

PiperOrigin-RevId: 573994110
This commit is contained in:
Etienne Perot
2023-10-16 19:16:26 -07:00
committed by gVisor bot
parent 15fdd74e5c
commit e69b01c3a8
4 changed files with 176 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
load("//tools:defs.bzl", "go_binary", "go_test")
package(
default_applicable_licenses = ["//:license"],
licenses = ["notice"],
)
go_binary(
name = "dumpfilter",
srcs = [
"dumpfilter.go",
"dumpfilter_unsafe.go",
],
deps = [
"//pkg/abi/linux",
"//pkg/bpf",
"//pkg/log",
"//pkg/seccomp",
"//pkg/sentry/platform/systrap",
"//runsc/boot/filter",
"//runsc/flag",
],
)
go_test(
name = "dumpfilter_test",
srcs = ["dumpfilter_test.go"],
data = [":dumpfilter"],
deps = ["//pkg/test/testutil"],
)
@@ -0,0 +1,80 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// dumpfilter dumps the seccomp-bpf program used by the Sentry.
package main
import (
"fmt"
"os"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/bpf"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/seccomp"
"gvisor.dev/gvisor/pkg/sentry/platform/systrap"
"gvisor.dev/gvisor/runsc/boot/filter"
"gvisor.dev/gvisor/runsc/flag"
)
// Flags.
var (
output = flag.String("output", "fancy", "Output type: 'fancy' (human-readable with line numbers resolved), 'plain' (diffable but still human-readable output), 'bytecode' (dump raw bytecode)")
nvproxy = flag.Bool("nvproxy", false, "Enable nvproxy in filter configuration")
)
func main() {
flag.Parse()
rules, denyRules := filter.Rules(filter.Options{
Platform: &systrap.Systrap{},
NVProxy: *nvproxy,
})
insns, stats, err := seccomp.BuildProgram([]seccomp.RuleSet{
{
Rules: denyRules,
Action: linux.SECCOMP_RET_ERRNO,
},
{
Rules: rules,
Action: linux.SECCOMP_RET_ALLOW,
},
}, linux.SECCOMP_RET_ERRNO, linux.SECCOMP_RET_ERRNO)
if err != nil {
log.Warningf("%v", err)
os.Exit(1)
}
log.Infof("Size before optimizations: %d", stats.SizeBeforeOptimizations)
log.Infof("Size after optimizations: %d", stats.SizeAfterOptimizations)
log.Infof("Build duration: %v", stats.BuildDuration)
log.Infof("Optimization passes duration: %v", stats.OptimizeDuration)
log.Infof("Total duration: %v", stats.BuildDuration+stats.OptimizeDuration)
switch *output {
case "fancy":
dump, err := bpf.DecodeInstructions(insns)
if err != nil {
log.Warningf("%v", err)
os.Exit(1)
}
fmt.Print(dump)
case "plain":
for _, ins := range insns {
fmt.Println(ins.String())
}
case "bytecode":
if _, err := os.Stdout.WriteString(InstructionsToBytecode(insns)); err != nil {
log.Warningf("cannot write bytecode to stdout: %v", err)
os.Exit(1)
}
}
}
@@ -0,0 +1,38 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package dumpfilter_test
import (
"os/exec"
"strings"
"testing"
"gvisor.dev/gvisor/pkg/test/testutil"
)
// TestDumpFilter tests that the `dumpfilter` program works.
func TestDumpFilter(t *testing.T) {
binPath, err := testutil.FindFile("runsc/boot/filter/dumpfilter/dumpfilter")
if err != nil {
t.Fatalf("cannot locate dumpfilter: %v", err)
}
output, err := exec.Command(binPath).CombinedOutput()
for _, line := range strings.Split(string(output), "\n") {
t.Log(line)
}
if err != nil {
t.Errorf("program failed: %v", err)
}
}
@@ -0,0 +1,28 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// dumpfilter dumps the seccomp-bpf program used by the Sentry.
package main
import (
"unsafe"
"gvisor.dev/gvisor/pkg/bpf"
)
// InstructionsToBytecode returns raw the BPF bytecode for the given program.
func InstructionsToBytecode(insns []bpf.Instruction) string {
bytePointer := (*byte)(unsafe.Pointer(&insns[0]))
return unsafe.String(bytePointer, len(insns)*int(unsafe.Sizeof(bpf.Instruction{})))
}