seccomp: allow specifying a custom profile with --privileged

`--privileged --security-opt seccomp=<CUSTOM.json>` was ignoring
`<CUSTOM.json>`.

Fix issue 47499

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2024-03-05 23:37:29 +09:00
parent 046827c657
commit 46119ea631
No known key found for this signature in database
GPG key ID: 49524C6F9F638F1A
3 changed files with 63 additions and 4 deletions

View file

@ -22,7 +22,11 @@ func WithSeccomp(daemon *Daemon, c *container.Container) coci.SpecOpts {
return nil
}
if c.HostConfig.Privileged {
return nil
var err error
if c.SeccompProfile != "" {
s.Linux.Seccomp, err = seccomp.LoadProfile(c.SeccompProfile, s)
}
return err
}
if !daemon.RawSysInfo().Seccomp {
if c.SeccompProfile != "" && c.SeccompProfile != dconfig.SeccompProfileDefault {

View file

@ -40,7 +40,9 @@ func TestWithSeccomp(t *testing.T) {
outSpec: oci.DefaultLinuxSpec(),
},
{
comment: "privileged container w/ custom profile runs unconfined",
// Prior to Docker v26, it had resulted in unconfined.
// https://github.com/moby/moby/pull/47500
comment: "privileged container w/ custom profile",
daemon: &Daemon{
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
@ -50,8 +52,15 @@ func TestWithSeccomp(t *testing.T) {
Privileged: true,
},
},
inSpec: oci.DefaultLinuxSpec(),
outSpec: oci.DefaultLinuxSpec(),
inSpec: oci.DefaultLinuxSpec(),
outSpec: func() coci.Spec {
s := oci.DefaultLinuxSpec()
profile := &specs.LinuxSeccomp{
DefaultAction: specs.LinuxSeccompAction("SCMP_ACT_LOG"),
}
s.Linux.Seccomp = profile
return s
}(),
},
{
comment: "privileged container w/ default runs unconfined",

View file

@ -326,3 +326,49 @@ func TestStaticIPOutsideSubpool(t *testing.T) {
assert.Check(t, is.Contains(b.String(), "inet 10.42.1.3/16"))
}
func TestSeccomp(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
ctx := setupTest(t)
apiClient := testEnv.APIClient()
const confined = `{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [ { "names": [ "connect" ], "action": "SCMP_ACT_ERRNO" } ]
}
`
type testCase struct {
ops []func(*container.TestContainerConfig)
expectedExitCode int
}
testCases := []testCase{
{
ops: nil,
expectedExitCode: 0,
},
{
ops: []func(*container.TestContainerConfig){container.WithPrivileged(true)},
expectedExitCode: 0,
},
{
ops: []func(*container.TestContainerConfig){container.WithSecurityOpt("seccomp=" + confined)},
expectedExitCode: 1,
},
{
// A custom profile should be still enabled, even when --privileged is set
// https://github.com/moby/moby/issues/47499
ops: []func(*container.TestContainerConfig){container.WithPrivileged(true), container.WithSecurityOpt("seccomp=" + confined)},
expectedExitCode: 1,
},
}
for _, tc := range testCases {
cID := container.Run(ctx, t, apiClient, tc.ops...)
res, err := container.Exec(ctx, apiClient, cID, []string{"wget", "-O-", "http://1.1.1.1"})
assert.NilError(t, err)
assert.Equal(t, tc.expectedExitCode, res.ExitCode)
if tc.expectedExitCode != 0 {
assert.Check(t, is.Contains(res.Stderr(), "Operation not permitted"))
}
}
}