`--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>
| ... | ... |
@@ -22,7 +22,11 @@ func WithSeccomp(daemon *Daemon, c *container.Container) coci.SpecOpts {
|
| 22 | 22 |
return nil |
| 23 | 23 |
} |
| 24 | 24 |
if c.HostConfig.Privileged {
|
| 25 |
- return nil |
|
| 25 |
+ var err error |
|
| 26 |
+ if c.SeccompProfile != "" {
|
|
| 27 |
+ s.Linux.Seccomp, err = seccomp.LoadProfile(c.SeccompProfile, s) |
|
| 28 |
+ } |
|
| 29 |
+ return err |
|
| 26 | 30 |
} |
| 27 | 31 |
if !daemon.RawSysInfo().Seccomp {
|
| 28 | 32 |
if c.SeccompProfile != "" && c.SeccompProfile != dconfig.SeccompProfileDefault {
|
| ... | ... |
@@ -40,7 +40,9 @@ func TestWithSeccomp(t *testing.T) {
|
| 40 | 40 |
outSpec: oci.DefaultLinuxSpec(), |
| 41 | 41 |
}, |
| 42 | 42 |
{
|
| 43 |
- comment: "privileged container w/ custom profile runs unconfined", |
|
| 43 |
+ // Prior to Docker v27, it had resulted in unconfined. |
|
| 44 |
+ // https://github.com/moby/moby/pull/47500 |
|
| 45 |
+ comment: "privileged container w/ custom profile", |
|
| 44 | 46 |
daemon: &Daemon{
|
| 45 | 47 |
sysInfo: &sysinfo.SysInfo{Seccomp: true},
|
| 46 | 48 |
}, |
| ... | ... |
@@ -50,8 +52,15 @@ func TestWithSeccomp(t *testing.T) {
|
| 50 | 50 |
Privileged: true, |
| 51 | 51 |
}, |
| 52 | 52 |
}, |
| 53 |
- inSpec: oci.DefaultLinuxSpec(), |
|
| 54 |
- outSpec: oci.DefaultLinuxSpec(), |
|
| 53 |
+ inSpec: oci.DefaultLinuxSpec(), |
|
| 54 |
+ outSpec: func() coci.Spec {
|
|
| 55 |
+ s := oci.DefaultLinuxSpec() |
|
| 56 |
+ profile := &specs.LinuxSeccomp{
|
|
| 57 |
+ DefaultAction: specs.LinuxSeccompAction("SCMP_ACT_LOG"),
|
|
| 58 |
+ } |
|
| 59 |
+ s.Linux.Seccomp = profile |
|
| 60 |
+ return s |
|
| 61 |
+ }(), |
|
| 55 | 62 |
}, |
| 56 | 63 |
{
|
| 57 | 64 |
comment: "privileged container w/ default runs unconfined", |
| ... | ... |
@@ -353,6 +353,51 @@ func TestWorkingDirNormalization(t *testing.T) {
|
| 353 | 353 |
|
| 354 | 354 |
assert.Check(t, is.Equal(inspect.Config.WorkingDir, "/tmp")) |
| 355 | 355 |
}) |
| 356 |
+ } |
|
| 357 |
+} |
|
| 358 |
+ |
|
| 359 |
+func TestSeccomp(t *testing.T) {
|
|
| 360 |
+ skip.If(t, testEnv.DaemonInfo.OSType != "linux") |
|
| 361 |
+ |
|
| 362 |
+ ctx := setupTest(t) |
|
| 363 |
+ apiClient := testEnv.APIClient() |
|
| 356 | 364 |
|
| 365 |
+ const confined = `{
|
|
| 366 |
+ "defaultAction": "SCMP_ACT_ALLOW", |
|
| 367 |
+ "syscalls": [ { "names": [ "chown", "chown32", "fchownat" ], "action": "SCMP_ACT_ERRNO" } ]
|
|
| 368 |
+} |
|
| 369 |
+` |
|
| 370 |
+ type testCase struct {
|
|
| 371 |
+ ops []func(*container.TestContainerConfig) |
|
| 372 |
+ expectedExitCode int |
|
| 373 |
+ } |
|
| 374 |
+ testCases := []testCase{
|
|
| 375 |
+ {
|
|
| 376 |
+ ops: nil, |
|
| 377 |
+ expectedExitCode: 0, |
|
| 378 |
+ }, |
|
| 379 |
+ {
|
|
| 380 |
+ ops: []func(*container.TestContainerConfig){container.WithPrivileged(true)},
|
|
| 381 |
+ expectedExitCode: 0, |
|
| 382 |
+ }, |
|
| 383 |
+ {
|
|
| 384 |
+ ops: []func(*container.TestContainerConfig){container.WithSecurityOpt("seccomp=" + confined)},
|
|
| 385 |
+ expectedExitCode: 1, |
|
| 386 |
+ }, |
|
| 387 |
+ {
|
|
| 388 |
+ // A custom profile should be still enabled, even when --privileged is set |
|
| 389 |
+ // https://github.com/moby/moby/issues/47499 |
|
| 390 |
+ ops: []func(*container.TestContainerConfig){container.WithPrivileged(true), container.WithSecurityOpt("seccomp=" + confined)},
|
|
| 391 |
+ expectedExitCode: 1, |
|
| 392 |
+ }, |
|
| 393 |
+ } |
|
| 394 |
+ for _, tc := range testCases {
|
|
| 395 |
+ cID := container.Run(ctx, t, apiClient, tc.ops...) |
|
| 396 |
+ res, err := container.Exec(ctx, apiClient, cID, []string{"chown", "42", "/bin/true"})
|
|
| 397 |
+ assert.NilError(t, err) |
|
| 398 |
+ assert.Equal(t, tc.expectedExitCode, res.ExitCode) |
|
| 399 |
+ if tc.expectedExitCode != 0 {
|
|
| 400 |
+ assert.Check(t, is.Contains(res.Stderr(), "Operation not permitted")) |
|
| 401 |
+ } |
|
| 357 | 402 |
} |
| 358 | 403 |
} |