Skip to content

Commit e2588d7

Browse files
committed
Merge pull request #12692 from dany74q:exec-seccomp-filters
PiperOrigin-RevId: 889399059
2 parents e99e98c + 9b9db9a commit e2588d7

6 files changed

Lines changed: 154 additions & 23 deletions

File tree

‎pkg/sentry/control/BUILD‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ go_library(
3636
deps = [
3737
":control_api_go_proto",
3838
"//pkg/abi/linux",
39+
"//pkg/bpf",
3940
"//pkg/cleanup",
4041
"//pkg/context",
4142
"//pkg/eventchannel",

‎pkg/sentry/control/proc.go‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"gvisor.dev/gvisor/pkg/abi/linux"
28+
"gvisor.dev/gvisor/pkg/bpf"
2829
"gvisor.dev/gvisor/pkg/cleanup"
2930
"gvisor.dev/gvisor/pkg/fd"
3031
"gvisor.dev/gvisor/pkg/log"
@@ -152,6 +153,10 @@ type ExecArgs struct {
152153

153154
// Limits is the limit set for the process being executed.
154155
Limits *limits.LimitSet
156+
157+
// SeccompProgram is an optional seccomp BPF program to install on the
158+
// new process.
159+
SeccompProgram *bpf.Program
155160
}
156161

157162
// String prints the arguments as a string.
@@ -319,6 +324,13 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
319324
return nil, 0, nil, err
320325
}
321326

327+
if args.SeccompProgram != nil {
328+
task := tg.Leader()
329+
if err := task.AppendSyscallFilter(*args.SeccompProgram, true); err != nil {
330+
return nil, 0, nil, fmt.Errorf("appending seccomp filters: %w", err)
331+
}
332+
}
333+
322334
// Start the newly created process.
323335
proc.Kernel.StartProcess(tg)
324336

‎runsc/boot/BUILD‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ go_library(
2626
"restore.go",
2727
"restore_impl.go",
2828
"seccheck.go",
29+
"seccomp.go",
2930
"strace.go",
3031
"vfs.go",
3132
],

‎runsc/boot/loader.go‎

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
specs "github.com/opencontainers/runtime-spec/specs-go"
2929
"golang.org/x/sys/unix"
3030
"gvisor.dev/gvisor/pkg/abi/linux"
31-
"gvisor.dev/gvisor/pkg/bpf"
3231
"gvisor.dev/gvisor/pkg/cleanup"
3332
"gvisor.dev/gvisor/pkg/context"
3433
"gvisor.dev/gvisor/pkg/coverage"
@@ -84,7 +83,6 @@ import (
8483
"gvisor.dev/gvisor/runsc/config"
8584
"gvisor.dev/gvisor/runsc/profile"
8685
"gvisor.dev/gvisor/runsc/specutils"
87-
"gvisor.dev/gvisor/runsc/specutils/seccomp"
8886

8987
// Top-level inet providers.
9088
"gvisor.dev/gvisor/pkg/sentry/socket/hostinet"
@@ -1361,27 +1359,15 @@ func (l *Loader) createContainerProcess(info *containerInfo) (*kernel.ThreadGrou
13611359
info.procArgs.FDTable.DecRef(ctx)
13621360

13631361
// Install seccomp filters with the new task if there are any.
1364-
if info.conf.OCISeccomp {
1365-
if info.spec.Linux != nil && info.spec.Linux.Seccomp != nil {
1366-
program, err := seccomp.BuildProgram(info.spec.Linux.Seccomp)
1367-
if err != nil {
1368-
return nil, nil, fmt.Errorf("building seccomp program: %w", err)
1369-
}
1370-
1371-
if log.IsLogging(log.Debug) {
1372-
out, _ := bpf.DecodeProgram(program)
1373-
log.Debugf("Installing OCI seccomp filters\nProgram:\n%s", out)
1374-
}
1375-
1376-
task := tg.Leader()
1377-
// NOTE: It seems Flags are ignored by runc so we ignore them too.
1378-
if err := task.AppendSyscallFilter(program, true); err != nil {
1379-
return nil, nil, fmt.Errorf("appending seccomp filters: %w", err)
1380-
}
1381-
}
1382-
} else {
1383-
if info.spec.Linux != nil && info.spec.Linux.Seccomp != nil {
1384-
log.Warningf("Seccomp spec is being ignored")
1362+
program, err := buildOCISeccompProgram(info.conf, info.spec)
1363+
if err != nil {
1364+
return nil, nil, err
1365+
}
1366+
if program != nil {
1367+
task := tg.Leader()
1368+
// NOTE: It seems Flags are ignored by runc so we ignore them too.
1369+
if err := task.AppendSyscallFilter(*program, true); err != nil {
1370+
return nil, nil, fmt.Errorf("appending seccomp filters: %w", err)
13851371
}
13861372
}
13871373

@@ -1524,6 +1510,16 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
15241510
return 0, fmt.Errorf("creating limits: %w", err)
15251511
}
15261512

1513+
containerName := l.k.ContainerName(args.ContainerID)
1514+
spec := l.containerSpecs[containerName]
1515+
if spec != nil {
1516+
seccompProgram, err := buildOCISeccompProgram(l.root.conf, spec)
1517+
if err != nil {
1518+
return 0, err
1519+
}
1520+
args.SeccompProgram = seccompProgram
1521+
}
1522+
15271523
// Start the process.
15281524
proc := control.Proc{Kernel: l.k}
15291525
newTG, tgid, ttyFile, err := control.ExecAsync(&proc, args)

‎runsc/boot/seccomp.go‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2026 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package boot
16+
17+
import (
18+
"fmt"
19+
20+
specs "github.com/opencontainers/runtime-spec/specs-go"
21+
22+
"gvisor.dev/gvisor/pkg/bpf"
23+
"gvisor.dev/gvisor/pkg/log"
24+
"gvisor.dev/gvisor/runsc/config"
25+
"gvisor.dev/gvisor/runsc/specutils/seccomp"
26+
)
27+
28+
func buildOCISeccompProgram(conf *config.Config, spec *specs.Spec) (*bpf.Program, error) {
29+
if !conf.OCISeccomp {
30+
if spec.Linux != nil && spec.Linux.Seccomp != nil {
31+
log.Warningf("Seccomp spec is being ignored because oci-seccomp is disabled")
32+
}
33+
return nil, nil
34+
}
35+
36+
if spec.Linux == nil || spec.Linux.Seccomp == nil {
37+
return nil, nil
38+
}
39+
40+
program, err := seccomp.BuildProgram(spec.Linux.Seccomp)
41+
if err != nil {
42+
return nil, fmt.Errorf("building seccomp program: %w", err)
43+
}
44+
45+
if log.IsLogging(log.Debug) {
46+
out, _ := bpf.DecodeProgram(program)
47+
log.Debugf("Installing OCI seccomp filters\nProgram:\n%s", out)
48+
}
49+
50+
return &program, nil
51+
}

‎runsc/container/multi_container_test.go‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,3 +3309,73 @@ func TestFSCheckpointCommand(t *testing.T) {
33093309
t.Errorf("Error waiting for FS restore: %v", err)
33103310
}
33113311
}
3312+
3313+
func TestMultiContainerExecSeccomp(t *testing.T) {
3314+
rootDir, cleanup, err := testutil.SetupRootDir()
3315+
if err != nil {
3316+
t.Fatalf("error creating root dir: %v", err)
3317+
}
3318+
defer cleanup()
3319+
3320+
conf := testutil.TestConfig(t)
3321+
conf.RootDir = rootDir
3322+
conf.OCISeccomp = true
3323+
3324+
testSpecs, ids := createSpecs(sleepCmd, sleepCmd)
3325+
3326+
// Container 0 (sandbox root): Block "uname" syscall.
3327+
testSpecs[0].Linux = &specs.Linux{
3328+
Seccomp: &specs.LinuxSeccomp{
3329+
DefaultAction: specs.ActAllow,
3330+
Syscalls: []specs.LinuxSyscall{
3331+
{
3332+
Names: []string{"uname"},
3333+
Action: specs.ActErrno,
3334+
},
3335+
},
3336+
},
3337+
}
3338+
3339+
// Container 1 (sub-container): Block "getdents64" syscall.
3340+
testSpecs[1].Linux = &specs.Linux{
3341+
Seccomp: &specs.LinuxSeccomp{
3342+
DefaultAction: specs.ActAllow,
3343+
Syscalls: []specs.LinuxSyscall{
3344+
{
3345+
Names: []string{"getdents", "getdents64"},
3346+
Action: specs.ActErrno,
3347+
},
3348+
},
3349+
},
3350+
}
3351+
3352+
containers, cleanup, err := startContainers(conf, testSpecs, ids)
3353+
if err != nil {
3354+
t.Fatalf("error starting containers: %v", err)
3355+
}
3356+
defer cleanup()
3357+
3358+
// Container 0: "uname" should be blocked.
3359+
_, err = executeCombinedOutput(conf, containers[0], nil, "/bin/uname")
3360+
if err == nil {
3361+
t.Errorf("uname in container 0 should have failed, but succeeded")
3362+
}
3363+
3364+
// Container 0: "getdents64" should not be blocked.
3365+
_, err = executeCombinedOutput(conf, containers[0], nil, "/bin/ls", "/")
3366+
if err != nil {
3367+
t.Errorf("ls in container 0 should have succeeded: %v", err)
3368+
}
3369+
3370+
// Container 1: "getdents64" should be blocked.
3371+
_, err = executeCombinedOutput(conf, containers[1], nil, "/bin/ls", "/")
3372+
if err == nil {
3373+
t.Errorf("ls in container 1 should have failed, but succeeded")
3374+
}
3375+
3376+
// Container 1: "uname" should not be blocked.
3377+
_, err = executeCombinedOutput(conf, containers[1], nil, "/bin/uname")
3378+
if err != nil {
3379+
t.Errorf("uname in container 1 should have succeeded: %v", err)
3380+
}
3381+
}

0 commit comments

Comments
 (0)