Package: release.debian.org Severity: normal Tags: bullseye moreinfo User: release.debian....@packages.debian.org Usertags: pu X-Debbugs-Cc: z...@debian.org, arna...@kali.org, t...@security.debian.org
[ Reason ] Backport 3 CVE patches. + CVE-2021-41089: Create parent directories inside a chroot during docker cp to prevent a specially crafted container from changing permissions of existing files in the host’s filesystem. + CVE-2021-41091: Lock down file permissions to prevent unprivileged users from discovering and executing programs in /var/lib/docker. + CVE-2021-41092: Ensure default auth config has address field set, to prevent credentials being sent to the default registry. (Closes: #998292) And backport 1 patch to run container which uses "clone3" syscall (for example glibc 2.34) [ Impact ] Except the security patches, user will not able to run container like fedora:rawhide, ubuntu:impish (same reason with containerd) without disabling seccomp(lost security protect). [ Tests ] + CVE-2021-41089 I haven't figured out how to trigger the bug, but the patch is backported without modification from upstream 20.10 branch. + CVE-2021-41091 I have verified the patch. With the patch, non-root user is not able to run setuid file in /var/lib/docker. + CVE-2021-41092 this patch includes upstream unit test. + "clone3" patch I have installed it on bullseye vm and succefully run following command: docker run --rm -it registry.fedoraproject.org/fedora:rawhide /usr/bin/curl www.debian.org Without the patch, this command will fail. [ Risks ] The 3 CVE patches are backported from upstream 20.10 branch without modification. The "clone3" patch is backported with modification, since upstream patch fails on mips64el and mipsel. But the modification is also provided by upstream, although they decided not to merged into 20.10 branch, since they want to fix it in conainer spec, which would take long time. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] * Backport patches for CVE-2021-41089 CVE-2021-41091 CVE-2021-41092 + CVE-2021-41089: Create parent directories inside a chroot during docker cp to prevent a specially crafted container from changing permissions of existing files in the host’s filesystem. + CVE-2021-41091: Lock down file permissions to prevent unprivileged users from discovering and executing programs in /var/lib/docker. + CVE-2021-41092: Ensure default auth config has address field set, to prevent credentials being sent to the default registry. (Closes: #998292) * Backport "clone3" syscall workaround in default seccomp policy (Closes: #995191) [ Other info ] + Please build docker.io after containerd/1.4.12~ds1-1~deb11u1 has been built. So the RPi1/RPi0 workaround(#998909) will be used. + The "clone3" hasn't been in testing yet(due to FTBFS on mips64el/mipsel previously, but I have fixed it in docker.io/20.10.11+dfsg1-2. It will hopefully migrate to testing in 5 days). So I have added the moreinfo tag.
diff -Nru docker.io-20.10.5+dfsg1/debian/changelog docker.io-20.10.5+dfsg1/debian/changelog --- docker.io-20.10.5+dfsg1/debian/changelog 2021-03-10 00:53:21.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/changelog 2021-12-04 18:53:03.000000000 +0800 @@ -1,3 +1,18 @@ +docker.io (20.10.5+dfsg1-1+deb11u1) bullseye; urgency=medium + + * Backport patches for CVE-2021-41089 CVE-2021-41091 CVE-2021-41092 + + CVE-2021-41089: Create parent directories inside a chroot during docker + cp to prevent a specially crafted container from changing permissions of + existing files in the host’s filesystem. + + CVE-2021-41091: Lock down file permissions to prevent unprivileged users + from discovering and executing programs in /var/lib/docker. + + CVE-2021-41092: Ensure default auth config has address field set, to + prevent credentials being sent to the default registry. (Closes: #998292) + * Backport "clone3" syscall workaround in default seccomp policy + (Closes: #995191) + + -- Shengjing Zhu <z...@debian.org> Sat, 04 Dec 2021 18:53:03 +0800 + docker.io (20.10.5+dfsg1-1) unstable; urgency=medium * Team upload. diff -Nru docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41089.patch docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41089.patch --- docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41089.patch 1970-01-01 08:00:00.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41089.patch 2021-12-04 18:08:34.000000000 +0800 @@ -0,0 +1,28 @@ +Description: chrootarchive: don't create parent dirs outside of chroot +Origin: backport, https://github.com/moby/moby/commit/80f1169e +--- a/engine/pkg/chrootarchive/archive.go ++++ b/engine/pkg/chrootarchive/archive.go +@@ -74,13 +74,17 @@ + options.ExcludePatterns = []string{} + } + +- idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) +- rootIDs := idMapping.RootPair() ++ // If dest is inside a root then directory is created within chroot by extractor. ++ // This case is only currently used by cp. ++ if dest == root { ++ idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) ++ rootIDs := idMapping.RootPair() + +- dest = filepath.Clean(dest) +- if _, err := os.Stat(dest); os.IsNotExist(err) { +- if err := idtools.MkdirAllAndChownNew(dest, 0755, rootIDs); err != nil { +- return err ++ dest = filepath.Clean(dest) ++ if _, err := os.Stat(dest); os.IsNotExist(err) { ++ if err := idtools.MkdirAllAndChownNew(dest, 0755, rootIDs); err != nil { ++ return err ++ } + } + } + diff -Nru docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41091.patch docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41091.patch --- docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41091.patch 1970-01-01 08:00:00.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41091.patch 2021-12-04 18:17:18.000000000 +0800 @@ -0,0 +1,320 @@ +Description: Lock down docker root dir perms +Origin: backport, https://github.com/moby/moby/commit/93ac040b +--- a/engine/daemon/container_operations_unix.go ++++ b/engine/daemon/container_operations_unix.go +@@ -466,5 +466,5 @@ + if err != nil { + return err + } +- return idtools.MkdirAllAndChown(p, 0701, idtools.CurrentIdentity()) ++ return idtools.MkdirAllAndChown(p, 0710, idtools.Identity{UID: idtools.CurrentIdentity().UID, GID: daemon.IdentityMapping().RootPair().GID}) + } +--- a/engine/daemon/create.go ++++ b/engine/daemon/create.go +@@ -212,10 +212,11 @@ + } + ctr.RWLayer = rwLayer + +- if err := idtools.MkdirAndChown(ctr.Root, 0701, idtools.CurrentIdentity()); err != nil { ++ current := idtools.CurrentIdentity() ++ if err := idtools.MkdirAndChown(ctr.Root, 0710, idtools.Identity{UID: current.UID, GID: daemon.IdentityMapping().RootPair().GID}); err != nil { + return nil, err + } +- if err := idtools.MkdirAndChown(ctr.CheckpointDir(), 0700, idtools.CurrentIdentity()); err != nil { ++ if err := idtools.MkdirAndChown(ctr.CheckpointDir(), 0700, current); err != nil { + return nil, err + } + +--- a/engine/daemon/daemon.go ++++ b/engine/daemon/daemon.go +@@ -861,7 +861,10 @@ + } + + daemonRepo := filepath.Join(config.Root, "containers") +- if err := idtools.MkdirAllAndChown(daemonRepo, 0701, idtools.CurrentIdentity()); err != nil { ++ if err := idtools.MkdirAllAndChown(daemonRepo, 0710, idtools.Identity{ ++ UID: idtools.CurrentIdentity().UID, ++ GID: rootIDs.GID, ++ }); err != nil { + return nil, err + } + +--- a/engine/daemon/daemon_unix.go ++++ b/engine/daemon/daemon_unix.go +@@ -1216,21 +1216,21 @@ + } + } + ++ id := idtools.Identity{UID: idtools.CurrentIdentity().UID, GID: remappedRoot.GID} ++ // First make sure the current root dir has the correct perms. ++ if err := idtools.MkdirAllAndChown(config.Root, 0710, id); err != nil { ++ return errors.Wrapf(err, "could not create or set daemon root permissions: %s", config.Root) ++ } ++ + // if user namespaces are enabled we will create a subtree underneath the specified root + // with any/all specified remapped root uid/gid options on the daemon creating + // a new subdirectory with ownership set to the remapped uid/gid (so as to allow + // `chdir()` to work for containers namespaced to that uid/gid) + if config.RemappedRoot != "" { +- id := idtools.CurrentIdentity() +- // First make sure the current root dir has the correct perms. +- if err := idtools.MkdirAllAndChown(config.Root, 0701, id); err != nil { +- return errors.Wrapf(err, "could not create or set daemon root permissions: %s", config.Root) +- } +- + config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", remappedRoot.UID, remappedRoot.GID)) + logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) + // Create the root directory if it doesn't exist +- if err := idtools.MkdirAllAndChown(config.Root, 0701, id); err != nil { ++ if err := idtools.MkdirAllAndChown(config.Root, 0710, id); err != nil { + return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) + } + // we also need to verify that any pre-existing directories in the path to +--- a/engine/daemon/graphdriver/aufs/aufs.go ++++ b/engine/daemon/graphdriver/aufs/aufs.go +@@ -130,14 +130,23 @@ + } + + currentID := idtools.CurrentIdentity() ++ _, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) ++ if err != nil { ++ return nil, err ++ } ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: rootGID, ++ } ++ + // Create the root aufs driver dir +- if err := idtools.MkdirAllAndChown(root, 0701, currentID); err != nil { ++ if err := idtools.MkdirAllAndChown(root, 0710, dirID); err != nil { + return nil, err + } + + // Populate the dir structure + for _, p := range paths { +- if err := idtools.MkdirAllAndChown(path.Join(root, p), 0701, currentID); err != nil { ++ if err := idtools.MkdirAllAndChown(path.Join(root, p), 0710, dirID); err != nil { + return nil, err + } + } +--- a/engine/daemon/graphdriver/btrfs/btrfs.go ++++ b/engine/daemon/graphdriver/btrfs/btrfs.go +@@ -70,7 +70,14 @@ + return nil, graphdriver.ErrPrerequisites + } + +- if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil { ++ remappedRoot := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps) ++ currentID := idtools.CurrentIdentity() ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: remappedRoot.RootPair().GID, ++ } ++ ++ if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil { + return nil, err + } + +@@ -521,7 +528,14 @@ + if err != nil { + return err + } +- if err := idtools.MkdirAllAndChown(subvolumes, 0701, idtools.CurrentIdentity()); err != nil { ++ ++ currentID := idtools.CurrentIdentity() ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: rootGID, ++ } ++ ++ if err := idtools.MkdirAllAndChown(subvolumes, 0710, dirID); err != nil { + return err + } + if parent == "" { +--- a/engine/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs.go ++++ b/engine/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs.go +@@ -88,7 +88,17 @@ + return nil, graphdriver.ErrNotSupported + } + +- if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0701, idtools.CurrentIdentity()); err != nil { ++ remappedRoot := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps) ++ currentID := idtools.CurrentIdentity() ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: remappedRoot.RootPair().GID, ++ } ++ ++ if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil { ++ return nil, err ++ } ++ if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 700, currentID); err != nil { + return nil, err + } + +@@ -173,11 +183,15 @@ + } + root := idtools.Identity{UID: rootUID, GID: rootGID} + +- currentID := idtools.CurrentIdentity() +- if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, currentID); err != nil { ++ dirID := idtools.Identity{ ++ UID: rootUID, ++ GID: rootGID, ++ } ++ ++ if err := idtools.MkdirAllAndChown(path.Dir(dir), 0710, dirID); err != nil { + return err + } +- if err := idtools.MkdirAndChown(dir, 0701, currentID); err != nil { ++ if err := idtools.MkdirAndChown(dir, 0710, dirID); err != nil { + return err + } + +@@ -211,7 +225,7 @@ + return nil + } + +- if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0701, currentID); err != nil { ++ if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0710, dirID); err != nil { + return err + } + +--- a/engine/daemon/graphdriver/overlay/overlay.go ++++ b/engine/daemon/graphdriver/overlay/overlay.go +@@ -156,11 +156,20 @@ + logrus.WithField("storage-driver", "overlay").Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs)) + } + +- // Create the driver home dir +- if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil { ++ currentID := idtools.CurrentIdentity() ++ _, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) ++ if err != nil { + return nil, err + } ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: rootGID, ++ } + ++ // Create the driver home dir ++ if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil { ++ return nil, err ++ } + d := &Driver{ + home: home, + uidMaps: uidMaps, +@@ -262,10 +271,11 @@ + root := idtools.Identity{UID: rootUID, GID: rootGID} + + currentID := idtools.CurrentIdentity() +- if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, currentID); err != nil { +- return err ++ dirID := idtools.Identity{ ++ UID: currentID.UID, ++ GID: rootGID, + } +- if err := idtools.MkdirAndChown(dir, 0701, currentID); err != nil { ++ if err := idtools.MkdirAndChown(dir, 0710, dirID); err != nil { + return err + } + +--- a/engine/daemon/graphdriver/overlay2/overlay.go ++++ b/engine/daemon/graphdriver/overlay2/overlay.go +@@ -165,7 +165,20 @@ + logger.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs)) + } + +- if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0701, idtools.CurrentIdentity()); err != nil { ++ _, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) ++ if err != nil { ++ return nil, err ++ } ++ ++ cur := idtools.CurrentIdentity() ++ dirID := idtools.Identity{ ++ UID: cur.UID, ++ GID: rootGID, ++ } ++ if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil { ++ return nil, err ++ } ++ if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, cur); err != nil { + return nil, err + } + +@@ -334,12 +347,15 @@ + return err + } + root := idtools.Identity{UID: rootUID, GID: rootGID} +- current := idtools.CurrentIdentity() ++ dirID := idtools.Identity{ ++ UID: idtools.CurrentIdentity().UID, ++ GID: rootGID, ++ } + +- if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, current); err != nil { ++ if err := idtools.MkdirAllAndChown(path.Dir(dir), 0710, dirID); err != nil { + return err + } +- if err := idtools.MkdirAndChown(dir, 0701, current); err != nil { ++ if err := idtools.MkdirAndChown(dir, 0710, dirID); err != nil { + return err + } + +--- a/engine/daemon/graphdriver/vfs/driver.go ++++ b/engine/daemon/graphdriver/vfs/driver.go +@@ -37,8 +37,16 @@ + if err := d.parseOptions(options); err != nil { + return nil, err + } ++ _, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) ++ if err != nil { ++ return nil, err ++ } + +- if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil { ++ dirID := idtools.Identity{ ++ UID: idtools.CurrentIdentity().UID, ++ GID: rootGID, ++ } ++ if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil { + return nil, err + } + +@@ -140,7 +148,12 @@ + func (d *Driver) create(id, parent string, size uint64) error { + dir := d.dir(id) + rootIDs := d.idMapping.RootPair() +- if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0701, idtools.CurrentIdentity()); err != nil { ++ ++ dirID := idtools.Identity{ ++ UID: idtools.CurrentIdentity().UID, ++ GID: rootIDs.GID, ++ } ++ if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0710, dirID); err != nil { + return err + } + if err := idtools.MkdirAndChown(dir, 0755, rootIDs); err != nil { +--- a/engine/daemon/graphdriver/zfs/zfs.go ++++ b/engine/daemon/graphdriver/zfs/zfs.go +@@ -104,7 +104,16 @@ + return nil, fmt.Errorf("BUG: zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName) + } + +- if err := idtools.MkdirAllAndChown(base, 0701, idtools.CurrentIdentity()); err != nil { ++ _, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) ++ if err != nil { ++ return nil, err ++ } ++ ++ dirID := idtools.Identity{ ++ UID: idtools.CurrentIdentity().UID, ++ GID: rootGID, ++ } ++ if err := idtools.MkdirAllAndChown(base, 0710, dirID); err != nil { + return nil, fmt.Errorf("Failed to create '%s': %v", base, err) + } + diff -Nru docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41092.patch docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41092.patch --- docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41092.patch 1970-01-01 08:00:00.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/patches/CVE-2021-41092.patch 2021-12-04 18:41:36.000000000 +0800 @@ -0,0 +1,115 @@ +Description: registry: ensure default auth config has address +Origin: backport, https://github.com/docker/cli/commit/42d1c027 +Bug-Debian: https://bugs.debian.org/998292 +--- a/cli/cli/command/registry.go ++++ b/cli/cli/command/registry.go +@@ -63,17 +63,14 @@ + indexServer := registry.GetAuthConfigKey(index) + isDefaultRegistry := indexServer == ElectAuthServer(context.Background(), cli) + authConfig, err := GetDefaultAuthConfig(cli, true, indexServer, isDefaultRegistry) +- if authConfig == nil { +- authConfig = &types.AuthConfig{} +- } + if err != nil { + fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err) + } +- err = ConfigureAuth(cli, "", "", authConfig, isDefaultRegistry) ++ err = ConfigureAuth(cli, "", "", &authConfig, isDefaultRegistry) + if err != nil { + return "", err + } +- return EncodeAuthToBase64(*authConfig) ++ return EncodeAuthToBase64(authConfig) + } + } + +@@ -92,7 +89,7 @@ + + // GetDefaultAuthConfig gets the default auth config given a serverAddress + // If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it +-func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (*types.AuthConfig, error) { ++func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { + if !isDefaultRegistry { + serverAddress = registry.ConvertToHostname(serverAddress) + } +@@ -101,13 +98,15 @@ + if checkCredStore { + authconfig, err = cli.ConfigFile().GetAuthConfig(serverAddress) + if err != nil { +- return nil, err ++ return types.AuthConfig{ ++ ServerAddress: serverAddress, ++ }, err + } + } + authconfig.ServerAddress = serverAddress + authconfig.IdentityToken = "" + res := types.AuthConfig(authconfig) +- return &res, nil ++ return res, nil + } + + // ConfigureAuth handles prompting of user's username and password if needed +--- a/cli/cli/command/registry/login.go ++++ b/cli/cli/command/registry/login.go +@@ -114,22 +114,19 @@ + var response registrytypes.AuthenticateOKBody + isDefaultRegistry := serverAddress == authServer + authConfig, err := command.GetDefaultAuthConfig(dockerCli, opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry) +- if authConfig == nil { +- authConfig = &types.AuthConfig{} +- } + if err == nil && authConfig.Username != "" && authConfig.Password != "" { +- response, err = loginWithCredStoreCreds(ctx, dockerCli, authConfig) ++ response, err = loginWithCredStoreCreds(ctx, dockerCli, &authConfig) + } + if err != nil || authConfig.Username == "" || authConfig.Password == "" { +- err = command.ConfigureAuth(dockerCli, opts.user, opts.password, authConfig, isDefaultRegistry) ++ err = command.ConfigureAuth(dockerCli, opts.user, opts.password, &authConfig, isDefaultRegistry) + if err != nil { + return err + } + +- response, err = clnt.RegistryLogin(ctx, *authConfig) ++ response, err = clnt.RegistryLogin(ctx, authConfig) + if err != nil && client.IsErrConnectionFailed(err) { + // If the server isn't responding (yet) attempt to login purely client side +- response, err = loginClientSide(ctx, *authConfig) ++ response, err = loginClientSide(ctx, authConfig) + } + // If we (still) have an error, give up + if err != nil { +@@ -152,7 +149,7 @@ + } + } + +- if err := creds.Store(configtypes.AuthConfig(*authConfig)); err != nil { ++ if err := creds.Store(configtypes.AuthConfig(authConfig)); err != nil { + return errors.Errorf("Error saving credentials: %v", err) + } + +--- a/cli/cli/command/registry_test.go ++++ b/cli/cli/command/registry_test.go +@@ -145,7 +145,21 @@ + assert.Check(t, is.Equal(tc.expectedErr, err.Error())) + } else { + assert.NilError(t, err) +- assert.Check(t, is.DeepEqual(tc.expectedAuthConfig, *authconfig)) ++ assert.Check(t, is.DeepEqual(tc.expectedAuthConfig, authconfig)) + } + } + } ++ ++func TestGetDefaultAuthConfig_HelperError(t *testing.T) { ++ cli := test.NewFakeCli(&fakeClient{}) ++ errBuf := new(bytes.Buffer) ++ cli.SetErr(errBuf) ++ cli.ConfigFile().CredentialsStore = "fake-does-not-exist" ++ serverAddress := "test-server-address" ++ expectedAuthConfig := types.AuthConfig{ ++ ServerAddress: serverAddress, ++ } ++ authconfig, err := GetDefaultAuthConfig(cli, true, serverAddress, serverAddress == "https://index.docker.io/v1/") ++ assert.Check(t, is.DeepEqual(expectedAuthConfig, authconfig)) ++ assert.Check(t, is.ErrorContains(err, "docker-credential-fake-does-not-exist")) ++} diff -Nru docker.io-20.10.5+dfsg1/debian/patches/engine-clone3-seccomp.patch docker.io-20.10.5+dfsg1/debian/patches/engine-clone3-seccomp.patch --- docker.io-20.10.5+dfsg1/debian/patches/engine-clone3-seccomp.patch 1970-01-01 08:00:00.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/patches/engine-clone3-seccomp.patch 2021-12-04 18:52:06.000000000 +0800 @@ -0,0 +1,193 @@ +Description: seccomp: add support for "clone3" syscall in default policy +Origin: backport, https://github.com/moby/moby/commit/97728350 +Bug-Debian: https://bugs.debian.org/995191 + +It also includes fix in https://github.com/moby/moby/pull/43005 for mips. +--- a/engine/profiles/seccomp/default.json ++++ b/engine/profiles/seccomp/default.json +@@ -591,6 +591,7 @@ + "names": [ + "bpf", + "clone", ++ "clone3", + "fanotify_init", + "fsconfig", + "fsmount", +@@ -665,6 +666,51 @@ + ] + }, + "excludes": { ++ "caps": [ ++ "CAP_SYS_ADMIN" ++ ] ++ } ++ }, ++ { ++ "names": [ ++ "clone3" ++ ], ++ "action": "SCMP_ACT_ERRNO", ++ "errnoRet": 38, ++ "args": [], ++ "comment": "ENOSYS for clone3 on non-mips architectures", ++ "includes": {}, ++ "excludes": { ++ "caps": [ ++ "CAP_SYS_ADMIN" ++ ], ++ "arches": [ ++ "mips3l64n32", ++ "mips64", ++ "mips64n32", ++ "mipsel", ++ "mipsel64" ++ ] ++ } ++ }, ++ { ++ "names": [ ++ "clone3" ++ ], ++ "action": "SCMP_ACT_ERRNO", ++ "errnoRet": 89, ++ "args": [], ++ "comment": "ENOSYS for clone3 on mips architectures", ++ "includes": { ++ "arches": [ ++ "mips3l64n32", ++ "mips64", ++ "mips64n32", ++ "mipsel", ++ "mipsel64" ++ ] ++ }, ++ "excludes": { + "caps": [ + "CAP_SYS_ADMIN" + ] +--- a/engine/profiles/seccomp/default_linux.go ++++ b/engine/profiles/seccomp/default_linux.go +@@ -40,8 +40,26 @@ + } + } + ++const ( ++ enosys uint = 0x26 // enosys for non-mips architectures. ++ enosysMIPS uint = 0x59 // enosys for mips architectures. ++) ++ + // DefaultProfile defines the allowed syscalls for the default seccomp profile. + func DefaultProfile() *Seccomp { ++ // The value of ENOSYS differs between MIPS and non-MIPS architectures. While ++ // this is not problematic for the embedded seccomp profile, it prevents the ++ // profile from being saved as a portable JSON file that can be used for both ++ // architectures. ++ // To work around this situation, we include conditional rules for both arches. ++ // and hard-code the value for ENOSYS in both. ++ // For more details, refer to https://github.com/moby/moby/pull/42836#issuecomment-963429850 ++ // and https://github.com/opencontainers/runtime-spec/pull/1087#issuecomment-963463475 ++ var ( ++ nosys = enosys ++ nosysMIPS = enosysMIPS ++ ) ++ + syscalls := []*Syscall{ + { + Names: []string{ +@@ -522,6 +540,7 @@ + Names: []string{ + "bpf", + "clone", ++ "clone3", + "fanotify_init", + "fsconfig", + "fsmount", +@@ -585,6 +604,34 @@ + }, + Excludes: Filter{ + Caps: []string{"CAP_SYS_ADMIN"}, ++ }, ++ }, ++ { ++ Names: []string{ ++ "clone3", ++ }, ++ Action: specs.ActErrno, ++ ErrnoRet: &nosys, ++ Args: []*specs.LinuxSeccompArg{}, ++ Comment: "ENOSYS for clone3 on non-mips architectures", ++ Excludes: Filter{ ++ Arches: []string{"mips3l64n32", "mips64", "mips64n32", "mipsel", "mipsel64"}, ++ Caps: []string{"CAP_SYS_ADMIN"}, ++ }, ++ }, ++ { ++ Names: []string{ ++ "clone3", ++ }, ++ Action: specs.ActErrno, ++ ErrnoRet: &nosysMIPS, ++ Args: []*specs.LinuxSeccompArg{}, ++ Comment: "ENOSYS for clone3 on mips architectures", ++ Includes: Filter{ ++ Arches: []string{"mips3l64n32", "mips64", "mips64n32", "mipsel", "mipsel64"}, ++ }, ++ Excludes: Filter{ ++ Caps: []string{"CAP_SYS_ADMIN"}, + }, + }, + { +--- a/engine/profiles/seccomp/seccomp.go ++++ b/engine/profiles/seccomp/seccomp.go +@@ -45,6 +45,7 @@ + Name string `json:"name,omitempty"` + Names []string `json:"names,omitempty"` + Action specs.LinuxSeccompAction `json:"action"` ++ ErrnoRet *uint `json:"errnoRet,omitempty"` + Args []*specs.LinuxSeccompArg `json:"args"` + Comment string `json:"comment"` + Includes Filter `json:"includes"` +--- a/engine/profiles/seccomp/seccomp_linux.go ++++ b/engine/profiles/seccomp/seccomp_linux.go +@@ -150,29 +150,25 @@ + } + } + ++ newCall := specs.LinuxSyscall{ ++ Action: call.Action, ++ ErrnoRet: call.ErrnoRet, ++ } + if call.Name != "" && len(call.Names) != 0 { + return nil, errors.New("'name' and 'names' were specified in the seccomp profile, use either 'name' or 'names'") + } +- + if call.Name != "" { +- newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall([]string{call.Name}, call.Action, call.Args)) ++ newCall.Names = []string{call.Name} + } else { +- newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(call.Names, call.Action, call.Args)) ++ newCall.Names = call.Names ++ } ++ // Loop through all the arguments of the syscall and convert them ++ for _, arg := range call.Args { ++ newCall.Args = append(newCall.Args, *arg) + } +- } +- +- return newConfig, nil +-} + +-func createSpecsSyscall(names []string, action specs.LinuxSeccompAction, args []*specs.LinuxSeccompArg) specs.LinuxSyscall { +- newCall := specs.LinuxSyscall{ +- Names: names, +- Action: action, ++ newConfig.Syscalls = append(newConfig.Syscalls, newCall) + } + +- // Loop through all the arguments of the syscall and convert them +- for _, arg := range args { +- newCall.Args = append(newCall.Args, *arg) +- } +- return newCall ++ return newConfig, nil + } diff -Nru docker.io-20.10.5+dfsg1/debian/patches/series docker.io-20.10.5+dfsg1/debian/patches/series --- docker.io-20.10.5+dfsg1/debian/patches/series 2021-03-10 00:53:21.000000000 +0800 +++ docker.io-20.10.5+dfsg1/debian/patches/series 2021-12-04 18:45:47.000000000 +0800 @@ -27,3 +27,7 @@ test--skip-TestGetRootUIDGID.patch test--skip-TestStateRunStop.patch test--skip-TestUntarParentPathPermissions +CVE-2021-41089.patch +CVE-2021-41091.patch +CVE-2021-41092.patch +engine-clone3-seccomp.patch