[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1000448: marked as done (bullseye-pu: package containerd/1.4.12~ds1-1~deb11u1)



Your message dated Sat, 18 Dec 2021 20:57:56 +0000
with message-id <7c5e58422d4fd1d02cfae36eca731d5d90ba0743.camel@adam-barratt.org.uk>
and subject line Closing bugs for p-u requests included in 11.2 (part the deux)
has caused the Debian Bug report #1000448,
regarding bullseye-pu: package containerd/1.4.12~ds1-1~deb11u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1000448: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1000448
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: zhsj@debian.org

[ Reason ]

I'd like to update containerd in bullseye to latest upstream
patch version. Upstream does maintain a stable release branch
1.4.x with only backporting important bugfix.

Notably:
1.4.12~ds1-1~deb11u1 will have:

+ Workaround for "clone3" syscall. So users can run images like
  fedora:rawhide, ubuntu:impish, which has enabled clone3 syscall
  in glibc.
  See also https://bugs.launchpad.net/cloud-images/+bug/1943049
+ Mitigate CVE-2021-41190: Handle ambiguous OCI manifest parsing
+ Backport RPi1/RPi0 workaround #998909

[ Impact ]

Same as above three notable changes.

[ Tests ]

+ Extensive unit tests in upstream source
+ Manually install it on bullseye system. I can successfully run:
  ctr run --net-host --seccomp --rm registry.fedoraproject.org/fedora:rawhide test1 /usr/bin/curl www.debian.org

+ I don't have RPi1 or RPi0 to test, but the backported patch is fairly simple.

[ Risks ]

There are 7 patch releases from the version in bullseye.
So the change is not small.

[ 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 ]

I will copy filtered diff here, and attach full diff as attachment.

filter command:

cat containerd_1.4.12~ds1-1~deb11u1.patch|filterdiff -x '*/patches/*CVE-2021*' -x '*_windows.*' -x '*_test.*' -x '*.toml' -x '*.yml' -x '*.yaml' -x '*/vendor.conf' -x '*/Dockerfile.test'

diffstat:

 .mailmap                                                                    |    3 
 Vagrantfile                                                                 |    2 
 archive/tar_unix.go                                                         |    2 
 content/local/store.go                                                      |    2 
 contrib/seccomp/seccomp_default.go                                          |   11 
 debian/changelog                                                            |   31 ++
 debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch                       |    2 
 debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch |  114 ++++++----
 debian/patches/0008-Add-RPi1-RPi0-workaround.patch                          |   35 +++
 debian/patches/series                                                       |    5 
 images/image.go                                                             |   55 ++++
 metadata/containers.go                                                      |    2 
 metadata/content.go                                                         |    6 
 remotes/docker/authorizer.go                                                |    7 
 remotes/docker/fetcher.go                                                   |   12 -
 remotes/docker/pusher.go                                                    |    5 
 remotes/docker/resolver.go                                                  |   51 +++-
 remotes/docker/schema1/converter.go                                         |    9 
 runtime/v1/linux/bundle.go                                                  |   56 ++++
 runtime/v2/bundle.go                                                        |    5 
 runtime/v2/bundle_default.go                                                |   24 ++
 runtime/v2/bundle_linux.go                                                  |   74 ++++++
 script/setup/runc-version                                                   |    2 
 snapshots/btrfs/btrfs.go                                                    |    8 
 snapshots/devmapper/snapshotter.go                                          |    4 
 vendor/github.com/containerd/cri/pkg/os/os.go                               |   13 -
 vendor/github.com/containerd/cri/pkg/os/os_unix.go                          |   15 +
 vendor/github.com/containerd/cri/pkg/server/sandbox_run.go                  |    4 
 version/version.go                                                          |    2 
 29 files changed, 471 insertions(+), 90 deletions(-)

diff -Nru containerd-1.4.5~ds1/archive/tar_unix.go containerd-1.4.12~ds1/archive/tar_unix.go
--- containerd-1.4.5~ds1/archive/tar_unix.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/archive/tar_unix.go	2021-11-18 03:52:12.000000000 +0800
@@ -113,7 +113,7 @@
 
 func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
 	if hdr.Typeflag == tar.TypeLink {
-		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
+		if fi, err := os.Lstat(path); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
 			if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
 				return err
 			}
diff -Nru containerd-1.4.5~ds1/content/local/store.go containerd-1.4.12~ds1/content/local/store.go
--- containerd-1.4.5~ds1/content/local/store.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/content/local/store.go	2021-11-18 03:52:12.000000000 +0800
@@ -502,7 +502,7 @@
 	if ref != status.Ref {
 		// NOTE(stevvooe): This is fairly catastrophic. Either we have some
 		// layout corruption or a hash collision for the ref key.
-		return status, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref)
+		return status, errors.Errorf("ref key does not match: %v != %v", ref, status.Ref)
 	}
 
 	if total > 0 && status.Total > 0 && total != status.Total {
diff -Nru containerd-1.4.5~ds1/contrib/seccomp/seccomp_default.go containerd-1.4.12~ds1/contrib/seccomp/seccomp_default.go
--- containerd-1.4.5~ds1/contrib/seccomp/seccomp_default.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/contrib/seccomp/seccomp_default.go	2021-11-18 03:52:12.000000000 +0800
@@ -49,6 +49,7 @@
 
 // DefaultProfile defines the allowed syscalls for the default seccomp profile.
 func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
+	nosys := uint(unix.ENOSYS)
 	syscalls := []specs.LinuxSyscall{
 		{
 			Names: []string{
@@ -524,6 +525,7 @@
 				Names: []string{
 					"bpf",
 					"clone",
+					"clone3",
 					"fanotify_init",
 					"lookup_dcookie",
 					"mount",
@@ -648,6 +650,15 @@
 				},
 			})
 		}
+		// clone3 is explicitly requested to give ENOSYS instead of the default EPERM, when CAP_SYS_ADMIN is unset
+		// https://github.com/moby/moby/pull/42681
+		s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{
+			Names: []string{
+				"clone3",
+			},
+			Action:   specs.ActErrno,
+			ErrnoRet: &nosys,
+		})
 	}
 
 	return s
diff -Nru containerd-1.4.5~ds1/debian/changelog containerd-1.4.12~ds1/debian/changelog
--- containerd-1.4.5~ds1/debian/changelog	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/changelog	2021-11-23 18:42:16.000000000 +0800
@@ -1,3 +1,34 @@
+containerd (1.4.12~ds1-1~deb11u1) bullseye; urgency=medium
+
+  * New upstream version 1.4.12~ds1
+    + 1.4.12
+      * Mitigate CVE-2021-41190: Handle ambiguous OCI manifest parsing
+      * Update pull to try next mirror for non-404 errors
+      * Update pull to handle of non-https urls in descriptors
+    + 1.4.11
+      * CVE-2021-41103: Fix insufficiently restricted permissions on container
+        root and plugin directories
+    + 1.4.10
+      * Support "clone3" in default seccomp profile
+      * Fix panic in metadata content writer on copy error
+    + 1.4.9
+      * Update pull authorization logic on redirect
+      * Fix user agent used for fetching registry authentication tokens
+    + 1.4.8
+      * CVE-2021-32760: Archive package allows chmod of file outside of unpack
+        target directory
+    + 1.4.7
+      * Fix invalid validation error checking
+      * Fix error on image pull resume
+  * Refresh patches
+    + Drop CVE-2021-32760 patch
+    + Drop CVE-2021-41103 patch
+    + Refresh 0005-backport-github.com-containerd-containerd-remotes.patch
+      with latest 1.5 release branch
+  * Backport RPi1/RPi0 workaround (Closes: #998909)
+
+ -- Shengjing Zhu <zhsj@debian.org>  Tue, 23 Nov 2021 18:42:16 +0800
+
 containerd (1.4.5~ds1-2+deb11u1) bullseye-security; urgency=high
 
   * CVE-2021-41103: Insufficiently restricted permissions on container
diff -Nru containerd-1.4.5~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch containerd-1.4.12~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch
--- containerd-1.4.5~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch	2021-11-23 18:42:16.000000000 +0800
@@ -20,7 +20,7 @@
  /*
     Copyright The containerd Authors.
 diff --git a/snapshots/btrfs/btrfs.go b/snapshots/btrfs/btrfs.go
-index ea90853..eef883b 100644
+index 78f825c..778b783 100644
 --- a/snapshots/btrfs/btrfs.go
 +++ b/snapshots/btrfs/btrfs.go
 @@ -1,4 +1,4 @@
diff -Nru containerd-1.4.5~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch containerd-1.4.12~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch
--- containerd-1.4.5~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch	2021-11-23 18:42:16.000000000 +0800
@@ -1,6 +1,7 @@
 From: Shengjing Zhu <zhsj@debian.org>
-Date: Fri, 5 Mar 2021 16:35:17 +0800
-Subject: backport_github=2Ecom/containerd/containerd/remotes
+Date: Tue, 23 Nov 2021 15:49:57 +0800
+Subject: =?utf-8?q?backport_github=2Ecom/containerd/containerd/remotes?=
+ =?utf-8?q?=C2=AC?=
 
 For building docker.io 20.10
 
@@ -10,19 +11,19 @@
 
 Forwarded: not-needed
 ---
- remotes/docker/auth.go           | 198 ---------------------------
- remotes/docker/auth/fetch.go     | 202 +++++++++++++++++++++++++++
- remotes/docker/auth/parse.go     | 203 ++++++++++++++++++++++++++++
- remotes/docker/authorizer.go     | 285 ++++++++++-----------------------------
+ remotes/docker/auth.go           | 198 --------------------------
+ remotes/docker/auth/fetch.go     | 209 ++++++++++++++++++++++++++++
+ remotes/docker/auth/parse.go     | 203 +++++++++++++++++++++++++++
+ remotes/docker/authorizer.go     | 292 +++++++++------------------------------
  remotes/docker/errcode.go        |   2 +-
  remotes/docker/fetcher.go        |   2 +-
  remotes/docker/httpreadseeker.go |   2 +-
- remotes/docker/pusher.go         |  36 +++--
- remotes/docker/resolver.go       |  47 +++----
+ remotes/docker/pusher.go         |  38 +++--
+ remotes/docker/resolver.go       |  49 +++----
  remotes/docker/scope.go          |  14 +-
  remotes/docker/scope_test.go     |   4 +-
- remotes/errors/errors.go         |  46 +++++++
- 12 files changed, 573 insertions(+), 468 deletions(-)
+ remotes/errors/errors.go         |  46 ++++++
+ 12 files changed, 581 insertions(+), 478 deletions(-)
  delete mode 100644 remotes/docker/auth.go
  create mode 100644 remotes/docker/auth/fetch.go
  create mode 100644 remotes/docker/auth/parse.go
@@ -234,10 +235,10 @@
 -}
 diff --git a/remotes/docker/auth/fetch.go b/remotes/docker/auth/fetch.go
 new file mode 100644
-index 0000000..0d01c81
+index 0000000..8b0a87e
 --- /dev/null
 +++ b/remotes/docker/auth/fetch.go
-@@ -0,0 +1,202 @@
+@@ -0,0 +1,209 @@
 +/*
 +   Copyright The containerd Authors.
 +
@@ -266,6 +267,7 @@
 +
 +	"github.com/containerd/containerd/log"
 +	remoteserrors "github.com/containerd/containerd/remotes/errors"
++	"github.com/containerd/containerd/version"
 +	"github.com/pkg/errors"
 +	"golang.org/x/net/context/ctxhttp"
 +)
@@ -349,6 +351,9 @@
 +	for k, v := range headers {
 +		req.Header[k] = append(req.Header[k], v...)
 +	}
++	if len(req.Header.Get("User-Agent")) == 0 {
++		req.Header.Set("User-Agent", "containerd/"+version.Version)
++	}
 +
 +	resp, err := ctxhttp.Do(ctx, client, req)
 +	if err != nil {
@@ -393,6 +398,9 @@
 +	for k, v := range headers {
 +		req.Header[k] = append(req.Header[k], v...)
 +	}
++	if len(req.Header.Get("User-Agent")) == 0 {
++		req.Header.Set("User-Agent", "containerd/"+version.Version)
++	}
 +
 +	reqParams := req.URL.Query()
 +
@@ -650,10 +658,10 @@
 +	return "", ""
 +}
 diff --git a/remotes/docker/authorizer.go b/remotes/docker/authorizer.go
-index 001423a..67e4aea 100644
+index 2f459b7..67e4aea 100644
 --- a/remotes/docker/authorizer.go
 +++ b/remotes/docker/authorizer.go
-@@ -19,21 +19,17 @@ package docker
+@@ -19,22 +19,17 @@ package docker
  import (
  	"context"
  	"encoding/base64"
@@ -669,6 +677,7 @@
  
  	"github.com/containerd/containerd/errdefs"
  	"github.com/containerd/containerd/log"
+-	"github.com/containerd/containerd/version"
 +	"github.com/containerd/containerd/remotes/docker/auth"
 +	remoteerrors "github.com/containerd/containerd/remotes/errors"
  	"github.com/pkg/errors"
@@ -677,7 +686,7 @@
  )
  
  type dockerAuthorizer struct {
-@@ -135,8 +131,8 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -136,8 +131,8 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  
  	a.mu.Lock()
  	defer a.mu.Unlock()
@@ -688,7 +697,7 @@
  			if err := invalidAuthorization(c, responses); err != nil {
  				delete(a.handlers, host)
  				return err
-@@ -152,26 +148,35 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -153,26 +148,35 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  				return nil
  			}
  
@@ -731,7 +740,7 @@
  				return nil
  			}
  		}
-@@ -179,38 +184,6 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -180,38 +184,6 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  	return errors.Wrap(errdefs.ErrNotImplemented, "failed to find supported auth scheme")
  }
  
@@ -770,7 +779,7 @@
  // authResult is used to control limit rate.
  type authResult struct {
  	sync.WaitGroup
-@@ -227,17 +200,17 @@ type authHandler struct {
+@@ -228,17 +200,17 @@ type authHandler struct {
  	client *http.Client
  
  	// only support basic and bearer schemes
@@ -791,7 +800,7 @@
  	return &authHandler{
  		header:       hdr,
  		client:       client,
-@@ -249,17 +222,17 @@ func newAuthHandler(client *http.Client, hdr http.Header, scheme authenticationS
+@@ -250,17 +222,17 @@ func newAuthHandler(client *http.Client, hdr http.Header, scheme authenticationS
  
  func (ah *authHandler) authorize(ctx context.Context) (string, error) {
  	switch ah.scheme {
@@ -813,7 +822,7 @@
  
  	if username == "" || secret == "" {
  		return "", fmt.Errorf("failed to handle basic auth because missing username or secret")
-@@ -269,14 +242,14 @@ func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) {
+@@ -270,14 +242,14 @@ func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) {
  	return fmt.Sprintf("Basic %s", auth), nil
  }
  
@@ -831,7 +840,7 @@
  
  	ah.Lock()
  	if r, exist := ah.scopedTokens[scoped]; exist {
-@@ -291,174 +264,52 @@ func (ah *authHandler) doBearerAuth(ctx context.Context) (string, error) {
+@@ -292,180 +264,52 @@ func (ah *authHandler) doBearerAuth(ctx context.Context) (string, error) {
  	ah.scopedTokens[scoped] = r
  	ah.Unlock()
  
@@ -910,6 +919,9 @@
 -			req.Header[k] = append(req.Header[k], v...)
 -		}
 -	}
+-	if len(req.Header.Get("User-Agent")) == 0 {
+-		req.Header.Set("User-Agent", "containerd/"+version.Version)
+-	}
 -
 -	resp, err := ctxhttp.Do(ctx, ah.client, req)
 -	if err != nil {
@@ -984,6 +996,9 @@
  		}
 +		return resp.AccessToken, nil
  	}
+-	if len(req.Header.Get("User-Agent")) == 0 {
+-		req.Header.Set("User-Agent", "containerd/"+version.Version)
+-	}
 -
 -	reqParams := req.URL.Query()
 -
@@ -1058,7 +1073,7 @@
  	Message string
  
 diff --git a/remotes/docker/fetcher.go b/remotes/docker/fetcher.go
-index cd0168b..9d6708d 100644
+index 5aaaf9e..4b2c10e 100644
 --- a/remotes/docker/fetcher.go
 +++ b/remotes/docker/fetcher.go
 @@ -45,7 +45,7 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
@@ -1084,7 +1099,7 @@
  
  		if hrs.rc != nil {
 diff --git a/remotes/docker/pusher.go b/remotes/docker/pusher.go
-index d95e0c8..94a270c 100644
+index d46396b..c367b1e 100644
 --- a/remotes/docker/pusher.go
 +++ b/remotes/docker/pusher.go
 @@ -30,6 +30,7 @@ import (
@@ -1104,19 +1119,20 @@
  	if err != nil {
  		return nil, err
  	}
-@@ -112,8 +113,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -113,9 +114,10 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  				return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
  			}
  		} else if resp.StatusCode != http.StatusNotFound {
--			// TODO: log error
--			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 +			err := remoteserrors.NewUnexpectedStatusErr(resp)
 +			log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response")
+ 			resp.Body.Close()
+-			// TODO: log error
+-			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 +			return nil, err
  		}
+ 		resp.Body.Close()
  	}
- 
-@@ -128,7 +130,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -131,7 +133,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		var resp *http.Response
  		if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" {
  			preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo)
@@ -1125,7 +1141,7 @@
  
  			// NOTE: the fromRepo might be private repo and
  			// auth service still can grant token without error.
-@@ -166,8 +168,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -170,8 +172,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  			})
  			return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
  		default:
@@ -1137,7 +1153,7 @@
  		}
  
  		var (
-@@ -219,7 +222,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -223,7 +226,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  	// TODO: Support chunked upload
  
  	pr, pw := io.Pipe()
@@ -1146,7 +1162,7 @@
  	body := ioutil.NopCloser(pr)
  
  	req.body = func() (io.ReadCloser, error) {
-@@ -237,6 +240,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -241,6 +244,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		defer close(respC)
  		resp, err := req.doWithRetries(ctx, nil)
  		if err != nil {
@@ -1154,7 +1170,7 @@
  			pr.CloseWithError(err)
  			return
  		}
-@@ -244,10 +248,11 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -248,10 +252,11 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		switch resp.StatusCode {
  		case http.StatusOK, http.StatusCreated, http.StatusNoContent:
  		default:
@@ -1169,7 +1185,7 @@
  	}()
  
  	return &pushWriter{
-@@ -280,12 +285,17 @@ func getManifestPath(object string, dgst digest.Digest) []string {
+@@ -284,12 +289,17 @@ func getManifestPath(object string, dgst digest.Digest) []string {
  	return []string{"manifests", object}
  }
  
@@ -1188,7 +1204,7 @@
  	isManifest bool
  
  	expected digest.Digest
-@@ -335,8 +345,8 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
+@@ -339,10 +349,10 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
  
  	// TODO: timeout waiting for response
  	resp := <-pw.responseC
@@ -1197,10 +1213,13 @@
 +	if resp.err != nil {
 +		return resp.err
  	}
+-	defer resp.Body.Close()
++	defer resp.Response.Body.Close()
  
  	// 201 is specified return status, some registries return
+ 	// 200, 202 or 204.
 diff --git a/remotes/docker/resolver.go b/remotes/docker/resolver.go
-index aea092c..866379e 100644
+index 40831f1..d6ccd70 100644
 --- a/remotes/docker/resolver.go
 +++ b/remotes/docker/resolver.go
 @@ -41,10 +41,6 @@ import (
@@ -1235,8 +1254,8 @@
 -	}
 -
  	var (
- 		lastErr error
- 		paths   [][]string
+ 		firstErr error
+ 		paths    [][]string
 @@ -267,7 +258,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
  		return "", ocispec.Descriptor{}, errors.Wrap(errdefs.ErrNotFound, "no resolve hosts")
  	}
@@ -1246,7 +1265,22 @@
  	if err != nil {
  		return "", ocispec.Descriptor{}, err
  	}
-@@ -393,12 +384,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
+@@ -295,14 +286,12 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
+ 				if firstErr == nil {
+ 					firstErr = err
+ 				}
+-				log.G(ctx).WithError(err).Info("trying next host")
+ 				continue // try another host
+ 			}
+ 			resp.Body.Close() // don't care about body contents.
+ 
+ 			if resp.StatusCode > 299 {
+ 				if resp.StatusCode == http.StatusNotFound {
+-					log.G(ctx).Info("trying next host - response was http.StatusNotFound")
+ 					continue
+ 				}
+ 				if resp.StatusCode > 399 {
+@@ -404,12 +393,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
  }
  
  func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
@@ -1260,7 +1294,7 @@
  	if err != nil {
  		return nil, err
  	}
-@@ -409,23 +395,27 @@ func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetch
+@@ -420,23 +404,27 @@ func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetch
  }
  
  func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
@@ -1295,7 +1329,7 @@
  type dockerBase struct {
  	refspec    reference.Spec
  	repository string
-@@ -457,10 +447,11 @@ func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) {
+@@ -468,10 +456,11 @@ func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) {
  }
  
  func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request {
diff -Nru containerd-1.4.5~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch containerd-1.4.12~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch
--- containerd-1.4.5~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch	2021-11-23 18:42:16.000000000 +0800
@@ -0,0 +1,35 @@
+From: Tianon Gravi <admwiggin@gmail.com>
+Date: Fri, 4 Sep 2020 14:12:04 -0700
+Subject: Add RPi1/RPi0 workaround
+
+On the very popular Raspberry Pi 1 and Zero devices, the CPU is actually ARMv6, but the chip happens to support the feature bit the kernel uses to differentiate v6/v7, so it gets reported as "CPU architecture: 7" and thus fails to run many of the images that get pulled.
+
+To account for this very popular edge case, this also checks "model name" which on these chips will begin with "ARMv6-compatible" -- we could also check uname, but getCPUInfo is already handy, low overhead, and mirrors the code before this.
+
+Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
+
+Origin: backport, https://github.com/containerd/containerd/commit/2055e12953bb538228d8d9fe627fa545d7cf82be
+---
+ platforms/cpuinfo.go | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/platforms/cpuinfo.go b/platforms/cpuinfo.go
+index db65a72..0512bc9 100644
+--- a/platforms/cpuinfo.go
++++ b/platforms/cpuinfo.go
+@@ -96,6 +96,15 @@ func getCPUVariant() string {
+ 		return ""
+ 	}
+ 
++	// handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
++	// https://www.raspberrypi.org/forums/viewtopic.php?t=12614
++	if runtime.GOARCH == "arm" && variant == "7" {
++		model, err := getCPUInfo("model name")
++		if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
++			variant = "6"
++		}
++	}
++
+ 	switch strings.ToLower(variant) {
+ 	case "8", "aarch64":
+ 		// special case: if running a 32-bit userspace on aarch64, the variant should be "v7"
diff -Nru containerd-1.4.5~ds1/debian/patches/series containerd-1.4.12~ds1/debian/patches/series
--- containerd-1.4.5~ds1/debian/patches/series	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/series	2021-11-23 18:42:16.000000000 +0800
@@ -5,7 +5,4 @@
 0005-backport-github.com-containerd-containerd-remotes.patch
 0006-backport-apparmor-handle-signal-mediation.patch
 0007-backport-runtime-ignore-file-already-closed-error.patch
-0008-CVE-2021-32760.patch
-0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch
-0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch
-0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch
+0008-Add-RPi1-RPi0-workaround.patch
diff -Nru containerd-1.4.5~ds1/images/image.go containerd-1.4.12~ds1/images/image.go
--- containerd-1.4.5~ds1/images/image.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/images/image.go	2021-11-18 03:52:12.000000000 +0800
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"sort"
 	"time"
 
@@ -154,6 +155,10 @@
 				return nil, err
 			}
 
+			if err := validateMediaType(p, desc.MediaType); err != nil {
+				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
+			}
+
 			var manifest ocispec.Manifest
 			if err := json.Unmarshal(p, &manifest); err != nil {
 				return nil, err
@@ -194,6 +199,10 @@
 				return nil, err
 			}
 
+			if err := validateMediaType(p, desc.MediaType); err != nil {
+				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
+			}
+
 			var idx ocispec.Index
 			if err := json.Unmarshal(p, &idx); err != nil {
 				return nil, err
@@ -336,6 +345,10 @@
 			return nil, err
 		}
 
+		if err := validateMediaType(p, desc.MediaType); err != nil {
+			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
+		}
+
 		// TODO(stevvooe): We just assume oci manifest, for now. There may be
 		// subtle differences from the docker version.
 		var manifest ocispec.Manifest
@@ -351,6 +364,10 @@
 			return nil, err
 		}
 
+		if err := validateMediaType(p, desc.MediaType); err != nil {
+			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
+		}
+
 		var index ocispec.Index
 		if err := json.Unmarshal(p, &index); err != nil {
 			return nil, err
@@ -368,6 +385,44 @@
 	return descs, nil
 }
 
+// unknownDocument represents a manifest, manifest list, or index that has not
+// yet been validated.
+type unknownDocument struct {
+	MediaType string          `json:"mediaType,omitempty"`
+	Config    json.RawMessage `json:"config,omitempty"`
+	Layers    json.RawMessage `json:"layers,omitempty"`
+	Manifests json.RawMessage `json:"manifests,omitempty"`
+	FSLayers  json.RawMessage `json:"fsLayers,omitempty"` // schema 1
+}
+
+// validateMediaType returns an error if the byte slice is invalid JSON or if
+// the media type identifies the blob as one format but it contains elements of
+// another format.
+func validateMediaType(b []byte, mt string) error {
+	var doc unknownDocument
+	if err := json.Unmarshal(b, &doc); err != nil {
+		return err
+	}
+	if len(doc.FSLayers) != 0 {
+		return fmt.Errorf("media-type: schema 1 not supported")
+	}
+	switch mt {
+	case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+		if len(doc.Manifests) != 0 ||
+			doc.MediaType == MediaTypeDockerSchema2ManifestList ||
+			doc.MediaType == ocispec.MediaTypeImageIndex {
+			return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
+		}
+	case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+		if len(doc.Config) != 0 || len(doc.Layers) != 0 ||
+			doc.MediaType == MediaTypeDockerSchema2Manifest ||
+			doc.MediaType == ocispec.MediaTypeImageManifest {
+			return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
+		}
+	}
+	return nil
+}
+
 // RootFS returns the unpacked diffids that make up and images rootfs.
 //
 // These are used to verify that a set of layers unpacked to the expected
diff -Nru containerd-1.4.5~ds1/.mailmap containerd-1.4.12~ds1/.mailmap
--- containerd-1.4.5~ds1/.mailmap	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.mailmap	2021-11-18 03:52:12.000000000 +0800
@@ -17,6 +17,7 @@
 Cao Zhihao <caozhihao@163.com>
 Cao Zhihao <caozhihao@163.com> <caozhihao.xd@bytedance.com>
 Carlos Eduardo <me@carlosedp.com> <me@carlosedp.com>
+Cory Bennett <cbennett@netflix.com>
 Cristian Staretu <cristian.staretu@gmail.com>
 Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
 Daniel Dao <dqminh89@gmail.com>
@@ -73,6 +74,7 @@
 Nishchay Kumar <mrawesomenix@gmail.com>
 Oliver Stenbom <oliver@stenbom.eu> <ostenbom@pivotal.io>
 Phil Estes <estesp@gmail.com> <estesp@linux.vnet.ibm.com>
+Phil Estes <estesp@gmail.com> <estesp@amazon.com>
 Reid Li <reid.li@utexas.edu>
 Ross Boucher <rboucher@gmail.com>
 Ruediger Maass <ruediger.maass@de.ibm.com>
@@ -90,6 +92,7 @@
 Su Fei  <fesu@ebay.com> <fesu@ebay.com>
 Ted Yu <yuzhihong@gmail.com>
 Tõnis Tiigi <tonistiigi@gmail.com>
+Wei Fu <fuweid89@gmail.com>
 Wei Fu <fuweid89@gmail.com> <fhfuwei@163.com>
 Xiaodong Zhang <a4012017@sina.com>
 Xuean Yan <yan.xuean@zte.com.cn>
diff -Nru containerd-1.4.5~ds1/metadata/containers.go containerd-1.4.12~ds1/metadata/containers.go
--- containerd-1.4.5~ds1/metadata/containers.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/metadata/containers.go	2021-11-18 03:52:12.000000000 +0800
@@ -290,7 +290,7 @@
 
 	// image has no validation
 	for k, v := range container.Labels {
-		if err := labels.Validate(k, v); err == nil {
+		if err := labels.Validate(k, v); err != nil {
 			return errors.Wrapf(err, "containers.Labels")
 		}
 	}
diff -Nru containerd-1.4.5~ds1/metadata/content.go containerd-1.4.12~ds1/metadata/content.go
--- containerd-1.4.5~ds1/metadata/content.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/metadata/content.go	2021-11-18 03:52:12.000000000 +0800
@@ -551,13 +551,13 @@
 	if desc.Size > 0 {
 		ra, err := nw.provider.ReaderAt(ctx, nw.desc)
 		if err != nil {
+			w.Close()
 			return err
 		}
 		defer ra.Close()
 
 		if err := content.CopyReaderAt(w, ra, desc.Size); err != nil {
-			nw.w.Close()
-			nw.w = nil
+			w.Close()
 			return err
 		}
 	}
@@ -708,7 +708,7 @@
 
 func validateInfo(info *content.Info) error {
 	for k, v := range info.Labels {
-		if err := labels.Validate(k, v); err == nil {
+		if err := labels.Validate(k, v); err != nil {
 			return errors.Wrapf(err, "info.Labels")
 		}
 	}
diff -Nru containerd-1.4.5~ds1/remotes/docker/authorizer.go containerd-1.4.12~ds1/remotes/docker/authorizer.go
--- containerd-1.4.5~ds1/remotes/docker/authorizer.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/authorizer.go	2021-11-18 03:52:12.000000000 +0800
@@ -31,6 +31,7 @@
 
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/log"
+	"github.com/containerd/containerd/version"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context/ctxhttp"
@@ -356,6 +357,9 @@
 			req.Header[k] = append(req.Header[k], v...)
 		}
 	}
+	if len(req.Header.Get("User-Agent")) == 0 {
+		req.Header.Set("User-Agent", "containerd/"+version.Version)
+	}
 
 	resp, err := ctxhttp.Do(ctx, ah.client, req)
 	if err != nil {
@@ -408,6 +412,9 @@
 			req.Header[k] = append(req.Header[k], v...)
 		}
 	}
+	if len(req.Header.Get("User-Agent")) == 0 {
+		req.Header.Set("User-Agent", "containerd/"+version.Version)
+	}
 
 	reqParams := req.URL.Query()
 
diff -Nru containerd-1.4.5~ds1/remotes/docker/fetcher.go containerd-1.4.12~ds1/remotes/docker/fetcher.go
--- containerd-1.4.5~ds1/remotes/docker/fetcher.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/fetcher.go	2021-11-18 03:52:12.000000000 +0800
@@ -60,6 +60,10 @@
 				log.G(ctx).WithError(err).Debug("failed to parse")
 				continue
 			}
+			if u.Scheme != "http" && u.Scheme != "https" {
+				log.G(ctx).Debug("non-http(s) alternative url is unsupported")
+				continue
+			}
 			log.G(ctx).Debug("trying alternative url")
 
 			// Try this first, parse it
@@ -148,7 +152,7 @@
 	})
 }
 
-func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (io.ReadCloser, error) {
+func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) {
 	req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
 
 	if offset > 0 {
@@ -162,13 +166,17 @@
 	if err != nil {
 		return nil, err
 	}
+	defer func() {
+		if retErr != nil {
+			resp.Body.Close()
+		}
+	}()
 
 	if resp.StatusCode > 299 {
 		// TODO(stevvooe): When doing a offset specific request, we should
 		// really distinguish between a 206 and a 200. In the case of 200, we
 		// can discard the bytes, hiding the seek behavior from the
 		// implementation.
-		defer resp.Body.Close()
 
 		if resp.StatusCode == http.StatusNotFound {
 			return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String())
diff -Nru containerd-1.4.5~ds1/remotes/docker/pusher.go containerd-1.4.12~ds1/remotes/docker/pusher.go
--- containerd-1.4.5~ds1/remotes/docker/pusher.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/pusher.go	2021-11-18 03:52:12.000000000 +0800
@@ -109,12 +109,15 @@
 						// TODO: Set updated time?
 					},
 				})
+				resp.Body.Close()
 				return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
 			}
 		} else if resp.StatusCode != http.StatusNotFound {
+			resp.Body.Close()
 			// TODO: log error
 			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 		}
+		resp.Body.Close()
 	}
 
 	if isManifest {
@@ -155,6 +158,7 @@
 				return nil, err
 			}
 		}
+		defer resp.Body.Close()
 
 		switch resp.StatusCode {
 		case http.StatusOK, http.StatusAccepted, http.StatusNoContent:
@@ -338,6 +342,7 @@
 	if resp == nil {
 		return errors.New("no response")
 	}
+	defer resp.Body.Close()
 
 	// 201 is specified return status, some registries return
 	// 200, 202 or 204.
diff -Nru containerd-1.4.5~ds1/remotes/docker/resolver.go containerd-1.4.12~ds1/remotes/docker/resolver.go
--- containerd-1.4.5~ds1/remotes/docker/resolver.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/resolver.go	2021-11-18 03:52:12.000000000 +0800
@@ -238,10 +238,10 @@
 	}
 
 	var (
-		lastErr error
-		paths   [][]string
-		dgst    = refspec.Digest()
-		caps    = HostCapabilityPull
+		firstErr error
+		paths    [][]string
+		dgst     = refspec.Digest()
+		caps     = HostCapabilityPull
 	)
 
 	if dgst != "" {
@@ -292,8 +292,8 @@
 					err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization")
 				}
 				// Store the error for referencing later
-				if lastErr == nil {
-					lastErr = err
+				if firstErr == nil {
+					firstErr = err
 				}
 				log.G(ctx).WithError(err).Info("trying next host")
 				continue // try another host
@@ -305,7 +305,14 @@
 					log.G(ctx).Info("trying next host - response was http.StatusNotFound")
 					continue
 				}
-				return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status)
+				if resp.StatusCode > 399 {
+					// Set firstErr when encountering the first non-404 status code.
+					if firstErr == nil {
+						firstErr = errors.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status)
+					}
+					continue // try another host
+				}
+				return "", ocispec.Descriptor{}, errors.Errorf("pulling from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status)
 			}
 			size := resp.ContentLength
 			contentType := getManifestMediaType(resp)
@@ -368,8 +375,8 @@
 			}
 			// Prevent resolving to excessively large manifests
 			if size > MaxManifestSize {
-				if lastErr == nil {
-					lastErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref)
+				if firstErr == nil {
+					firstErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref)
 				}
 				continue
 			}
@@ -385,11 +392,15 @@
 		}
 	}
 
-	if lastErr == nil {
-		lastErr = errors.Wrap(errdefs.ErrNotFound, ref)
+	// If above loop terminates without return, then there was an error.
+	// "firstErr" contains the first non-404 error. That is, "firstErr == nil"
+	// means that either no registries were given or each registry returned 404.
+
+	if firstErr == nil {
+		firstErr = errors.Wrap(errdefs.ErrNotFound, ref)
 	}
 
-	return "", ocispec.Descriptor{}, lastErr
+	return "", ocispec.Descriptor{}, firstErr
 }
 
 func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
@@ -548,7 +559,21 @@
 	if err := r.authorize(ctx, req); err != nil {
 		return nil, errors.Wrap(err, "failed to authorize")
 	}
-	resp, err := ctxhttp.Do(ctx, r.host.Client, req)
+
+	var client = &http.Client{}
+	if r.host.Client != nil {
+		*client = *r.host.Client
+	}
+	if client.CheckRedirect == nil {
+		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+			if len(via) >= 10 {
+				return errors.New("stopped after 10 redirects")
+			}
+			return errors.Wrap(r.authorize(ctx, req), "failed to authorize redirect")
+		}
+	}
+
+	resp, err := ctxhttp.Do(ctx, client, req)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to do request")
 	}
diff -Nru containerd-1.4.5~ds1/remotes/docker/schema1/converter.go containerd-1.4.12~ds1/remotes/docker/schema1/converter.go
--- containerd-1.4.5~ds1/remotes/docker/schema1/converter.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/schema1/converter.go	2021-11-18 03:52:12.000000000 +0800
@@ -256,6 +256,9 @@
 	if err := json.Unmarshal(b, &m); err != nil {
 		return err
 	}
+	if len(m.Manifests) != 0 || len(m.Layers) != 0 {
+		return errors.New("converter: expected schema1 document but found extra keys")
+	}
 	c.pulledManifest = &m
 
 	return nil
@@ -472,8 +475,10 @@
 }
 
 type manifest struct {
-	FSLayers []fsLayer `json:"fsLayers"`
-	History  []history `json:"history"`
+	FSLayers  []fsLayer       `json:"fsLayers"`
+	History   []history       `json:"history"`
+	Layers    json.RawMessage `json:"layers,omitempty"`    // OCI manifest
+	Manifests json.RawMessage `json:"manifests,omitempty"` // OCI index
 }
 
 type v1History struct {
diff -Nru containerd-1.4.5~ds1/runtime/v1/linux/bundle.go containerd-1.4.12~ds1/runtime/v1/linux/bundle.go
--- containerd-1.4.5~ds1/runtime/v1/linux/bundle.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v1/linux/bundle.go	2021-11-18 03:52:12.000000000 +0800
@@ -21,6 +21,7 @@
 import (
 	"context"
 	"crypto/sha256"
+	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -30,6 +31,7 @@
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	"github.com/containerd/containerd/runtime/v1/shim"
 	"github.com/containerd/containerd/runtime/v1/shim/client"
+	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
 
@@ -48,7 +50,7 @@
 		return nil, err
 	}
 	path = filepath.Join(path, id)
-	if err := os.Mkdir(path, 0711); err != nil {
+	if err := os.Mkdir(path, 0700); err != nil {
 		return nil, err
 	}
 	defer func() {
@@ -56,6 +58,9 @@
 			os.RemoveAll(path)
 		}
 	}()
+	if err := prepareBundleDirectoryPermissions(path, spec); err != nil {
+		return nil, err
+	}
 	workDir = filepath.Join(workDir, id)
 	if err := os.MkdirAll(workDir, 0711); err != nil {
 		return nil, err
@@ -77,6 +82,55 @@
 	}, err
 }
 
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory. When user namespaces are enabled, the permissions are modified
+// to allow the remapped root GID to access the bundle.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
+	gid, err := remappedGID(spec)
+	if err != nil {
+		return err
+	}
+	if gid == 0 {
+		return nil
+	}
+	if err := os.Chown(path, -1, int(gid)); err != nil {
+		return err
+	}
+	return os.Chmod(path, 0710)
+}
+
+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
+// unmarshal.
+type ociSpecUserNS struct {
+	Linux *linuxSpecUserNS
+}
+
+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
+// unmarshal.
+type linuxSpecUserNS struct {
+	GIDMappings []specs.LinuxIDMapping
+}
+
+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
+// remappedGID returns an error.
+func remappedGID(spec []byte) (uint32, error) {
+	var ociSpec ociSpecUserNS
+	err := json.Unmarshal(spec, &ociSpec)
+	if err != nil {
+		return 0, err
+	}
+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
+		return 0, nil
+	}
+	for _, mapping := range ociSpec.Linux.GIDMappings {
+		if mapping.ContainerID == 0 {
+			return mapping.HostID, nil
+		}
+	}
+	return 0, nil
+}
+
 type bundle struct {
 	id      string
 	path    string
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_default.go containerd-1.4.12~ds1/runtime/v2/bundle_default.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_default.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_default.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,24 @@
+//go:build !linux
+// +build !linux
+
+/*
+   Copyright The containerd 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 v2
+
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory according to the needs of the current platform.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error { return nil }
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle.go containerd-1.4.12~ds1/runtime/v2/bundle.go
--- containerd-1.4.5~ds1/runtime/v2/bundle.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle.go	2021-11-18 03:52:12.000000000 +0800
@@ -72,7 +72,10 @@
 	if err := os.MkdirAll(filepath.Dir(b.Path), 0711); err != nil {
 		return nil, err
 	}
-	if err := os.Mkdir(b.Path, 0711); err != nil {
+	if err := os.Mkdir(b.Path, 0700); err != nil {
+		return nil, err
+	}
+	if err := prepareBundleDirectoryPermissions(b.Path, spec); err != nil {
 		return nil, err
 	}
 	paths = append(paths, b.Path)
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_linux.go containerd-1.4.12~ds1/runtime/v2/bundle_linux.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_linux.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_linux.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,74 @@
+/*
+   Copyright The containerd 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 v2
+
+import (
+	"encoding/json"
+	"os"
+
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory according to the needs of the current platform.
+// On Linux when user namespaces are enabled, the permissions are modified to
+// allow the remapped root GID to access the bundle.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
+	gid, err := remappedGID(spec)
+	if err != nil {
+		return err
+	}
+	if gid == 0 {
+		return nil
+	}
+	if err := os.Chown(path, -1, int(gid)); err != nil {
+		return err
+	}
+	return os.Chmod(path, 0710)
+}
+
+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
+// unmarshal.
+type ociSpecUserNS struct {
+	Linux *linuxSpecUserNS
+}
+
+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
+// unmarshal.
+type linuxSpecUserNS struct {
+	GIDMappings []specs.LinuxIDMapping
+}
+
+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
+// remappedGID returns an error.
+func remappedGID(spec []byte) (uint32, error) {
+	var ociSpec ociSpecUserNS
+	err := json.Unmarshal(spec, &ociSpec)
+	if err != nil {
+		return 0, err
+	}
+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
+		return 0, nil
+	}
+	for _, mapping := range ociSpec.Linux.GIDMappings {
+		if mapping.ContainerID == 0 {
+			return mapping.HostID, nil
+		}
+	}
+	return 0, nil
+}
diff -Nru containerd-1.4.5~ds1/script/setup/runc-version containerd-1.4.12~ds1/script/setup/runc-version
--- containerd-1.4.5~ds1/script/setup/runc-version	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/script/setup/runc-version	2021-11-18 03:52:12.000000000 +0800
@@ -1 +1 @@
-v1.0.0-rc94
+v1.0.2
diff -Nru containerd-1.4.5~ds1/snapshots/btrfs/btrfs.go containerd-1.4.12~ds1/snapshots/btrfs/btrfs.go
--- containerd-1.4.5~ds1/snapshots/btrfs/btrfs.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/snapshots/btrfs/btrfs.go	2021-11-18 03:52:12.000000000 +0800
@@ -63,11 +63,15 @@
 // root needs to be a mount point of btrfs.
 func NewSnapshotter(root string) (snapshots.Snapshotter, error) {
 	// If directory does not exist, create it
-	if _, err := os.Stat(root); err != nil {
+	if st, err := os.Stat(root); err != nil {
 		if !os.IsNotExist(err) {
 			return nil, err
 		}
-		if err := os.Mkdir(root, 0755); err != nil {
+		if err := os.Mkdir(root, 0700); err != nil {
+			return nil, err
+		}
+	} else if st.Mode()&os.ModePerm != 0700 {
+		if err := os.Chmod(root, 0700); err != nil {
 			return nil, err
 		}
 	}
diff -Nru containerd-1.4.5~ds1/snapshots/devmapper/snapshotter.go containerd-1.4.12~ds1/snapshots/devmapper/snapshotter.go
--- containerd-1.4.5~ds1/snapshots/devmapper/snapshotter.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/snapshots/devmapper/snapshotter.go	2021-11-18 03:52:12.000000000 +0800
@@ -232,7 +232,7 @@
 
 // View creates readonly thin device for the given snapshot key
 func (s *Snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
-	log.G(ctx).WithFields(logrus.Fields{"key": key, "parent": parent}).Debug("prepare")
+	log.G(ctx).WithFields(logrus.Fields{"key": key, "parent": parent}).Debug("view")
 
 	var (
 		mounts []mount.Mount
@@ -511,6 +511,8 @@
 }
 
 func (s *Snapshotter) Cleanup(ctx context.Context) error {
+	log.G(ctx).Debug("cleanup")
+
 	var removedDevices []*DeviceInfo
 
 	if !s.config.AsyncRemove {
diff -Nru containerd-1.4.5~ds1/Vagrantfile containerd-1.4.12~ds1/Vagrantfile
--- containerd-1.4.5~ds1/Vagrantfile	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/Vagrantfile	2021-11-18 03:52:12.000000000 +0800
@@ -77,7 +77,7 @@
   config.vm.provision "install-golang", type: "shell", run: "once" do |sh|
     sh.upload_path = "/tmp/vagrant-install-golang"
     sh.env = {
-        'GO_VERSION': ENV['GO_VERSION'] || "1.15.11",
+        'GO_VERSION': ENV['GO_VERSION'] || "1.16.10",
     }
     sh.inline = <<~SHELL
         #!/usr/bin/env bash
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os.go	2021-11-18 03:52:12.000000000 +0800
@@ -20,7 +20,6 @@
 	"io"
 	"io/ioutil"
 	"os"
-	"path/filepath"
 
 	"github.com/docker/docker/pkg/symlink"
 )
@@ -56,18 +55,6 @@
 	return os.Stat(name)
 }
 
-// ResolveSymbolicLink will follow any symbolic links
-func (RealOS) ResolveSymbolicLink(path string) (string, error) {
-	info, err := os.Lstat(path)
-	if err != nil {
-		return "", err
-	}
-	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
-		return path, nil
-	}
-	return filepath.EvalSymlinks(path)
-}
-
 // FollowSymlinkInScope will call symlink.FollowSymlinkInScope.
 func (RealOS) FollowSymlinkInScope(path, scope string) (string, error) {
 	return symlink.FollowSymlinkInScope(path, scope)
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go	2021-11-18 03:52:12.000000000 +0800
@@ -19,6 +19,9 @@
 package os
 
 import (
+	"os"
+	"path/filepath"
+
 	"github.com/containerd/containerd/mount"
 	"golang.org/x/sys/unix"
 )
@@ -57,3 +60,15 @@
 
 	return err
 }
+
+// ResolveSymbolicLink will follow any symbolic links
+func (RealOS) ResolveSymbolicLink(path string) (string, error) {
+	info, err := os.Lstat(path)
+	if err != nil {
+		return "", err
+	}
+	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
+		return path, nil
+	}
+	return filepath.EvalSymlinks(path)
+}
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go	2021-11-18 03:52:12.000000000 +0800
@@ -124,8 +124,10 @@
 		sandbox.NetNSPath = sandbox.NetNS.GetPath()
 		defer func() {
 			if retErr != nil {
+				deferCtx, deferCancel := ctrdutil.DeferContext()
+				defer deferCancel()
 				// Teardown network if an error is returned.
-				if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
+				if err := c.teardownPodNetwork(deferCtx, sandbox); err != nil {
 					log.G(ctx).WithError(err).Errorf("Failed to destroy network for sandbox %q", id)
 				}
 
diff -Nru containerd-1.4.5~ds1/version/version.go containerd-1.4.12~ds1/version/version.go
--- containerd-1.4.5~ds1/version/version.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/version/version.go	2021-11-18 03:52:12.000000000 +0800
@@ -23,7 +23,7 @@
 	Package = "github.com/containerd/containerd"
 
 	// Version holds the complete version number. Filled in at linking time.
-	Version = "1.4.5+unknown"
+	Version = "1.4.12+unknown"
 
 	// Revision is filled with the VCS (e.g. git) revision being used to build
 	// the program at linking time.

[ Other info ]

Since it's a Go package, and containerd as library is static linked in other packages.
However I don't think we need to rebuild other packages. The most fixes are targeted
for containerd as a program.

The RPi0/RPi1 workaround may need to rebuild docker.io. But I think we can skip this
time. As I think docker.io needs its own update for bullseye as well, to fix things
like supporting "clone3" syscall.
diff -Nru containerd-1.4.5~ds1/archive/tar_test.go containerd-1.4.12~ds1/archive/tar_test.go
--- containerd-1.4.5~ds1/archive/tar_test.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/archive/tar_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -243,6 +243,11 @@
 		return nil
 	}
 	errFileDiff := errors.New("files differ")
+	td, err := ioutil.TempDir("", "test-breakouts-")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(td)
 
 	isSymlinkFile := func(f string) func(string) error {
 		return func(root string) error {
@@ -744,6 +749,36 @@
 			// resolution ends up just removing etc
 			validator: fileNotExists("etc/passwd"),
 		},
+		{
+
+			name: "HardlinkSymlinkChmod",
+			w: func() tartest.WriterToTar {
+				p := filepath.Join(td, "perm400")
+				if err := ioutil.WriteFile(p, []byte("..."), 0400); err != nil {
+					t.Fatal(err)
+				}
+				ep := filepath.Join(td, "also-exists-outside-root")
+				if err := ioutil.WriteFile(ep, []byte("..."), 0640); err != nil {
+					t.Fatal(err)
+				}
+
+				return tartest.TarAll(
+					tc.Symlink(p, ep),
+					tc.Link(ep, "sketchylink"),
+				)
+			}(),
+			validator: func(string) error {
+				p := filepath.Join(td, "perm400")
+				fi, err := os.Lstat(p)
+				if err != nil {
+					return err
+				}
+				if perm := fi.Mode() & os.ModePerm; perm != 0400 {
+					return errors.Errorf("%s perm changed from 0400 to %04o", p, perm)
+				}
+				return nil
+			},
+		},
 	}
 
 	for _, bo := range breakouts {
diff -Nru containerd-1.4.5~ds1/archive/tar_unix.go containerd-1.4.12~ds1/archive/tar_unix.go
--- containerd-1.4.5~ds1/archive/tar_unix.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/archive/tar_unix.go	2021-11-18 03:52:12.000000000 +0800
@@ -113,7 +113,7 @@
 
 func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
 	if hdr.Typeflag == tar.TypeLink {
-		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
+		if fi, err := os.Lstat(path); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
 			if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
 				return err
 			}
diff -Nru containerd-1.4.5~ds1/client_test.go containerd-1.4.12~ds1/client_test.go
--- containerd-1.4.5~ds1/client_test.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/client_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -309,7 +309,7 @@
 	defer cancel()
 
 	cs := client.ContentStore()
-	img, err := client.Fetch(ctx, "docker.io/library/busybox:latest")
+	img, err := client.Fetch(ctx, "ghcr.io/containerd/busybox:latest")
 	if err != nil {
 		t.Fatal(err)
 	}
diff -Nru containerd-1.4.5~ds1/client_unix_test.go containerd-1.4.12~ds1/client_unix_test.go
--- containerd-1.4.5~ds1/client_unix_test.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/client_unix_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -40,17 +40,17 @@
 func init() {
 	switch runtime.GOARCH {
 	case "386":
-		testImage = "docker.io/i386/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest-i386"
 	case "arm":
-		testImage = "docker.io/arm32v6/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest-arm32v6"
 	case "arm64":
-		testImage = "docker.io/arm64v8/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest-arm64v8"
 	case "ppc64le":
-		testImage = "docker.io/ppc64le/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest-ppc64le"
 	case "s390x":
-		testImage = "docker.io/s390x/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest-s390x"
 	default:
-		testImage = "docker.io/library/alpine:latest"
+		testImage = "ghcr.io/containerd/alpine:latest"
 	}
 }
 
diff -Nru containerd-1.4.5~ds1/content/local/store.go containerd-1.4.12~ds1/content/local/store.go
--- containerd-1.4.5~ds1/content/local/store.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/content/local/store.go	2021-11-18 03:52:12.000000000 +0800
@@ -502,7 +502,7 @@
 	if ref != status.Ref {
 		// NOTE(stevvooe): This is fairly catastrophic. Either we have some
 		// layout corruption or a hash collision for the ref key.
-		return status, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref)
+		return status, errors.Errorf("ref key does not match: %v != %v", ref, status.Ref)
 	}
 
 	if total > 0 && status.Total > 0 && total != status.Total {
diff -Nru containerd-1.4.5~ds1/contrib/Dockerfile.test containerd-1.4.12~ds1/contrib/Dockerfile.test
--- containerd-1.4.5~ds1/contrib/Dockerfile.test	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/contrib/Dockerfile.test	2021-11-18 03:52:12.000000000 +0800
@@ -10,7 +10,7 @@
 #
 # docker build -t containerd-test --build-arg RUNC_VERSION=v1.0.0-rc93 -f Dockerfile.test ../
 
-ARG GOLANG_VERSION=1.15.11
+ARG GOLANG_VERSION=1.16.10
 
 FROM golang:${GOLANG_VERSION} AS golang-base
 RUN mkdir -p /go/src/github.com/containerd/containerd
diff -Nru containerd-1.4.5~ds1/contrib/seccomp/seccomp_default.go containerd-1.4.12~ds1/contrib/seccomp/seccomp_default.go
--- containerd-1.4.5~ds1/contrib/seccomp/seccomp_default.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/contrib/seccomp/seccomp_default.go	2021-11-18 03:52:12.000000000 +0800
@@ -49,6 +49,7 @@
 
 // DefaultProfile defines the allowed syscalls for the default seccomp profile.
 func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
+	nosys := uint(unix.ENOSYS)
 	syscalls := []specs.LinuxSyscall{
 		{
 			Names: []string{
@@ -524,6 +525,7 @@
 				Names: []string{
 					"bpf",
 					"clone",
+					"clone3",
 					"fanotify_init",
 					"lookup_dcookie",
 					"mount",
@@ -648,6 +650,15 @@
 				},
 			})
 		}
+		// clone3 is explicitly requested to give ENOSYS instead of the default EPERM, when CAP_SYS_ADMIN is unset
+		// https://github.com/moby/moby/pull/42681
+		s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{
+			Names: []string{
+				"clone3",
+			},
+			Action:   specs.ActErrno,
+			ErrnoRet: &nosys,
+		})
 	}
 
 	return s
diff -Nru containerd-1.4.5~ds1/debian/changelog containerd-1.4.12~ds1/debian/changelog
--- containerd-1.4.5~ds1/debian/changelog	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/changelog	2021-11-23 18:42:16.000000000 +0800
@@ -1,3 +1,34 @@
+containerd (1.4.12~ds1-1~deb11u1) bullseye; urgency=medium
+
+  * New upstream version 1.4.12~ds1
+    + 1.4.12
+      * Mitigate CVE-2021-41190: Handle ambiguous OCI manifest parsing
+      * Update pull to try next mirror for non-404 errors
+      * Update pull to handle of non-https urls in descriptors
+    + 1.4.11
+      * CVE-2021-41103: Fix insufficiently restricted permissions on container
+        root and plugin directories
+    + 1.4.10
+      * Support "clone3" in default seccomp profile
+      * Fix panic in metadata content writer on copy error
+    + 1.4.9
+      * Update pull authorization logic on redirect
+      * Fix user agent used for fetching registry authentication tokens
+    + 1.4.8
+      * CVE-2021-32760: Archive package allows chmod of file outside of unpack
+        target directory
+    + 1.4.7
+      * Fix invalid validation error checking
+      * Fix error on image pull resume
+  * Refresh patches
+    + Drop CVE-2021-32760 patch
+    + Drop CVE-2021-41103 patch
+    + Refresh 0005-backport-github.com-containerd-containerd-remotes.patch
+      with latest 1.5 release branch
+  * Backport RPi1/RPi0 workaround (Closes: #998909)
+
+ -- Shengjing Zhu <zhsj@debian.org>  Tue, 23 Nov 2021 18:42:16 +0800
+
 containerd (1.4.5~ds1-2+deb11u1) bullseye-security; urgency=high
 
   * CVE-2021-41103: Insufficiently restricted permissions on container
diff -Nru containerd-1.4.5~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch containerd-1.4.12~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch
--- containerd-1.4.5~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0004-Add-cgo-tag-to-btrfs-plugin.patch	2021-11-23 18:42:16.000000000 +0800
@@ -20,7 +20,7 @@
  /*
     Copyright The containerd Authors.
 diff --git a/snapshots/btrfs/btrfs.go b/snapshots/btrfs/btrfs.go
-index ea90853..eef883b 100644
+index 78f825c..778b783 100644
 --- a/snapshots/btrfs/btrfs.go
 +++ b/snapshots/btrfs/btrfs.go
 @@ -1,4 +1,4 @@
diff -Nru containerd-1.4.5~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch containerd-1.4.12~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch
--- containerd-1.4.5~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0005-backport-github.com-containerd-containerd-remotes.patch	2021-11-23 18:42:16.000000000 +0800
@@ -1,6 +1,7 @@
 From: Shengjing Zhu <zhsj@debian.org>
-Date: Fri, 5 Mar 2021 16:35:17 +0800
-Subject: backport_github=2Ecom/containerd/containerd/remotes
+Date: Tue, 23 Nov 2021 15:49:57 +0800
+Subject: =?utf-8?q?backport_github=2Ecom/containerd/containerd/remotes?=
+ =?utf-8?q?=C2=AC?=
 
 For building docker.io 20.10
 
@@ -10,19 +11,19 @@
 
 Forwarded: not-needed
 ---
- remotes/docker/auth.go           | 198 ---------------------------
- remotes/docker/auth/fetch.go     | 202 +++++++++++++++++++++++++++
- remotes/docker/auth/parse.go     | 203 ++++++++++++++++++++++++++++
- remotes/docker/authorizer.go     | 285 ++++++++++-----------------------------
+ remotes/docker/auth.go           | 198 --------------------------
+ remotes/docker/auth/fetch.go     | 209 ++++++++++++++++++++++++++++
+ remotes/docker/auth/parse.go     | 203 +++++++++++++++++++++++++++
+ remotes/docker/authorizer.go     | 292 +++++++++------------------------------
  remotes/docker/errcode.go        |   2 +-
  remotes/docker/fetcher.go        |   2 +-
  remotes/docker/httpreadseeker.go |   2 +-
- remotes/docker/pusher.go         |  36 +++--
- remotes/docker/resolver.go       |  47 +++----
+ remotes/docker/pusher.go         |  38 +++--
+ remotes/docker/resolver.go       |  49 +++----
  remotes/docker/scope.go          |  14 +-
  remotes/docker/scope_test.go     |   4 +-
- remotes/errors/errors.go         |  46 +++++++
- 12 files changed, 573 insertions(+), 468 deletions(-)
+ remotes/errors/errors.go         |  46 ++++++
+ 12 files changed, 581 insertions(+), 478 deletions(-)
  delete mode 100644 remotes/docker/auth.go
  create mode 100644 remotes/docker/auth/fetch.go
  create mode 100644 remotes/docker/auth/parse.go
@@ -234,10 +235,10 @@
 -}
 diff --git a/remotes/docker/auth/fetch.go b/remotes/docker/auth/fetch.go
 new file mode 100644
-index 0000000..0d01c81
+index 0000000..8b0a87e
 --- /dev/null
 +++ b/remotes/docker/auth/fetch.go
-@@ -0,0 +1,202 @@
+@@ -0,0 +1,209 @@
 +/*
 +   Copyright The containerd Authors.
 +
@@ -266,6 +267,7 @@
 +
 +	"github.com/containerd/containerd/log"
 +	remoteserrors "github.com/containerd/containerd/remotes/errors"
++	"github.com/containerd/containerd/version"
 +	"github.com/pkg/errors"
 +	"golang.org/x/net/context/ctxhttp"
 +)
@@ -349,6 +351,9 @@
 +	for k, v := range headers {
 +		req.Header[k] = append(req.Header[k], v...)
 +	}
++	if len(req.Header.Get("User-Agent")) == 0 {
++		req.Header.Set("User-Agent", "containerd/"+version.Version)
++	}
 +
 +	resp, err := ctxhttp.Do(ctx, client, req)
 +	if err != nil {
@@ -393,6 +398,9 @@
 +	for k, v := range headers {
 +		req.Header[k] = append(req.Header[k], v...)
 +	}
++	if len(req.Header.Get("User-Agent")) == 0 {
++		req.Header.Set("User-Agent", "containerd/"+version.Version)
++	}
 +
 +	reqParams := req.URL.Query()
 +
@@ -650,10 +658,10 @@
 +	return "", ""
 +}
 diff --git a/remotes/docker/authorizer.go b/remotes/docker/authorizer.go
-index 001423a..67e4aea 100644
+index 2f459b7..67e4aea 100644
 --- a/remotes/docker/authorizer.go
 +++ b/remotes/docker/authorizer.go
-@@ -19,21 +19,17 @@ package docker
+@@ -19,22 +19,17 @@ package docker
  import (
  	"context"
  	"encoding/base64"
@@ -669,6 +677,7 @@
  
  	"github.com/containerd/containerd/errdefs"
  	"github.com/containerd/containerd/log"
+-	"github.com/containerd/containerd/version"
 +	"github.com/containerd/containerd/remotes/docker/auth"
 +	remoteerrors "github.com/containerd/containerd/remotes/errors"
  	"github.com/pkg/errors"
@@ -677,7 +686,7 @@
  )
  
  type dockerAuthorizer struct {
-@@ -135,8 +131,8 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -136,8 +131,8 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  
  	a.mu.Lock()
  	defer a.mu.Unlock()
@@ -688,7 +697,7 @@
  			if err := invalidAuthorization(c, responses); err != nil {
  				delete(a.handlers, host)
  				return err
-@@ -152,26 +148,35 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -153,26 +148,35 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  				return nil
  			}
  
@@ -731,7 +740,7 @@
  				return nil
  			}
  		}
-@@ -179,38 +184,6 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
+@@ -180,38 +184,6 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
  	return errors.Wrap(errdefs.ErrNotImplemented, "failed to find supported auth scheme")
  }
  
@@ -770,7 +779,7 @@
  // authResult is used to control limit rate.
  type authResult struct {
  	sync.WaitGroup
-@@ -227,17 +200,17 @@ type authHandler struct {
+@@ -228,17 +200,17 @@ type authHandler struct {
  	client *http.Client
  
  	// only support basic and bearer schemes
@@ -791,7 +800,7 @@
  	return &authHandler{
  		header:       hdr,
  		client:       client,
-@@ -249,17 +222,17 @@ func newAuthHandler(client *http.Client, hdr http.Header, scheme authenticationS
+@@ -250,17 +222,17 @@ func newAuthHandler(client *http.Client, hdr http.Header, scheme authenticationS
  
  func (ah *authHandler) authorize(ctx context.Context) (string, error) {
  	switch ah.scheme {
@@ -813,7 +822,7 @@
  
  	if username == "" || secret == "" {
  		return "", fmt.Errorf("failed to handle basic auth because missing username or secret")
-@@ -269,14 +242,14 @@ func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) {
+@@ -270,14 +242,14 @@ func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) {
  	return fmt.Sprintf("Basic %s", auth), nil
  }
  
@@ -831,7 +840,7 @@
  
  	ah.Lock()
  	if r, exist := ah.scopedTokens[scoped]; exist {
-@@ -291,174 +264,52 @@ func (ah *authHandler) doBearerAuth(ctx context.Context) (string, error) {
+@@ -292,180 +264,52 @@ func (ah *authHandler) doBearerAuth(ctx context.Context) (string, error) {
  	ah.scopedTokens[scoped] = r
  	ah.Unlock()
  
@@ -910,6 +919,9 @@
 -			req.Header[k] = append(req.Header[k], v...)
 -		}
 -	}
+-	if len(req.Header.Get("User-Agent")) == 0 {
+-		req.Header.Set("User-Agent", "containerd/"+version.Version)
+-	}
 -
 -	resp, err := ctxhttp.Do(ctx, ah.client, req)
 -	if err != nil {
@@ -984,6 +996,9 @@
  		}
 +		return resp.AccessToken, nil
  	}
+-	if len(req.Header.Get("User-Agent")) == 0 {
+-		req.Header.Set("User-Agent", "containerd/"+version.Version)
+-	}
 -
 -	reqParams := req.URL.Query()
 -
@@ -1058,7 +1073,7 @@
  	Message string
  
 diff --git a/remotes/docker/fetcher.go b/remotes/docker/fetcher.go
-index cd0168b..9d6708d 100644
+index 5aaaf9e..4b2c10e 100644
 --- a/remotes/docker/fetcher.go
 +++ b/remotes/docker/fetcher.go
 @@ -45,7 +45,7 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
@@ -1084,7 +1099,7 @@
  
  		if hrs.rc != nil {
 diff --git a/remotes/docker/pusher.go b/remotes/docker/pusher.go
-index d95e0c8..94a270c 100644
+index d46396b..c367b1e 100644
 --- a/remotes/docker/pusher.go
 +++ b/remotes/docker/pusher.go
 @@ -30,6 +30,7 @@ import (
@@ -1104,19 +1119,20 @@
  	if err != nil {
  		return nil, err
  	}
-@@ -112,8 +113,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -113,9 +114,10 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  				return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
  			}
  		} else if resp.StatusCode != http.StatusNotFound {
--			// TODO: log error
--			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 +			err := remoteserrors.NewUnexpectedStatusErr(resp)
 +			log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response")
+ 			resp.Body.Close()
+-			// TODO: log error
+-			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 +			return nil, err
  		}
+ 		resp.Body.Close()
  	}
- 
-@@ -128,7 +130,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -131,7 +133,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		var resp *http.Response
  		if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" {
  			preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo)
@@ -1125,7 +1141,7 @@
  
  			// NOTE: the fromRepo might be private repo and
  			// auth service still can grant token without error.
-@@ -166,8 +168,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -170,8 +172,9 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  			})
  			return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
  		default:
@@ -1137,7 +1153,7 @@
  		}
  
  		var (
-@@ -219,7 +222,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -223,7 +226,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  	// TODO: Support chunked upload
  
  	pr, pw := io.Pipe()
@@ -1146,7 +1162,7 @@
  	body := ioutil.NopCloser(pr)
  
  	req.body = func() (io.ReadCloser, error) {
-@@ -237,6 +240,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -241,6 +244,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		defer close(respC)
  		resp, err := req.doWithRetries(ctx, nil)
  		if err != nil {
@@ -1154,7 +1170,7 @@
  			pr.CloseWithError(err)
  			return
  		}
-@@ -244,10 +248,11 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
+@@ -248,10 +252,11 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
  		switch resp.StatusCode {
  		case http.StatusOK, http.StatusCreated, http.StatusNoContent:
  		default:
@@ -1169,7 +1185,7 @@
  	}()
  
  	return &pushWriter{
-@@ -280,12 +285,17 @@ func getManifestPath(object string, dgst digest.Digest) []string {
+@@ -284,12 +289,17 @@ func getManifestPath(object string, dgst digest.Digest) []string {
  	return []string{"manifests", object}
  }
  
@@ -1188,7 +1204,7 @@
  	isManifest bool
  
  	expected digest.Digest
-@@ -335,8 +345,8 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
+@@ -339,10 +349,10 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
  
  	// TODO: timeout waiting for response
  	resp := <-pw.responseC
@@ -1197,10 +1213,13 @@
 +	if resp.err != nil {
 +		return resp.err
  	}
+-	defer resp.Body.Close()
++	defer resp.Response.Body.Close()
  
  	// 201 is specified return status, some registries return
+ 	// 200, 202 or 204.
 diff --git a/remotes/docker/resolver.go b/remotes/docker/resolver.go
-index aea092c..866379e 100644
+index 40831f1..d6ccd70 100644
 --- a/remotes/docker/resolver.go
 +++ b/remotes/docker/resolver.go
 @@ -41,10 +41,6 @@ import (
@@ -1235,8 +1254,8 @@
 -	}
 -
  	var (
- 		lastErr error
- 		paths   [][]string
+ 		firstErr error
+ 		paths    [][]string
 @@ -267,7 +258,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
  		return "", ocispec.Descriptor{}, errors.Wrap(errdefs.ErrNotFound, "no resolve hosts")
  	}
@@ -1246,7 +1265,22 @@
  	if err != nil {
  		return "", ocispec.Descriptor{}, err
  	}
-@@ -393,12 +384,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
+@@ -295,14 +286,12 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
+ 				if firstErr == nil {
+ 					firstErr = err
+ 				}
+-				log.G(ctx).WithError(err).Info("trying next host")
+ 				continue // try another host
+ 			}
+ 			resp.Body.Close() // don't care about body contents.
+ 
+ 			if resp.StatusCode > 299 {
+ 				if resp.StatusCode == http.StatusNotFound {
+-					log.G(ctx).Info("trying next host - response was http.StatusNotFound")
+ 					continue
+ 				}
+ 				if resp.StatusCode > 399 {
+@@ -404,12 +393,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
  }
  
  func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
@@ -1260,7 +1294,7 @@
  	if err != nil {
  		return nil, err
  	}
-@@ -409,23 +395,27 @@ func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetch
+@@ -420,23 +404,27 @@ func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetch
  }
  
  func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
@@ -1295,7 +1329,7 @@
  type dockerBase struct {
  	refspec    reference.Spec
  	repository string
-@@ -457,10 +447,11 @@ func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) {
+@@ -468,10 +456,11 @@ func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) {
  }
  
  func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request {
diff -Nru containerd-1.4.5~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch containerd-1.4.12~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch
--- containerd-1.4.5~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0008-Add-RPi1-RPi0-workaround.patch	2021-11-23 18:42:16.000000000 +0800
@@ -0,0 +1,35 @@
+From: Tianon Gravi <admwiggin@gmail.com>
+Date: Fri, 4 Sep 2020 14:12:04 -0700
+Subject: Add RPi1/RPi0 workaround
+
+On the very popular Raspberry Pi 1 and Zero devices, the CPU is actually ARMv6, but the chip happens to support the feature bit the kernel uses to differentiate v6/v7, so it gets reported as "CPU architecture: 7" and thus fails to run many of the images that get pulled.
+
+To account for this very popular edge case, this also checks "model name" which on these chips will begin with "ARMv6-compatible" -- we could also check uname, but getCPUInfo is already handy, low overhead, and mirrors the code before this.
+
+Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
+
+Origin: backport, https://github.com/containerd/containerd/commit/2055e12953bb538228d8d9fe627fa545d7cf82be
+---
+ platforms/cpuinfo.go | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/platforms/cpuinfo.go b/platforms/cpuinfo.go
+index db65a72..0512bc9 100644
+--- a/platforms/cpuinfo.go
++++ b/platforms/cpuinfo.go
+@@ -96,6 +96,15 @@ func getCPUVariant() string {
+ 		return ""
+ 	}
+ 
++	// handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
++	// https://www.raspberrypi.org/forums/viewtopic.php?t=12614
++	if runtime.GOARCH == "arm" && variant == "7" {
++		model, err := getCPUInfo("model name")
++		if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
++			variant = "6"
++		}
++	}
++
+ 	switch strings.ToLower(variant) {
+ 	case "8", "aarch64":
+ 		// special case: if running a 32-bit userspace on aarch64, the variant should be "v7"
diff -Nru containerd-1.4.5~ds1/debian/patches/0008-CVE-2021-32760.patch containerd-1.4.12~ds1/debian/patches/0008-CVE-2021-32760.patch
--- containerd-1.4.5~ds1/debian/patches/0008-CVE-2021-32760.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0008-CVE-2021-32760.patch	1970-01-01 08:00:00.000000000 +0800
@@ -1,91 +0,0 @@
-From 03aa748c11663e87a72fab92b7ab7c88c28bf13e Mon Sep 17 00:00:00 2001
-From: Derek McGowan <derek@mcg.dev>
-Date: Tue, 6 Jul 2021 12:37:54 -0700
-Subject: [PATCH 1/2] Use chmod path for checking symlink
-
-Signed-off-by: Derek McGowan <derek@mcg.dev>
-(cherry picked from commit 27597ccfd30d8aa06b448062896bccfb33ad8f22)
-Signed-off-by: Derek McGowan <derek@mcg.dev>
----
- archive/tar_unix.go | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/archive/tar_unix.go b/archive/tar_unix.go
-index 6e89d2fdbc9..c22e79bf2be 100644
---- a/archive/tar_unix.go
-+++ b/archive/tar_unix.go
-@@ -113,7 +113,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
- 
- func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
- 	if hdr.Typeflag == tar.TypeLink {
--		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
-+		if fi, err := os.Lstat(path); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
- 			if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
- 				return err
- 			}
-
-From 664f93ead6c613a9f0e9932dfa75c602dbe35f41 Mon Sep 17 00:00:00 2001
-From: Derek McGowan <derek@mcg.dev>
-Date: Tue, 6 Jul 2021 16:23:03 -0700
-Subject: [PATCH 2/2] Add test for archive breakout test for lchmod
-
-Signed-off-by: Derek McGowan <derek@mcg.dev>
-(cherry picked from commit ad81d76219a75559cb9d74a214efe0d779d7cbef)
-Signed-off-by: Derek McGowan <derek@mcg.dev>
----
- archive/tar_test.go | 35 +++++++++++++++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
-
-diff --git a/archive/tar_test.go b/archive/tar_test.go
-index 568f5a95f1c..8ffd3f221b8 100644
---- a/archive/tar_test.go
-+++ b/archive/tar_test.go
-@@ -243,6 +243,11 @@ func TestBreakouts(t *testing.T) {
- 		return nil
- 	}
- 	errFileDiff := errors.New("files differ")
-+	td, err := ioutil.TempDir("", "test-breakouts-")
-+	if err != nil {
-+		t.Fatal(err)
-+	}
-+	defer os.RemoveAll(td)
- 
- 	isSymlinkFile := func(f string) func(string) error {
- 		return func(root string) error {
-@@ -744,6 +749,36 @@ func TestBreakouts(t *testing.T) {
- 			// resolution ends up just removing etc
- 			validator: fileNotExists("etc/passwd"),
- 		},
-+		{
-+
-+			name: "HardlinkSymlinkChmod",
-+			w: func() tartest.WriterToTar {
-+				p := filepath.Join(td, "perm400")
-+				if err := ioutil.WriteFile(p, []byte("..."), 0400); err != nil {
-+					t.Fatal(err)
-+				}
-+				ep := filepath.Join(td, "also-exists-outside-root")
-+				if err := ioutil.WriteFile(ep, []byte("..."), 0640); err != nil {
-+					t.Fatal(err)
-+				}
-+
-+				return tartest.TarAll(
-+					tc.Symlink(p, ep),
-+					tc.Link(ep, "sketchylink"),
-+				)
-+			}(),
-+			validator: func(string) error {
-+				p := filepath.Join(td, "perm400")
-+				fi, err := os.Lstat(p)
-+				if err != nil {
-+					return err
-+				}
-+				if perm := fi.Mode() & os.ModePerm; perm != 0400 {
-+					return errors.Errorf("%s perm changed from 0400 to %04o", p, perm)
-+				}
-+				return nil
-+			},
-+		},
- 	}
- 
- 	for _, bo := range breakouts {
diff -Nru containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch
--- containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch	1970-01-01 08:00:00.000000000 +0800
@@ -1,349 +0,0 @@
-From: Samuel Karp <skarp@amazon.com>
-Date: Mon, 20 Sep 2021 16:20:26 -0700
-Subject: v2 runtime: reduce permissions for bundle dir
-
-Bundle directory permissions should be 0700 by default.  On Linux with
-user namespaces enabled, the remapped root also needs access to the
-bundle directory.  In this case, the bundle directory is modified to
-0710 and group ownership is changed to the remapped root group.
-
-Signed-off-by: Samuel Karp <skarp@amazon.com>
----
- runtime/v2/bundle.go            |   5 +-
- runtime/v2/bundle_default.go    |  24 ++++++
- runtime/v2/bundle_linux.go      |  74 ++++++++++++++++++
- runtime/v2/bundle_linux_test.go | 166 ++++++++++++++++++++++++++++++++++++++++
- runtime/v2/bundle_test.go       |  23 ++++++
- 5 files changed, 291 insertions(+), 1 deletion(-)
- create mode 100644 runtime/v2/bundle_default.go
- create mode 100644 runtime/v2/bundle_linux.go
- create mode 100644 runtime/v2/bundle_linux_test.go
- create mode 100644 runtime/v2/bundle_test.go
-
-diff --git a/runtime/v2/bundle.go b/runtime/v2/bundle.go
-index 1a58e62..954163b 100644
---- a/runtime/v2/bundle.go
-+++ b/runtime/v2/bundle.go
-@@ -72,7 +72,10 @@ func NewBundle(ctx context.Context, root, state, id string, spec []byte) (b *Bun
- 	if err := os.MkdirAll(filepath.Dir(b.Path), 0711); err != nil {
- 		return nil, err
- 	}
--	if err := os.Mkdir(b.Path, 0711); err != nil {
-+	if err := os.Mkdir(b.Path, 0700); err != nil {
-+		return nil, err
-+	}
-+	if err := prepareBundleDirectoryPermissions(b.Path, spec); err != nil {
- 		return nil, err
- 	}
- 	paths = append(paths, b.Path)
-diff --git a/runtime/v2/bundle_default.go b/runtime/v2/bundle_default.go
-new file mode 100644
-index 0000000..2be40c8
---- /dev/null
-+++ b/runtime/v2/bundle_default.go
-@@ -0,0 +1,24 @@
-+//go:build !linux
-+// +build !linux
-+
-+/*
-+   Copyright The containerd 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 v2
-+
-+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
-+// directory according to the needs of the current platform.
-+func prepareBundleDirectoryPermissions(path string, spec []byte) error { return nil }
-diff --git a/runtime/v2/bundle_linux.go b/runtime/v2/bundle_linux.go
-new file mode 100644
-index 0000000..5f1915d
---- /dev/null
-+++ b/runtime/v2/bundle_linux.go
-@@ -0,0 +1,74 @@
-+/*
-+   Copyright The containerd 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 v2
-+
-+import (
-+	"encoding/json"
-+	"os"
-+
-+	"github.com/opencontainers/runtime-spec/specs-go"
-+)
-+
-+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
-+// directory according to the needs of the current platform.
-+// On Linux when user namespaces are enabled, the permissions are modified to
-+// allow the remapped root GID to access the bundle.
-+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
-+	gid, err := remappedGID(spec)
-+	if err != nil {
-+		return err
-+	}
-+	if gid == 0 {
-+		return nil
-+	}
-+	if err := os.Chown(path, -1, int(gid)); err != nil {
-+		return err
-+	}
-+	return os.Chmod(path, 0710)
-+}
-+
-+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
-+// unmarshal.
-+type ociSpecUserNS struct {
-+	Linux *linuxSpecUserNS
-+}
-+
-+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
-+// unmarshal.
-+type linuxSpecUserNS struct {
-+	GIDMappings []specs.LinuxIDMapping
-+}
-+
-+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
-+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
-+// remappedGID returns an error.
-+func remappedGID(spec []byte) (uint32, error) {
-+	var ociSpec ociSpecUserNS
-+	err := json.Unmarshal(spec, &ociSpec)
-+	if err != nil {
-+		return 0, err
-+	}
-+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
-+		return 0, nil
-+	}
-+	for _, mapping := range ociSpec.Linux.GIDMappings {
-+		if mapping.ContainerID == 0 {
-+			return mapping.HostID, nil
-+		}
-+	}
-+	return 0, nil
-+}
-diff --git a/runtime/v2/bundle_linux_test.go b/runtime/v2/bundle_linux_test.go
-new file mode 100644
-index 0000000..617b105
---- /dev/null
-+++ b/runtime/v2/bundle_linux_test.go
-@@ -0,0 +1,166 @@
-+/*
-+   Copyright The containerd 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 v2
-+
-+import (
-+	"context"
-+	"encoding/json"
-+	"fmt"
-+	"io/ioutil"
-+	"os"
-+	"path/filepath"
-+	"strconv"
-+	"syscall"
-+	"testing"
-+
-+	"github.com/containerd/containerd/namespaces"
-+	"github.com/containerd/containerd/oci"
-+	"github.com/containerd/containerd/pkg/testutil"
-+	"github.com/opencontainers/runtime-spec/specs-go"
-+)
-+
-+func TestNewBundle(t *testing.T) {
-+	testutil.RequiresRoot(t)
-+	tests := []struct {
-+		userns bool
-+	}{{
-+		userns: false,
-+	}, {
-+		userns: true,
-+	}}
-+	const usernsGID = 4200
-+
-+	for i, tc := range tests {
-+		t.Run(strconv.Itoa(i), func(t *testing.T) {
-+			dir, err := ioutil.TempDir("", "test-new-bundle")
-+			if err != nil {
-+				t.Fatal("failed to create test directory", err)
-+			}
-+			defer os.RemoveAll(dir)
-+			work := filepath.Join(dir, "work")
-+			state := filepath.Join(dir, "state")
-+			id := fmt.Sprintf("new-bundle-%d", i)
-+			spec := oci.Spec{}
-+			if tc.userns {
-+				spec.Linux = &specs.Linux{
-+					GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}},
-+				}
-+			}
-+			specBytes, err := json.Marshal(&spec)
-+			if err != nil {
-+				t.Fatal("failed to marshal spec", err)
-+			}
-+
-+			ctx := namespaces.WithNamespace(context.TODO(), namespaces.Default)
-+			b, err := NewBundle(ctx, work, state, id, specBytes)
-+			if err != nil {
-+				t.Fatal("NewBundle should succeed", err)
-+			}
-+			if b == nil {
-+				t.Fatal("bundle should not be nil")
-+			}
-+
-+			fi, err := os.Stat(b.Path)
-+			if err != nil {
-+				t.Error("should be able to stat bundle path", err)
-+			}
-+			if tc.userns {
-+				if fi.Mode() != os.ModeDir|0710 {
-+					t.Error("bundle path should be a directory with perm 0710")
-+				}
-+			} else {
-+				if fi.Mode() != os.ModeDir|0700 {
-+					t.Error("bundle path should be a directory with perm 0700")
-+				}
-+			}
-+			stat, ok := fi.Sys().(*syscall.Stat_t)
-+			if !ok {
-+				t.Fatal("should assert to *syscall.Stat_t")
-+			}
-+			expectedGID := uint32(0)
-+			if tc.userns {
-+				expectedGID = usernsGID
-+			}
-+			if expectedGID != stat.Gid {
-+				t.Error("gid should match", expectedGID, stat.Gid)
-+			}
-+		})
-+	}
-+}
-+
-+func TestRemappedGID(t *testing.T) {
-+	tests := []struct {
-+		spec oci.Spec
-+		gid  uint32
-+	}{{
-+		// empty spec
-+		spec: oci.Spec{},
-+		gid:  0,
-+	}, {
-+		// empty Linux section
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{},
-+		},
-+		gid: 0,
-+	}, {
-+		// empty ID mappings
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: make([]specs.LinuxIDMapping, 0),
-+			},
-+		},
-+		gid: 0,
-+	}, {
-+		// valid ID mapping
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: []specs.LinuxIDMapping{{
-+					ContainerID: 0,
-+					HostID:      1000,
-+				}},
-+			},
-+		},
-+		gid: 1000,
-+	}, {
-+		// missing ID mapping
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: []specs.LinuxIDMapping{{
-+					ContainerID: 100,
-+					HostID:      1000,
-+				}},
-+			},
-+		},
-+		gid: 0,
-+	}}
-+
-+	for i, tc := range tests {
-+		t.Run(strconv.Itoa(i), func(t *testing.T) {
-+			s, err := json.Marshal(tc.spec)
-+			if err != nil {
-+				t.Fatal("failed to marshal spec", err)
-+			}
-+			gid, err := remappedGID(s)
-+			if err != nil {
-+				t.Error("should unmarshal successfully", err)
-+			}
-+			if tc.gid != gid {
-+				t.Error("expected GID to match", tc.gid, gid)
-+			}
-+		})
-+	}
-+}
-diff --git a/runtime/v2/bundle_test.go b/runtime/v2/bundle_test.go
-new file mode 100644
-index 0000000..54e5f24
---- /dev/null
-+++ b/runtime/v2/bundle_test.go
-@@ -0,0 +1,23 @@
-+/*
-+   Copyright The containerd 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 v2
-+
-+import (
-+	// When testutil is imported for one platform (bundle_linux_test.go) it
-+	// should be imported for all platforms.
-+	_ "github.com/containerd/containerd/pkg/testutil"
-+)
diff -Nru containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch
--- containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch	1970-01-01 08:00:00.000000000 +0800
@@ -1,285 +0,0 @@
-From: Samuel Karp <skarp@amazon.com>
-Date: Tue, 21 Sep 2021 13:46:40 -0700
-Subject: v1 runtime: reduce permissions for bundle dir
-
-Bundle directory permissions should be 0700 by default.  On Linux with
-user namespaces enabled, the remapped root also needs access to the
-bundle directory.  In this case, the bundle directory is modified to
-0710 and group ownership is changed to the remapped root group.
-
-Port of the same change for the v2 runtime
-
-Signed-off-by: Samuel Karp <skarp@amazon.com>
----
- runtime/v1/linux/bundle.go      |  56 +++++++++++++-
- runtime/v1/linux/bundle_test.go | 166 ++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 221 insertions(+), 1 deletion(-)
- create mode 100644 runtime/v1/linux/bundle_test.go
-
-diff --git a/runtime/v1/linux/bundle.go b/runtime/v1/linux/bundle.go
-index 9d0a6c4..48d81e8 100644
---- a/runtime/v1/linux/bundle.go
-+++ b/runtime/v1/linux/bundle.go
-@@ -21,6 +21,7 @@ package linux
- import (
- 	"context"
- 	"crypto/sha256"
-+	"encoding/json"
- 	"fmt"
- 	"io/ioutil"
- 	"os"
-@@ -30,6 +31,7 @@ import (
- 	"github.com/containerd/containerd/runtime/linux/runctypes"
- 	"github.com/containerd/containerd/runtime/v1/shim"
- 	"github.com/containerd/containerd/runtime/v1/shim/client"
-+	"github.com/opencontainers/runtime-spec/specs-go"
- 	"github.com/pkg/errors"
- )
- 
-@@ -48,7 +50,7 @@ func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
- 		return nil, err
- 	}
- 	path = filepath.Join(path, id)
--	if err := os.Mkdir(path, 0711); err != nil {
-+	if err := os.Mkdir(path, 0700); err != nil {
- 		return nil, err
- 	}
- 	defer func() {
-@@ -56,6 +58,9 @@ func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
- 			os.RemoveAll(path)
- 		}
- 	}()
-+	if err := prepareBundleDirectoryPermissions(path, spec); err != nil {
-+		return nil, err
-+	}
- 	workDir = filepath.Join(workDir, id)
- 	if err := os.MkdirAll(workDir, 0711); err != nil {
- 		return nil, err
-@@ -77,6 +82,55 @@ func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
- 	}, err
- }
- 
-+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
-+// directory. When user namespaces are enabled, the permissions are modified
-+// to allow the remapped root GID to access the bundle.
-+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
-+	gid, err := remappedGID(spec)
-+	if err != nil {
-+		return err
-+	}
-+	if gid == 0 {
-+		return nil
-+	}
-+	if err := os.Chown(path, -1, int(gid)); err != nil {
-+		return err
-+	}
-+	return os.Chmod(path, 0710)
-+}
-+
-+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
-+// unmarshal.
-+type ociSpecUserNS struct {
-+	Linux *linuxSpecUserNS
-+}
-+
-+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
-+// unmarshal.
-+type linuxSpecUserNS struct {
-+	GIDMappings []specs.LinuxIDMapping
-+}
-+
-+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
-+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
-+// remappedGID returns an error.
-+func remappedGID(spec []byte) (uint32, error) {
-+	var ociSpec ociSpecUserNS
-+	err := json.Unmarshal(spec, &ociSpec)
-+	if err != nil {
-+		return 0, err
-+	}
-+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
-+		return 0, nil
-+	}
-+	for _, mapping := range ociSpec.Linux.GIDMappings {
-+		if mapping.ContainerID == 0 {
-+			return mapping.HostID, nil
-+		}
-+	}
-+	return 0, nil
-+}
-+
- type bundle struct {
- 	id      string
- 	path    string
-diff --git a/runtime/v1/linux/bundle_test.go b/runtime/v1/linux/bundle_test.go
-new file mode 100644
-index 0000000..adf39b4
---- /dev/null
-+++ b/runtime/v1/linux/bundle_test.go
-@@ -0,0 +1,166 @@
-+//go:build linux
-+// +build linux
-+
-+/*
-+   Copyright The containerd 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 linux
-+
-+import (
-+	"encoding/json"
-+	"fmt"
-+	"io/ioutil"
-+	"os"
-+	"path/filepath"
-+	"strconv"
-+	"syscall"
-+	"testing"
-+
-+	"github.com/containerd/containerd/oci"
-+	"github.com/containerd/continuity/testutil"
-+	"github.com/opencontainers/runtime-spec/specs-go"
-+)
-+
-+func TestNewBundle(t *testing.T) {
-+	testutil.RequiresRoot(t)
-+	tests := []struct {
-+		userns bool
-+	}{{
-+		userns: false,
-+	}, {
-+		userns: true,
-+	}}
-+	const usernsGID = 4200
-+
-+	for i, tc := range tests {
-+		t.Run(strconv.Itoa(i), func(t *testing.T) {
-+			dir, err := ioutil.TempDir("", "test-new-bundle")
-+			if err != nil {
-+				t.Fatal("failed to create test directory", err)
-+			}
-+			defer os.RemoveAll(dir)
-+			work := filepath.Join(dir, "work")
-+			state := filepath.Join(dir, "state")
-+			id := fmt.Sprintf("new-bundle-%d", i)
-+			spec := oci.Spec{}
-+			if tc.userns {
-+				spec.Linux = &specs.Linux{
-+					GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}},
-+				}
-+			}
-+			specBytes, err := json.Marshal(&spec)
-+			if err != nil {
-+				t.Fatal("failed to marshal spec", err)
-+			}
-+
-+			b, err := newBundle(id, work, state, specBytes)
-+			if err != nil {
-+				t.Fatal("newBundle should succeed", err)
-+			}
-+			if b == nil {
-+				t.Fatal("bundle should not be nil")
-+			}
-+
-+			fi, err := os.Stat(b.path)
-+			if err != nil {
-+				t.Error("should be able to stat bundle path", err)
-+			}
-+			if tc.userns {
-+				if fi.Mode() != os.ModeDir|0710 {
-+					t.Error("bundle path should be a directory with perm 0710")
-+				}
-+			} else {
-+				if fi.Mode() != os.ModeDir|0700 {
-+					t.Error("bundle path should be a directory with perm 0700")
-+				}
-+			}
-+			stat, ok := fi.Sys().(*syscall.Stat_t)
-+			if !ok {
-+				t.Fatal("should assert to *syscall.Stat_t")
-+			}
-+			expectedGID := uint32(0)
-+			if tc.userns {
-+				expectedGID = usernsGID
-+			}
-+			if stat.Gid != expectedGID {
-+				t.Error("gid should match", expectedGID, stat.Gid)
-+			}
-+		})
-+	}
-+}
-+
-+func TestRemappedGID(t *testing.T) {
-+	tests := []struct {
-+		spec oci.Spec
-+		gid  uint32
-+	}{{
-+		// empty spec
-+		spec: oci.Spec{},
-+		gid:  0,
-+	}, {
-+		// empty Linux section
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{},
-+		},
-+		gid: 0,
-+	}, {
-+		// empty ID mappings
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: make([]specs.LinuxIDMapping, 0),
-+			},
-+		},
-+		gid: 0,
-+	}, {
-+		// valid ID mapping
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: []specs.LinuxIDMapping{{
-+					ContainerID: 0,
-+					HostID:      1000,
-+				}},
-+			},
-+		},
-+		gid: 1000,
-+	}, {
-+		// missing ID mapping
-+		spec: oci.Spec{
-+			Linux: &specs.Linux{
-+				GIDMappings: []specs.LinuxIDMapping{{
-+					ContainerID: 100,
-+					HostID:      1000,
-+				}},
-+			},
-+		},
-+		gid: 0,
-+	}}
-+
-+	for i, tc := range tests {
-+		t.Run(strconv.Itoa(i), func(t *testing.T) {
-+			s, err := json.Marshal(tc.spec)
-+			if err != nil {
-+				t.Fatal("failed to marshal spec", err)
-+			}
-+			gid, err := remappedGID(s)
-+			if err != nil {
-+				t.Error("should unmarshal successfully", err)
-+			}
-+			if gid != tc.gid {
-+				t.Error("expected GID to match", tc.gid, gid)
-+			}
-+		})
-+	}
-+}
diff -Nru containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch
--- containerd-1.4.5~ds1/debian/patches/0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch	1970-01-01 08:00:00.000000000 +0800
@@ -1,36 +0,0 @@
-From: Derek McGowan <derek@mcg.dev>
-Date: Wed, 15 Sep 2021 17:57:13 -0700
-Subject: btrfs: reduce permissions on plugin directories
-
-Disallow traversal into directories that may contain
-unpacked or mounted image filesystems.
-
-Signed-off-by: Derek McGowan <derek@mcg.dev>
-Signed-off-by: Samuel Karp <skarp@amazon.com>
-(cherry picked from commit 7c621e1fcc08bcf5a1a48b837342cc22eada1685)
----
- snapshots/btrfs/btrfs.go | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/snapshots/btrfs/btrfs.go b/snapshots/btrfs/btrfs.go
-index eef883b..778b783 100644
---- a/snapshots/btrfs/btrfs.go
-+++ b/snapshots/btrfs/btrfs.go
-@@ -63,11 +63,15 @@ type snapshotter struct {
- // root needs to be a mount point of btrfs.
- func NewSnapshotter(root string) (snapshots.Snapshotter, error) {
- 	// If directory does not exist, create it
--	if _, err := os.Stat(root); err != nil {
-+	if st, err := os.Stat(root); err != nil {
- 		if !os.IsNotExist(err) {
- 			return nil, err
- 		}
--		if err := os.Mkdir(root, 0755); err != nil {
-+		if err := os.Mkdir(root, 0700); err != nil {
-+			return nil, err
-+		}
-+	} else if st.Mode()&os.ModePerm != 0700 {
-+		if err := os.Chmod(root, 0700); err != nil {
- 			return nil, err
- 		}
- 	}
diff -Nru containerd-1.4.5~ds1/debian/patches/series containerd-1.4.12~ds1/debian/patches/series
--- containerd-1.4.5~ds1/debian/patches/series	2021-10-05 18:45:47.000000000 +0800
+++ containerd-1.4.12~ds1/debian/patches/series	2021-11-23 18:42:16.000000000 +0800
@@ -5,7 +5,4 @@
 0005-backport-github.com-containerd-containerd-remotes.patch
 0006-backport-apparmor-handle-signal-mediation.patch
 0007-backport-runtime-ignore-file-already-closed-error.patch
-0008-CVE-2021-32760.patch
-0009-CVE-2021-41103/0009-v2-runtime-reduce-permissions-for-bundle-dir.patch
-0009-CVE-2021-41103/0010-v1-runtime-reduce-permissions-for-bundle-dir.patch
-0009-CVE-2021-41103/0011-btrfs-reduce-permissions-on-plugin-directories.patch
+0008-Add-RPi1-RPi0-workaround.patch
diff -Nru containerd-1.4.5~ds1/.github/workflows/ci.yml containerd-1.4.12~ds1/.github/workflows/ci.yml
--- containerd-1.4.5~ds1/.github/workflows/ci.yml	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.github/workflows/ci.yml	2021-11-18 03:52:12.000000000 +0800
@@ -26,7 +26,7 @@
       - name: Install Go
         uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -47,6 +47,8 @@
         working-directory: src/github.com/containerd/containerd
 
       - name: Make check
+        env:
+          GO111MODULE: off
         shell: bash
         run: make check
         working-directory: src/github.com/containerd/containerd
@@ -80,7 +82,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -126,7 +128,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -143,6 +145,8 @@
         run: GO111MODULE=on go get github.com/cpuguy83/go-md2man/v2@v2.0.0
 
       - name: Make
+        env:
+          GO111MODULE: off
         run: make man
         working-directory: src/github.com/containerd/containerd
 
@@ -162,7 +166,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -176,6 +180,8 @@
           path: src/github.com/containerd/containerd
 
       - name: Make
+        env:
+          GO111MODULE: off
         run: |
           make build
           make binaries
@@ -193,7 +199,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -217,6 +223,8 @@
           cd src/github.com/containerd/containerd
           script/setup/install-dev-tools
       - name: Binaries
+        env:
+          GO111MODULE: off
         shell: bash
         run: |
           set -o xtrace
@@ -234,11 +242,14 @@
         shell: bash
         env:
           CGO_ENABLED: 1
+          GO111MODULE: off
         run: |
           cd src/github.com/containerd/containerd
           mingw32-make.exe test root-test
 
       - name: Integration 1
+        env:
+          GO111MODULE: off
         shell: bash
         run: |
           cd src/github.com/containerd/containerd
@@ -246,6 +257,8 @@
           mingw32-make.exe integration
       # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/175
       - name: Integration 2
+        env:
+          GO111MODULE: off
         shell: bash
         run: |
           cd src/github.com/containerd/containerd
@@ -272,7 +285,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -315,6 +328,7 @@
       - name: Install containerd
         env:
           CGO_ENABLED: 1
+          GO111MODULE: off
         run: |
           make binaries
           sudo -E PATH=$PATH make install
@@ -324,6 +338,7 @@
         env:
           GOPROXY: direct
           SKIPTESTS: github.com/containerd/containerd/snapshots/devmapper
+          GO111MODULE: off
         run: |
           make test
           sudo -E PATH=$PATH make root-test
@@ -334,6 +349,7 @@
           GOPROXY: direct
           TEST_RUNTIME: ${{ matrix.runtime }}
           RUNC_FLAVOR: ${{ matrix.runc }}
+          GO111MODULE: off
         run: |
           sudo -E PATH=$PATH make integration EXTRA_TESTFLAGS=-no-criu TESTFLAGS_RACE=-race
         working-directory: src/github.com/containerd/containerd
@@ -344,6 +360,7 @@
           GOPROXY: direct
           TEST_RUNTIME: ${{ matrix.runtime }}
           RUNC_FLAVOR: ${{ matrix.runc }}
+          GO111MODULE: off
         run: |
           sudo -E PATH=$PATH TESTFLAGS_PARALLEL=1 make integration EXTRA_TESTFLAGS=-no-criu
         working-directory: src/github.com/containerd/containerd
diff -Nru containerd-1.4.5~ds1/.github/workflows/nightly.yml containerd-1.4.12~ds1/.github/workflows/nightly.yml
--- containerd-1.4.5~ds1/.github/workflows/nightly.yml	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.github/workflows/nightly.yml	2021-11-18 03:52:12.000000000 +0800
@@ -14,7 +14,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Checkout
         uses: actions/checkout@v1
@@ -63,6 +63,7 @@
           GOPATH: ${{ runner.workspace }}
           GOOS: linux
           GOARCH: amd64
+          GO111MODULE: off
         run: |
           make binaries
           mv bin bin_amd64
@@ -74,6 +75,7 @@
           GOARCH: arm64
           CC: aarch64-linux-gnu-gcc
           CGO_ENABLED: 1
+          GO111MODULE: off
         run: |
           make binaries
           mv bin bin_arm64
@@ -85,6 +87,7 @@
           GOARCH: s390x
           CGO_ENABLED: 1
           CC: s390x-linux-gnu-gcc
+          GO111MODULE: off
         run: |
           make binaries
           mv bin bin_s390x
@@ -96,6 +99,7 @@
           GOARCH: ppc64le
           CGO_ENABLED: 1
           CC: powerpc64le-linux-gnu-gcc
+          GO111MODULE: off
         run: |
           make binaries
           mv bin bin_ppc64le
@@ -134,7 +138,7 @@
     steps:
       - uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Checkout
         uses: actions/checkout@v1
@@ -155,6 +159,7 @@
           GOPATH: ${{ runner.workspace }}
           GOOS: windows
           GOARCH: amd64
+          GO111MODULE: off
         run: |
           make binaries
 
diff -Nru containerd-1.4.5~ds1/.github/workflows/release.yml containerd-1.4.12~ds1/.github/workflows/release.yml
--- containerd-1.4.5~ds1/.github/workflows/release.yml	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.github/workflows/release.yml	2021-11-18 03:52:12.000000000 +0800
@@ -62,7 +62,7 @@
       - name: Install Go
         uses: actions/setup-go@v2
         with:
-          go-version: '1.15.11'
+          go-version: '1.16.10'
 
       - name: Set env
         shell: bash
@@ -103,6 +103,8 @@
           path: src/github.com/Microsoft/hcsshim
 
       - name: Make
+        env:
+          GO111MODULE: off
         shell: bash
         run: |
           make build
diff -Nru containerd-1.4.5~ds1/images/image.go containerd-1.4.12~ds1/images/image.go
--- containerd-1.4.5~ds1/images/image.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/images/image.go	2021-11-18 03:52:12.000000000 +0800
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"sort"
 	"time"
 
@@ -154,6 +155,10 @@
 				return nil, err
 			}
 
+			if err := validateMediaType(p, desc.MediaType); err != nil {
+				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
+			}
+
 			var manifest ocispec.Manifest
 			if err := json.Unmarshal(p, &manifest); err != nil {
 				return nil, err
@@ -194,6 +199,10 @@
 				return nil, err
 			}
 
+			if err := validateMediaType(p, desc.MediaType); err != nil {
+				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
+			}
+
 			var idx ocispec.Index
 			if err := json.Unmarshal(p, &idx); err != nil {
 				return nil, err
@@ -336,6 +345,10 @@
 			return nil, err
 		}
 
+		if err := validateMediaType(p, desc.MediaType); err != nil {
+			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
+		}
+
 		// TODO(stevvooe): We just assume oci manifest, for now. There may be
 		// subtle differences from the docker version.
 		var manifest ocispec.Manifest
@@ -351,6 +364,10 @@
 			return nil, err
 		}
 
+		if err := validateMediaType(p, desc.MediaType); err != nil {
+			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
+		}
+
 		var index ocispec.Index
 		if err := json.Unmarshal(p, &index); err != nil {
 			return nil, err
@@ -368,6 +385,44 @@
 	return descs, nil
 }
 
+// unknownDocument represents a manifest, manifest list, or index that has not
+// yet been validated.
+type unknownDocument struct {
+	MediaType string          `json:"mediaType,omitempty"`
+	Config    json.RawMessage `json:"config,omitempty"`
+	Layers    json.RawMessage `json:"layers,omitempty"`
+	Manifests json.RawMessage `json:"manifests,omitempty"`
+	FSLayers  json.RawMessage `json:"fsLayers,omitempty"` // schema 1
+}
+
+// validateMediaType returns an error if the byte slice is invalid JSON or if
+// the media type identifies the blob as one format but it contains elements of
+// another format.
+func validateMediaType(b []byte, mt string) error {
+	var doc unknownDocument
+	if err := json.Unmarshal(b, &doc); err != nil {
+		return err
+	}
+	if len(doc.FSLayers) != 0 {
+		return fmt.Errorf("media-type: schema 1 not supported")
+	}
+	switch mt {
+	case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+		if len(doc.Manifests) != 0 ||
+			doc.MediaType == MediaTypeDockerSchema2ManifestList ||
+			doc.MediaType == ocispec.MediaTypeImageIndex {
+			return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
+		}
+	case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+		if len(doc.Config) != 0 || len(doc.Layers) != 0 ||
+			doc.MediaType == MediaTypeDockerSchema2Manifest ||
+			doc.MediaType == ocispec.MediaTypeImageManifest {
+			return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
+		}
+	}
+	return nil
+}
+
 // RootFS returns the unpacked diffids that make up and images rootfs.
 //
 // These are used to verify that a set of layers unpacked to the expected
diff -Nru containerd-1.4.5~ds1/images/image_test.go containerd-1.4.12~ds1/images/image_test.go
--- containerd-1.4.5~ds1/images/image_test.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/images/image_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,150 @@
+/*
+   Copyright The containerd 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 images
+
+import (
+	"encoding/json"
+	"testing"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+func TestValidateMediaType(t *testing.T) {
+	docTests := []struct {
+		mt    string
+		index bool
+	}{
+		{MediaTypeDockerSchema2Manifest, false},
+		{ocispec.MediaTypeImageManifest, false},
+		{MediaTypeDockerSchema2ManifestList, true},
+		{ocispec.MediaTypeImageIndex, true},
+	}
+	for _, tc := range docTests {
+		t.Run("manifest-"+tc.mt, func(t *testing.T) {
+			manifest := ocispec.Manifest{
+				Config: ocispec.Descriptor{Size: 1},
+				Layers: []ocispec.Descriptor{{Size: 2}},
+			}
+			b, err := json.Marshal(manifest)
+			if err != nil {
+				t.Fatal("failed to marshal manifest", err)
+			}
+
+			err = validateMediaType(b, tc.mt)
+			if tc.index {
+				if err == nil {
+					t.Error("manifest should not be a valid index")
+				}
+			} else {
+				if err != nil {
+					t.Error("manifest should be valid")
+				}
+			}
+		})
+		t.Run("index-"+tc.mt, func(t *testing.T) {
+			index := ocispec.Index{
+				Manifests: []ocispec.Descriptor{{Size: 1}},
+			}
+			b, err := json.Marshal(index)
+			if err != nil {
+				t.Fatal("failed to marshal index", err)
+			}
+
+			err = validateMediaType(b, tc.mt)
+			if tc.index {
+				if err != nil {
+					t.Error("index should be valid")
+				}
+			} else {
+				if err == nil {
+					t.Error("index should not be a valid manifest")
+				}
+			}
+		})
+	}
+
+	mtTests := []struct {
+		mt      string
+		valid   []string
+		invalid []string
+	}{{
+		MediaTypeDockerSchema2Manifest,
+		[]string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest},
+		[]string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex},
+	}, {
+		ocispec.MediaTypeImageManifest,
+		[]string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest},
+		[]string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex},
+	}, {
+		MediaTypeDockerSchema2ManifestList,
+		[]string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex},
+		[]string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest},
+	}, {
+		ocispec.MediaTypeImageIndex,
+		[]string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex},
+		[]string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest},
+	}}
+	for _, tc := range mtTests {
+		for _, v := range tc.valid {
+			t.Run("valid-"+tc.mt+"-"+v, func(t *testing.T) {
+				doc := struct {
+					MediaType string `json:"mediaType"`
+				}{MediaType: v}
+				b, err := json.Marshal(doc)
+				if err != nil {
+					t.Fatal("failed to marshal document", err)
+				}
+
+				err = validateMediaType(b, tc.mt)
+				if err != nil {
+					t.Error("document should be valid", err)
+				}
+			})
+		}
+		for _, iv := range tc.invalid {
+			t.Run("invalid-"+tc.mt+"-"+iv, func(t *testing.T) {
+				doc := struct {
+					MediaType string `json:"mediaType"`
+				}{MediaType: iv}
+				b, err := json.Marshal(doc)
+				if err != nil {
+					t.Fatal("failed to marshal document", err)
+				}
+
+				err = validateMediaType(b, tc.mt)
+				if err == nil {
+					t.Error("document should not be valid")
+				}
+			})
+		}
+	}
+	t.Run("schema1", func(t *testing.T) {
+		doc := struct {
+			FSLayers []string `json:"fsLayers"`
+		}{FSLayers: []string{"1"}}
+		b, err := json.Marshal(doc)
+		if err != nil {
+			t.Fatal("failed to marshal document", err)
+		}
+
+		err = validateMediaType(b, "")
+		if err == nil {
+			t.Error("document should not be valid")
+		}
+
+	})
+}
diff -Nru containerd-1.4.5~ds1/image_test.go containerd-1.4.12~ds1/image_test.go
--- containerd-1.4.5~ds1/image_test.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/image_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -34,7 +34,7 @@
 		t.Skip()
 	}
 
-	const imageName = "docker.io/library/busybox:latest"
+	const imageName = "ghcr.io/containerd/busybox:latest"
 	ctx, cancel := testContext(t)
 	defer cancel()
 
@@ -140,7 +140,7 @@
 		t.Skip()
 	}
 
-	imageName := "docker.io/library/busybox:latest"
+	imageName := "ghcr.io/containerd/busybox:latest"
 	ctx, cancel := testContext(t)
 	defer cancel()
 
diff -Nru containerd-1.4.5~ds1/lease_test.go containerd-1.4.12~ds1/lease_test.go
--- containerd-1.4.5~ds1/lease_test.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/lease_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -54,7 +54,7 @@
 	defer ls.Delete(ctx, l, leases.SynchronousDelete)
 
 	// step 1: download image
-	imageName := "docker.io/library/busybox:1.25"
+	imageName := "ghcr.io/containerd/busybox:1.28"
 
 	image, err := client.Pull(ctx, imageName, WithPullUnpack, WithPullSnapshotter("native"))
 	if err != nil {
diff -Nru containerd-1.4.5~ds1/.mailmap containerd-1.4.12~ds1/.mailmap
--- containerd-1.4.5~ds1/.mailmap	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.mailmap	2021-11-18 03:52:12.000000000 +0800
@@ -17,6 +17,7 @@
 Cao Zhihao <caozhihao@163.com>
 Cao Zhihao <caozhihao@163.com> <caozhihao.xd@bytedance.com>
 Carlos Eduardo <me@carlosedp.com> <me@carlosedp.com>
+Cory Bennett <cbennett@netflix.com>
 Cristian Staretu <cristian.staretu@gmail.com>
 Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
 Daniel Dao <dqminh89@gmail.com>
@@ -73,6 +74,7 @@
 Nishchay Kumar <mrawesomenix@gmail.com>
 Oliver Stenbom <oliver@stenbom.eu> <ostenbom@pivotal.io>
 Phil Estes <estesp@gmail.com> <estesp@linux.vnet.ibm.com>
+Phil Estes <estesp@gmail.com> <estesp@amazon.com>
 Reid Li <reid.li@utexas.edu>
 Ross Boucher <rboucher@gmail.com>
 Ruediger Maass <ruediger.maass@de.ibm.com>
@@ -90,6 +92,7 @@
 Su Fei  <fesu@ebay.com> <fesu@ebay.com>
 Ted Yu <yuzhihong@gmail.com>
 Tõnis Tiigi <tonistiigi@gmail.com>
+Wei Fu <fuweid89@gmail.com>
 Wei Fu <fuweid89@gmail.com> <fhfuwei@163.com>
 Xiaodong Zhang <a4012017@sina.com>
 Xuean Yan <yan.xuean@zte.com.cn>
diff -Nru containerd-1.4.5~ds1/metadata/containers.go containerd-1.4.12~ds1/metadata/containers.go
--- containerd-1.4.5~ds1/metadata/containers.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/metadata/containers.go	2021-11-18 03:52:12.000000000 +0800
@@ -290,7 +290,7 @@
 
 	// image has no validation
 	for k, v := range container.Labels {
-		if err := labels.Validate(k, v); err == nil {
+		if err := labels.Validate(k, v); err != nil {
 			return errors.Wrapf(err, "containers.Labels")
 		}
 	}
diff -Nru containerd-1.4.5~ds1/metadata/content.go containerd-1.4.12~ds1/metadata/content.go
--- containerd-1.4.5~ds1/metadata/content.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/metadata/content.go	2021-11-18 03:52:12.000000000 +0800
@@ -551,13 +551,13 @@
 	if desc.Size > 0 {
 		ra, err := nw.provider.ReaderAt(ctx, nw.desc)
 		if err != nil {
+			w.Close()
 			return err
 		}
 		defer ra.Close()
 
 		if err := content.CopyReaderAt(w, ra, desc.Size); err != nil {
-			nw.w.Close()
-			nw.w = nil
+			w.Close()
 			return err
 		}
 	}
@@ -708,7 +708,7 @@
 
 func validateInfo(info *content.Info) error {
 	for k, v := range info.Labels {
-		if err := labels.Validate(k, v); err == nil {
+		if err := labels.Validate(k, v); err != nil {
 			return errors.Wrapf(err, "info.Labels")
 		}
 	}
diff -Nru containerd-1.4.5~ds1/releases/v1.4.10.toml containerd-1.4.12~ds1/releases/v1.4.10.toml
--- containerd-1.4.5~ds1/releases/v1.4.10.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.10.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,24 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.9"
+
+pre_release = false
+
+preface = """\
+The tenth patch release for containerd 1.4 contains minor fixes and updates
+including an updated runc and hcsshim.
+
+### Notable Updates
+
+* **Update runc to v1.0.2** [#5899](https://github.com/containerd/containerd/pull/5899)
+* **Update hcsshim to v0.8.21** [#5957](https://github.com/containerd/containerd/pull/5957)
+* **Support "clone3" in default seccomp profile** [#5982](https://github.com/containerd/containerd/pull/5982)
+* **Fix panic in metadata content writer on copy error** [#6043](https://github.com/containerd/containerd/pull/6043)
+
+See the changelog for complete list of changes"""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.11.toml containerd-1.4.12~ds1/releases/v1.4.11.toml
--- containerd-1.4.5~ds1/releases/v1.4.11.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.11.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,20 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.10"
+
+pre_release = false
+
+preface = """\
+The eleventh patch release for containerd 1.4 is a security release to fix CVE-2021-41103.
+
+### Notable Updates
+
+* **Fix insufficiently restricted permissions on container root and plugin directories** [GHSA-c2h3-6mxw-7mvq](https://github.com/containerd/containerd/security/advisories/GHSA-c2h3-6mxw-7mvq)
+
+See the changelog for complete list of changes"""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.12.toml containerd-1.4.12~ds1/releases/v1.4.12.toml
--- containerd-1.4.5~ds1/releases/v1.4.12.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.12.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,23 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.11"
+
+pre_release = false
+
+preface = """\
+The twelfth patch release for containerd 1.4 contains a few minor bug fixes
+and an update to mitigate [CVE-2021-41190](https://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m).
+
+### Notable Updates
+
+* **Handle ambiguous OCI manifest parsing** ([GHSA-5j5w-g665-5m35](https://github.com/containerd/containerd/security/advisories/GHSA-5j5w-g665-5m35))
+* **Update pull to try next mirror for non-404 errors** ([#5275](https://github.com/containerd/containerd/pull/5275))
+* **Update pull to handle of non-https urls in descriptors** ([#6221](https://github.com/containerd/containerd/pull/6221))
+
+See the changelog for complete list of changes"""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.6.toml containerd-1.4.12~ds1/releases/v1.4.6.toml
--- containerd-1.4.5~ds1/releases/v1.4.6.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.6.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,15 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.5"
+
+pre_release = false
+
+preface = """\
+The sixth patch release for containerd 1.4 is a security release to update
+runc for [CVE-2021-30465](https://github.com/opencontainers/runc/security/advisories/GHSA-c3xm-pvg7-gh7r)"""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.7.toml containerd-1.4.12~ds1/releases/v1.4.7.toml
--- containerd-1.4.5~ds1/releases/v1.4.7.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.7.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,23 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.6"
+
+pre_release = false
+
+preface = """\
+The seventh patch release for containerd 1.4 updates runc to 1.0.0 and contains
+various other fixes.
+
+### Notable Updates
+* **Update runc binary to 1.0.0** [5552](https://github.com/containerd/containerd/pull/5552)
+* **Fix invalid validation error checking** [#5565](https://github.com/containerd/containerd/pull/5565)
+* **Fix error on image pull resume** [#5560](https://github.com/containerd/containerd/pull/5560)
+* **Fix symlink resolution for disk mounts on Windows** [#5411](https://github.com/containerd/containerd/pull/5411)
+
+See the changelog for complete list of changes"""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.8.toml containerd-1.4.12~ds1/releases/v1.4.8.toml
--- containerd-1.4.5~ds1/releases/v1.4.8.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.8.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,14 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.7"
+
+pre_release = false
+
+preface = """\
+The eighth patch release for containerd 1.4 is a security release to address [CVE-2021-32760](https://github.com/containerd/containerd/security/advisories/GHSA-c72p-9xmj-rx3w)."""
diff -Nru containerd-1.4.5~ds1/releases/v1.4.9.toml containerd-1.4.12~ds1/releases/v1.4.9.toml
--- containerd-1.4.5~ds1/releases/v1.4.9.toml	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/releases/v1.4.9.toml	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,23 @@
+# commit to be tagged for new release
+commit = "HEAD"
+
+project_name = "containerd"
+github_repo = "containerd/containerd"
+match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$"
+
+# previous release
+previous = "v1.4.8"
+
+pre_release = false
+
+preface = """\
+The ninth patch release for containerd 1.4 updates runc to 1.0.1 and contains
+other minor updates.
+
+### Notable Updates
+
+* **Update runc binary to 1.0.1** [#5751](https://github.com/containerd/containerd/pull/5751)
+* **Update pull authorization logic on redirect** [#5504](https://github.com/containerd/containerd/pull/5504)
+* **Fix user agent used for fetching registry authentication tokens** [#5761](https://github.com/containerd/containerd/pull/5761)
+
+See the changelog for complete list of changes"""
diff -Nru containerd-1.4.5~ds1/remotes/docker/authorizer.go containerd-1.4.12~ds1/remotes/docker/authorizer.go
--- containerd-1.4.5~ds1/remotes/docker/authorizer.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/authorizer.go	2021-11-18 03:52:12.000000000 +0800
@@ -31,6 +31,7 @@
 
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/log"
+	"github.com/containerd/containerd/version"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context/ctxhttp"
@@ -356,6 +357,9 @@
 			req.Header[k] = append(req.Header[k], v...)
 		}
 	}
+	if len(req.Header.Get("User-Agent")) == 0 {
+		req.Header.Set("User-Agent", "containerd/"+version.Version)
+	}
 
 	resp, err := ctxhttp.Do(ctx, ah.client, req)
 	if err != nil {
@@ -408,6 +412,9 @@
 			req.Header[k] = append(req.Header[k], v...)
 		}
 	}
+	if len(req.Header.Get("User-Agent")) == 0 {
+		req.Header.Set("User-Agent", "containerd/"+version.Version)
+	}
 
 	reqParams := req.URL.Query()
 
diff -Nru containerd-1.4.5~ds1/remotes/docker/fetcher.go containerd-1.4.12~ds1/remotes/docker/fetcher.go
--- containerd-1.4.5~ds1/remotes/docker/fetcher.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/fetcher.go	2021-11-18 03:52:12.000000000 +0800
@@ -60,6 +60,10 @@
 				log.G(ctx).WithError(err).Debug("failed to parse")
 				continue
 			}
+			if u.Scheme != "http" && u.Scheme != "https" {
+				log.G(ctx).Debug("non-http(s) alternative url is unsupported")
+				continue
+			}
 			log.G(ctx).Debug("trying alternative url")
 
 			// Try this first, parse it
@@ -148,7 +152,7 @@
 	})
 }
 
-func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (io.ReadCloser, error) {
+func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) {
 	req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
 
 	if offset > 0 {
@@ -162,13 +166,17 @@
 	if err != nil {
 		return nil, err
 	}
+	defer func() {
+		if retErr != nil {
+			resp.Body.Close()
+		}
+	}()
 
 	if resp.StatusCode > 299 {
 		// TODO(stevvooe): When doing a offset specific request, we should
 		// really distinguish between a 206 and a 200. In the case of 200, we
 		// can discard the bytes, hiding the seek behavior from the
 		// implementation.
-		defer resp.Body.Close()
 
 		if resp.StatusCode == http.StatusNotFound {
 			return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String())
diff -Nru containerd-1.4.5~ds1/remotes/docker/pusher.go containerd-1.4.12~ds1/remotes/docker/pusher.go
--- containerd-1.4.5~ds1/remotes/docker/pusher.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/pusher.go	2021-11-18 03:52:12.000000000 +0800
@@ -109,12 +109,15 @@
 						// TODO: Set updated time?
 					},
 				})
+				resp.Body.Close()
 				return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
 			}
 		} else if resp.StatusCode != http.StatusNotFound {
+			resp.Body.Close()
 			// TODO: log error
 			return nil, errors.Errorf("unexpected response: %s", resp.Status)
 		}
+		resp.Body.Close()
 	}
 
 	if isManifest {
@@ -155,6 +158,7 @@
 				return nil, err
 			}
 		}
+		defer resp.Body.Close()
 
 		switch resp.StatusCode {
 		case http.StatusOK, http.StatusAccepted, http.StatusNoContent:
@@ -338,6 +342,7 @@
 	if resp == nil {
 		return errors.New("no response")
 	}
+	defer resp.Body.Close()
 
 	// 201 is specified return status, some registries return
 	// 200, 202 or 204.
diff -Nru containerd-1.4.5~ds1/remotes/docker/resolver.go containerd-1.4.12~ds1/remotes/docker/resolver.go
--- containerd-1.4.5~ds1/remotes/docker/resolver.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/resolver.go	2021-11-18 03:52:12.000000000 +0800
@@ -238,10 +238,10 @@
 	}
 
 	var (
-		lastErr error
-		paths   [][]string
-		dgst    = refspec.Digest()
-		caps    = HostCapabilityPull
+		firstErr error
+		paths    [][]string
+		dgst     = refspec.Digest()
+		caps     = HostCapabilityPull
 	)
 
 	if dgst != "" {
@@ -292,8 +292,8 @@
 					err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization")
 				}
 				// Store the error for referencing later
-				if lastErr == nil {
-					lastErr = err
+				if firstErr == nil {
+					firstErr = err
 				}
 				log.G(ctx).WithError(err).Info("trying next host")
 				continue // try another host
@@ -305,7 +305,14 @@
 					log.G(ctx).Info("trying next host - response was http.StatusNotFound")
 					continue
 				}
-				return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status)
+				if resp.StatusCode > 399 {
+					// Set firstErr when encountering the first non-404 status code.
+					if firstErr == nil {
+						firstErr = errors.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status)
+					}
+					continue // try another host
+				}
+				return "", ocispec.Descriptor{}, errors.Errorf("pulling from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status)
 			}
 			size := resp.ContentLength
 			contentType := getManifestMediaType(resp)
@@ -368,8 +375,8 @@
 			}
 			// Prevent resolving to excessively large manifests
 			if size > MaxManifestSize {
-				if lastErr == nil {
-					lastErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref)
+				if firstErr == nil {
+					firstErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref)
 				}
 				continue
 			}
@@ -385,11 +392,15 @@
 		}
 	}
 
-	if lastErr == nil {
-		lastErr = errors.Wrap(errdefs.ErrNotFound, ref)
+	// If above loop terminates without return, then there was an error.
+	// "firstErr" contains the first non-404 error. That is, "firstErr == nil"
+	// means that either no registries were given or each registry returned 404.
+
+	if firstErr == nil {
+		firstErr = errors.Wrap(errdefs.ErrNotFound, ref)
 	}
 
-	return "", ocispec.Descriptor{}, lastErr
+	return "", ocispec.Descriptor{}, firstErr
 }
 
 func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
@@ -548,7 +559,21 @@
 	if err := r.authorize(ctx, req); err != nil {
 		return nil, errors.Wrap(err, "failed to authorize")
 	}
-	resp, err := ctxhttp.Do(ctx, r.host.Client, req)
+
+	var client = &http.Client{}
+	if r.host.Client != nil {
+		*client = *r.host.Client
+	}
+	if client.CheckRedirect == nil {
+		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+			if len(via) >= 10 {
+				return errors.New("stopped after 10 redirects")
+			}
+			return errors.Wrap(r.authorize(ctx, req), "failed to authorize redirect")
+		}
+	}
+
+	resp, err := ctxhttp.Do(ctx, client, req)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to do request")
 	}
diff -Nru containerd-1.4.5~ds1/remotes/docker/schema1/converter.go containerd-1.4.12~ds1/remotes/docker/schema1/converter.go
--- containerd-1.4.5~ds1/remotes/docker/schema1/converter.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/remotes/docker/schema1/converter.go	2021-11-18 03:52:12.000000000 +0800
@@ -256,6 +256,9 @@
 	if err := json.Unmarshal(b, &m); err != nil {
 		return err
 	}
+	if len(m.Manifests) != 0 || len(m.Layers) != 0 {
+		return errors.New("converter: expected schema1 document but found extra keys")
+	}
 	c.pulledManifest = &m
 
 	return nil
@@ -472,8 +475,10 @@
 }
 
 type manifest struct {
-	FSLayers []fsLayer `json:"fsLayers"`
-	History  []history `json:"history"`
+	FSLayers  []fsLayer       `json:"fsLayers"`
+	History   []history       `json:"history"`
+	Layers    json.RawMessage `json:"layers,omitempty"`    // OCI manifest
+	Manifests json.RawMessage `json:"manifests,omitempty"` // OCI index
 }
 
 type v1History struct {
diff -Nru containerd-1.4.5~ds1/runtime/v1/linux/bundle.go containerd-1.4.12~ds1/runtime/v1/linux/bundle.go
--- containerd-1.4.5~ds1/runtime/v1/linux/bundle.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v1/linux/bundle.go	2021-11-18 03:52:12.000000000 +0800
@@ -21,6 +21,7 @@
 import (
 	"context"
 	"crypto/sha256"
+	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -30,6 +31,7 @@
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	"github.com/containerd/containerd/runtime/v1/shim"
 	"github.com/containerd/containerd/runtime/v1/shim/client"
+	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
 
@@ -48,7 +50,7 @@
 		return nil, err
 	}
 	path = filepath.Join(path, id)
-	if err := os.Mkdir(path, 0711); err != nil {
+	if err := os.Mkdir(path, 0700); err != nil {
 		return nil, err
 	}
 	defer func() {
@@ -56,6 +58,9 @@
 			os.RemoveAll(path)
 		}
 	}()
+	if err := prepareBundleDirectoryPermissions(path, spec); err != nil {
+		return nil, err
+	}
 	workDir = filepath.Join(workDir, id)
 	if err := os.MkdirAll(workDir, 0711); err != nil {
 		return nil, err
@@ -77,6 +82,55 @@
 	}, err
 }
 
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory. When user namespaces are enabled, the permissions are modified
+// to allow the remapped root GID to access the bundle.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
+	gid, err := remappedGID(spec)
+	if err != nil {
+		return err
+	}
+	if gid == 0 {
+		return nil
+	}
+	if err := os.Chown(path, -1, int(gid)); err != nil {
+		return err
+	}
+	return os.Chmod(path, 0710)
+}
+
+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
+// unmarshal.
+type ociSpecUserNS struct {
+	Linux *linuxSpecUserNS
+}
+
+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
+// unmarshal.
+type linuxSpecUserNS struct {
+	GIDMappings []specs.LinuxIDMapping
+}
+
+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
+// remappedGID returns an error.
+func remappedGID(spec []byte) (uint32, error) {
+	var ociSpec ociSpecUserNS
+	err := json.Unmarshal(spec, &ociSpec)
+	if err != nil {
+		return 0, err
+	}
+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
+		return 0, nil
+	}
+	for _, mapping := range ociSpec.Linux.GIDMappings {
+		if mapping.ContainerID == 0 {
+			return mapping.HostID, nil
+		}
+	}
+	return 0, nil
+}
+
 type bundle struct {
 	id      string
 	path    string
diff -Nru containerd-1.4.5~ds1/runtime/v1/linux/bundle_test.go containerd-1.4.12~ds1/runtime/v1/linux/bundle_test.go
--- containerd-1.4.5~ds1/runtime/v1/linux/bundle_test.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v1/linux/bundle_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,166 @@
+//go:build linux
+// +build linux
+
+/*
+   Copyright The containerd 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 linux
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"syscall"
+	"testing"
+
+	"github.com/containerd/containerd/oci"
+	"github.com/containerd/continuity/testutil"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func TestNewBundle(t *testing.T) {
+	testutil.RequiresRoot(t)
+	tests := []struct {
+		userns bool
+	}{{
+		userns: false,
+	}, {
+		userns: true,
+	}}
+	const usernsGID = 4200
+
+	for i, tc := range tests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			dir, err := ioutil.TempDir("", "test-new-bundle")
+			if err != nil {
+				t.Fatal("failed to create test directory", err)
+			}
+			defer os.RemoveAll(dir)
+			work := filepath.Join(dir, "work")
+			state := filepath.Join(dir, "state")
+			id := fmt.Sprintf("new-bundle-%d", i)
+			spec := oci.Spec{}
+			if tc.userns {
+				spec.Linux = &specs.Linux{
+					GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}},
+				}
+			}
+			specBytes, err := json.Marshal(&spec)
+			if err != nil {
+				t.Fatal("failed to marshal spec", err)
+			}
+
+			b, err := newBundle(id, work, state, specBytes)
+			if err != nil {
+				t.Fatal("newBundle should succeed", err)
+			}
+			if b == nil {
+				t.Fatal("bundle should not be nil")
+			}
+
+			fi, err := os.Stat(b.path)
+			if err != nil {
+				t.Error("should be able to stat bundle path", err)
+			}
+			if tc.userns {
+				if fi.Mode() != os.ModeDir|0710 {
+					t.Error("bundle path should be a directory with perm 0710")
+				}
+			} else {
+				if fi.Mode() != os.ModeDir|0700 {
+					t.Error("bundle path should be a directory with perm 0700")
+				}
+			}
+			stat, ok := fi.Sys().(*syscall.Stat_t)
+			if !ok {
+				t.Fatal("should assert to *syscall.Stat_t")
+			}
+			expectedGID := uint32(0)
+			if tc.userns {
+				expectedGID = usernsGID
+			}
+			if stat.Gid != expectedGID {
+				t.Error("gid should match", expectedGID, stat.Gid)
+			}
+		})
+	}
+}
+
+func TestRemappedGID(t *testing.T) {
+	tests := []struct {
+		spec oci.Spec
+		gid  uint32
+	}{{
+		// empty spec
+		spec: oci.Spec{},
+		gid:  0,
+	}, {
+		// empty Linux section
+		spec: oci.Spec{
+			Linux: &specs.Linux{},
+		},
+		gid: 0,
+	}, {
+		// empty ID mappings
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: make([]specs.LinuxIDMapping, 0),
+			},
+		},
+		gid: 0,
+	}, {
+		// valid ID mapping
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: []specs.LinuxIDMapping{{
+					ContainerID: 0,
+					HostID:      1000,
+				}},
+			},
+		},
+		gid: 1000,
+	}, {
+		// missing ID mapping
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: []specs.LinuxIDMapping{{
+					ContainerID: 100,
+					HostID:      1000,
+				}},
+			},
+		},
+		gid: 0,
+	}}
+
+	for i, tc := range tests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			s, err := json.Marshal(tc.spec)
+			if err != nil {
+				t.Fatal("failed to marshal spec", err)
+			}
+			gid, err := remappedGID(s)
+			if err != nil {
+				t.Error("should unmarshal successfully", err)
+			}
+			if gid != tc.gid {
+				t.Error("expected GID to match", tc.gid, gid)
+			}
+		})
+	}
+}
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_default.go containerd-1.4.12~ds1/runtime/v2/bundle_default.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_default.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_default.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,24 @@
+//go:build !linux
+// +build !linux
+
+/*
+   Copyright The containerd 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 v2
+
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory according to the needs of the current platform.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error { return nil }
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle.go containerd-1.4.12~ds1/runtime/v2/bundle.go
--- containerd-1.4.5~ds1/runtime/v2/bundle.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle.go	2021-11-18 03:52:12.000000000 +0800
@@ -72,7 +72,10 @@
 	if err := os.MkdirAll(filepath.Dir(b.Path), 0711); err != nil {
 		return nil, err
 	}
-	if err := os.Mkdir(b.Path, 0711); err != nil {
+	if err := os.Mkdir(b.Path, 0700); err != nil {
+		return nil, err
+	}
+	if err := prepareBundleDirectoryPermissions(b.Path, spec); err != nil {
 		return nil, err
 	}
 	paths = append(paths, b.Path)
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_linux.go containerd-1.4.12~ds1/runtime/v2/bundle_linux.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_linux.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_linux.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,74 @@
+/*
+   Copyright The containerd 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 v2
+
+import (
+	"encoding/json"
+	"os"
+
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// prepareBundleDirectoryPermissions prepares the permissions of the bundle
+// directory according to the needs of the current platform.
+// On Linux when user namespaces are enabled, the permissions are modified to
+// allow the remapped root GID to access the bundle.
+func prepareBundleDirectoryPermissions(path string, spec []byte) error {
+	gid, err := remappedGID(spec)
+	if err != nil {
+		return err
+	}
+	if gid == 0 {
+		return nil
+	}
+	if err := os.Chown(path, -1, int(gid)); err != nil {
+		return err
+	}
+	return os.Chmod(path, 0710)
+}
+
+// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during
+// unmarshal.
+type ociSpecUserNS struct {
+	Linux *linuxSpecUserNS
+}
+
+// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during
+// unmarshal.
+type linuxSpecUserNS struct {
+	GIDMappings []specs.LinuxIDMapping
+}
+
+// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If
+// there is no remapping, remappedGID returns 0. If the spec cannot be parsed,
+// remappedGID returns an error.
+func remappedGID(spec []byte) (uint32, error) {
+	var ociSpec ociSpecUserNS
+	err := json.Unmarshal(spec, &ociSpec)
+	if err != nil {
+		return 0, err
+	}
+	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 {
+		return 0, nil
+	}
+	for _, mapping := range ociSpec.Linux.GIDMappings {
+		if mapping.ContainerID == 0 {
+			return mapping.HostID, nil
+		}
+	}
+	return 0, nil
+}
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_linux_test.go containerd-1.4.12~ds1/runtime/v2/bundle_linux_test.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_linux_test.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_linux_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,166 @@
+/*
+   Copyright The containerd 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 v2
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"syscall"
+	"testing"
+
+	"github.com/containerd/containerd/namespaces"
+	"github.com/containerd/containerd/oci"
+	"github.com/containerd/containerd/pkg/testutil"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func TestNewBundle(t *testing.T) {
+	testutil.RequiresRoot(t)
+	tests := []struct {
+		userns bool
+	}{{
+		userns: false,
+	}, {
+		userns: true,
+	}}
+	const usernsGID = 4200
+
+	for i, tc := range tests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			dir, err := ioutil.TempDir("", "test-new-bundle")
+			if err != nil {
+				t.Fatal("failed to create test directory", err)
+			}
+			defer os.RemoveAll(dir)
+			work := filepath.Join(dir, "work")
+			state := filepath.Join(dir, "state")
+			id := fmt.Sprintf("new-bundle-%d", i)
+			spec := oci.Spec{}
+			if tc.userns {
+				spec.Linux = &specs.Linux{
+					GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}},
+				}
+			}
+			specBytes, err := json.Marshal(&spec)
+			if err != nil {
+				t.Fatal("failed to marshal spec", err)
+			}
+
+			ctx := namespaces.WithNamespace(context.TODO(), namespaces.Default)
+			b, err := NewBundle(ctx, work, state, id, specBytes)
+			if err != nil {
+				t.Fatal("NewBundle should succeed", err)
+			}
+			if b == nil {
+				t.Fatal("bundle should not be nil")
+			}
+
+			fi, err := os.Stat(b.Path)
+			if err != nil {
+				t.Error("should be able to stat bundle path", err)
+			}
+			if tc.userns {
+				if fi.Mode() != os.ModeDir|0710 {
+					t.Error("bundle path should be a directory with perm 0710")
+				}
+			} else {
+				if fi.Mode() != os.ModeDir|0700 {
+					t.Error("bundle path should be a directory with perm 0700")
+				}
+			}
+			stat, ok := fi.Sys().(*syscall.Stat_t)
+			if !ok {
+				t.Fatal("should assert to *syscall.Stat_t")
+			}
+			expectedGID := uint32(0)
+			if tc.userns {
+				expectedGID = usernsGID
+			}
+			if expectedGID != stat.Gid {
+				t.Error("gid should match", expectedGID, stat.Gid)
+			}
+		})
+	}
+}
+
+func TestRemappedGID(t *testing.T) {
+	tests := []struct {
+		spec oci.Spec
+		gid  uint32
+	}{{
+		// empty spec
+		spec: oci.Spec{},
+		gid:  0,
+	}, {
+		// empty Linux section
+		spec: oci.Spec{
+			Linux: &specs.Linux{},
+		},
+		gid: 0,
+	}, {
+		// empty ID mappings
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: make([]specs.LinuxIDMapping, 0),
+			},
+		},
+		gid: 0,
+	}, {
+		// valid ID mapping
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: []specs.LinuxIDMapping{{
+					ContainerID: 0,
+					HostID:      1000,
+				}},
+			},
+		},
+		gid: 1000,
+	}, {
+		// missing ID mapping
+		spec: oci.Spec{
+			Linux: &specs.Linux{
+				GIDMappings: []specs.LinuxIDMapping{{
+					ContainerID: 100,
+					HostID:      1000,
+				}},
+			},
+		},
+		gid: 0,
+	}}
+
+	for i, tc := range tests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			s, err := json.Marshal(tc.spec)
+			if err != nil {
+				t.Fatal("failed to marshal spec", err)
+			}
+			gid, err := remappedGID(s)
+			if err != nil {
+				t.Error("should unmarshal successfully", err)
+			}
+			if tc.gid != gid {
+				t.Error("expected GID to match", tc.gid, gid)
+			}
+		})
+	}
+}
diff -Nru containerd-1.4.5~ds1/runtime/v2/bundle_test.go containerd-1.4.12~ds1/runtime/v2/bundle_test.go
--- containerd-1.4.5~ds1/runtime/v2/bundle_test.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/runtime/v2/bundle_test.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,23 @@
+/*
+   Copyright The containerd 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 v2
+
+import (
+	// When testutil is imported for one platform (bundle_linux_test.go) it
+	// should be imported for all platforms.
+	_ "github.com/containerd/containerd/pkg/testutil"
+)
diff -Nru containerd-1.4.5~ds1/script/setup/runc-version containerd-1.4.12~ds1/script/setup/runc-version
--- containerd-1.4.5~ds1/script/setup/runc-version	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/script/setup/runc-version	2021-11-18 03:52:12.000000000 +0800
@@ -1 +1 @@
-v1.0.0-rc94
+v1.0.2
diff -Nru containerd-1.4.5~ds1/snapshots/btrfs/btrfs.go containerd-1.4.12~ds1/snapshots/btrfs/btrfs.go
--- containerd-1.4.5~ds1/snapshots/btrfs/btrfs.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/snapshots/btrfs/btrfs.go	2021-11-18 03:52:12.000000000 +0800
@@ -63,11 +63,15 @@
 // root needs to be a mount point of btrfs.
 func NewSnapshotter(root string) (snapshots.Snapshotter, error) {
 	// If directory does not exist, create it
-	if _, err := os.Stat(root); err != nil {
+	if st, err := os.Stat(root); err != nil {
 		if !os.IsNotExist(err) {
 			return nil, err
 		}
-		if err := os.Mkdir(root, 0755); err != nil {
+		if err := os.Mkdir(root, 0700); err != nil {
+			return nil, err
+		}
+	} else if st.Mode()&os.ModePerm != 0700 {
+		if err := os.Chmod(root, 0700); err != nil {
 			return nil, err
 		}
 	}
diff -Nru containerd-1.4.5~ds1/snapshots/devmapper/snapshotter.go containerd-1.4.12~ds1/snapshots/devmapper/snapshotter.go
--- containerd-1.4.5~ds1/snapshots/devmapper/snapshotter.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/snapshots/devmapper/snapshotter.go	2021-11-18 03:52:12.000000000 +0800
@@ -232,7 +232,7 @@
 
 // View creates readonly thin device for the given snapshot key
 func (s *Snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
-	log.G(ctx).WithFields(logrus.Fields{"key": key, "parent": parent}).Debug("prepare")
+	log.G(ctx).WithFields(logrus.Fields{"key": key, "parent": parent}).Debug("view")
 
 	var (
 		mounts []mount.Mount
@@ -511,6 +511,8 @@
 }
 
 func (s *Snapshotter) Cleanup(ctx context.Context) error {
+	log.G(ctx).Debug("cleanup")
+
 	var removedDevices []*DeviceInfo
 
 	if !s.config.AsyncRemove {
diff -Nru containerd-1.4.5~ds1/.travis.yml containerd-1.4.12~ds1/.travis.yml
--- containerd-1.4.5~ds1/.travis.yml	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.travis.yml	2021-11-18 03:52:12.000000000 +0800
@@ -15,7 +15,7 @@
 - linux
 
 go:
-  - "1.15.11"
+  - "1.16.10"
 
 env:
   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v1 TRAVIS_CGO_ENABLED=1 TRAVIS_DISTRO=bionic GOPROXY=direct
diff -Nru containerd-1.4.5~ds1/Vagrantfile containerd-1.4.12~ds1/Vagrantfile
--- containerd-1.4.5~ds1/Vagrantfile	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/Vagrantfile	2021-11-18 03:52:12.000000000 +0800
@@ -77,7 +77,7 @@
   config.vm.provision "install-golang", type: "shell", run: "once" do |sh|
     sh.upload_path = "/tmp/vagrant-install-golang"
     sh.env = {
-        'GO_VERSION': ENV['GO_VERSION'] || "1.15.11",
+        'GO_VERSION': ENV['GO_VERSION'] || "1.16.10",
     }
     sh.inline = <<~SHELL
         #!/usr/bin/env bash
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os.go	2021-11-18 03:52:12.000000000 +0800
@@ -20,7 +20,6 @@
 	"io"
 	"io/ioutil"
 	"os"
-	"path/filepath"
 
 	"github.com/docker/docker/pkg/symlink"
 )
@@ -56,18 +55,6 @@
 	return os.Stat(name)
 }
 
-// ResolveSymbolicLink will follow any symbolic links
-func (RealOS) ResolveSymbolicLink(path string) (string, error) {
-	info, err := os.Lstat(path)
-	if err != nil {
-		return "", err
-	}
-	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
-		return path, nil
-	}
-	return filepath.EvalSymlinks(path)
-}
-
 // FollowSymlinkInScope will call symlink.FollowSymlinkInScope.
 func (RealOS) FollowSymlinkInScope(path, scope string) (string, error) {
 	return symlink.FollowSymlinkInScope(path, scope)
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_unix.go	2021-11-18 03:52:12.000000000 +0800
@@ -19,6 +19,9 @@
 package os
 
 import (
+	"os"
+	"path/filepath"
+
 	"github.com/containerd/containerd/mount"
 	"golang.org/x/sys/unix"
 )
@@ -57,3 +60,15 @@
 
 	return err
 }
+
+// ResolveSymbolicLink will follow any symbolic links
+func (RealOS) ResolveSymbolicLink(path string) (string, error) {
+	info, err := os.Lstat(path)
+	if err != nil {
+		return "", err
+	}
+	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
+		return path, nil
+	}
+	return filepath.EvalSymlinks(path)
+}
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_windows.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_windows.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/os/os_windows.go	1970-01-01 08:00:00.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/os/os_windows.go	2021-11-18 03:52:12.000000000 +0800
@@ -0,0 +1,182 @@
+// +build windows
+
+/*
+   Copyright The containerd 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 os
+
+import (
+	"os"
+	"strings"
+	"sync"
+	"unicode/utf16"
+
+	"golang.org/x/sys/windows"
+)
+
+// openPath takes a path, opens it, and returns the resulting handle.
+// It works for both file and directory paths.
+//
+// We are not able to use builtin Go functionality for opening a directory path:
+// - os.Open on a directory returns a os.File where Fd() is a search handle from FindFirstFile.
+// - syscall.Open does not provide a way to specify FILE_FLAG_BACKUP_SEMANTICS, which is needed to
+//   open a directory.
+// We could use os.Open if the path is a file, but it's easier to just use the same code for both.
+// Therefore, we call windows.CreateFile directly.
+func openPath(path string) (windows.Handle, error) {
+	u16, err := windows.UTF16PtrFromString(path)
+	if err != nil {
+		return 0, err
+	}
+	h, err := windows.CreateFile(
+		u16,
+		0,
+		windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
+		nil,
+		windows.OPEN_EXISTING,
+		windows.FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory handle.
+		0)
+	if err != nil {
+		return 0, &os.PathError{
+			Op:   "CreateFile",
+			Path: path,
+			Err:  err,
+		}
+	}
+	return h, nil
+}
+
+// GetFinalPathNameByHandle flags.
+//nolint:golint
+const (
+	cFILE_NAME_OPENED = 0x8
+
+	cVOLUME_NAME_DOS  = 0x0
+	cVOLUME_NAME_GUID = 0x1
+)
+
+var pool = sync.Pool{
+	New: func() interface{} {
+		// Size of buffer chosen somewhat arbitrarily to accommodate a large number of path strings.
+		// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
+		b := make([]uint16, 310)
+		return &b
+	},
+}
+
+// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
+// with the given handle and flags. It transparently takes care of creating a buffer of the
+// correct size for the call.
+func getFinalPathNameByHandle(h windows.Handle, flags uint32) (string, error) {
+	b := *(pool.Get().(*[]uint16))
+	defer func() { pool.Put(&b) }()
+	for {
+		n, err := windows.GetFinalPathNameByHandle(h, &b[0], uint32(len(b)), flags)
+		if err != nil {
+			return "", err
+		}
+		// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
+		// Resize and try again.
+		if n > uint32(len(b)) {
+			b = make([]uint16, n)
+			continue
+		}
+		// If the buffer is large enough, n will be the size not including the null terminator.
+		// Convert to a Go string and return.
+		return string(utf16.Decode(b[:n])), nil
+	}
+}
+
+// resolvePath implements path resolution for Windows. It attempts to return the "real" path to the
+// file or directory represented by the given path.
+// The resolution works by using the Windows API GetFinalPathNameByHandle, which takes a handle and
+// returns the final path to that file.
+func resolvePath(path string) (string, error) {
+	h, err := openPath(path)
+	if err != nil {
+		return "", err
+	}
+	defer windows.CloseHandle(h)
+
+	// We use the Windows API GetFinalPathNameByHandle to handle path resolution. GetFinalPathNameByHandle
+	// returns a resolved path name for a file or directory. The returned path can be in several different
+	// formats, based on the flags passed. There are several goals behind the design here:
+	// - Do as little manual path manipulation as possible. Since Windows path formatting can be quite
+	//   complex, we try to just let the Windows APIs handle that for us.
+	// - Retain as much compatibility with existing Go path functions as we can. In particular, we try to
+	//   ensure paths returned from resolvePath can be passed to EvalSymlinks.
+	//
+	// First, we query for the VOLUME_NAME_GUID path of the file. This will return a path in the form
+	// "\\?\Volume{8a25748f-cf34-4ac6-9ee2-c89400e886db}\dir\file.txt". If the path is a UNC share
+	// (e.g. "\\server\share\dir\file.txt"), then the VOLUME_NAME_GUID query will fail with ERROR_PATH_NOT_FOUND.
+	// In this case, we will next try a VOLUME_NAME_DOS query. This query will return a path for a UNC share
+	// in the form "\\?\UNC\server\share\dir\file.txt". This path will work with most functions, but EvalSymlinks
+	// fails on it. Therefore, we rewrite the path to the form "\\server\share\dir\file.txt" before returning it.
+	// This path rewrite may not be valid in all cases (see the notes in the next paragraph), but those should
+	// be very rare edge cases, and this case wouldn't have worked with EvalSymlinks anyways.
+	//
+	// The "\\?\" prefix indicates that no path parsing or normalization should be performed by Windows.
+	// Instead the path is passed directly to the object manager. The lack of parsing means that "." and ".." are
+	// interpreted literally and "\"" must be used as a path separator. Additionally, because normalization is
+	// not done, certain paths can only be represented in this format. For instance, "\\?\C:\foo." (with a trailing .)
+	// cannot be written as "C:\foo.", because path normalization will remove the trailing ".".
+	//
+	// We use FILE_NAME_OPENED instead of FILE_NAME_NORMALIZED, as FILE_NAME_NORMALIZED can fail on some
+	// UNC paths based on access restrictions. The additional normalization done is also quite minimal in
+	// most cases.
+	//
+	// Querying for VOLUME_NAME_DOS first instead of VOLUME_NAME_GUID would yield a "nicer looking" path in some cases.
+	// For instance, it could return "\\?\C:\dir\file.txt" instead of "\\?\Volume{8a25748f-cf34-4ac6-9ee2-c89400e886db}\dir\file.txt".
+	// However, we query for VOLUME_NAME_GUID first for two reasons:
+	// - The volume GUID path is more stable. A volume's mount point can change when it is remounted, but its
+	//   volume GUID should not change.
+	// - If the volume is mounted at a non-drive letter path (e.g. mounted to "C:\mnt"), then VOLUME_NAME_DOS
+	//   will return the mount path. EvalSymlinks fails on a path like this due to a bug.
+	//
+	// References:
+	// - GetFinalPathNameByHandle: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea
+	// - Naming Files, Paths, and Namespaces: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+	// - Naming a Volume: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-volume
+
+	rPath, err := getFinalPathNameByHandle(h, cFILE_NAME_OPENED|cVOLUME_NAME_GUID)
+	if err == windows.ERROR_PATH_NOT_FOUND {
+		// ERROR_PATH_NOT_FOUND is returned from the VOLUME_NAME_GUID query if the path is a
+		// network share (UNC path). In this case, query for the DOS name instead, then translate
+		// the returned path to make it more palatable to other path functions.
+		rPath, err = getFinalPathNameByHandle(h, cFILE_NAME_OPENED|cVOLUME_NAME_DOS)
+		if err != nil {
+			return "", err
+		}
+		if strings.HasPrefix(rPath, `\\?\UNC\`) {
+			// Convert \\?\UNC\server\share -> \\server\share. The \\?\UNC syntax does not work with
+			// some Go filepath functions such as EvalSymlinks. In the future if other components
+			// move away from EvalSymlinks and use GetFinalPathNameByHandle instead, we could remove
+			// this path munging.
+			rPath = `\\` + rPath[len(`\\?\UNC\`):]
+		}
+	} else if err != nil {
+		return "", err
+	}
+	return rPath, nil
+}
+
+// ResolveSymbolicLink will follow any symbolic links
+func (RealOS) ResolveSymbolicLink(path string) (string, error) {
+	// filepath.EvalSymlinks does not work very well on Windows, so instead we resolve the path
+	// via resolvePath which uses GetFinalPathNameByHandle. This returns either a path prefixed with `\\?\`,
+	// or a remote share path in the form \\server\share. These should work with most Go and Windows APIs.
+	return resolvePath(path)
+}
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go	2021-11-18 03:52:12.000000000 +0800
@@ -124,8 +124,10 @@
 		sandbox.NetNSPath = sandbox.NetNS.GetPath()
 		defer func() {
 			if retErr != nil {
+				deferCtx, deferCancel := ctrdutil.DeferContext()
+				defer deferCancel()
 				// Teardown network if an error is returned.
-				if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
+				if err := c.teardownPodNetwork(deferCtx, sandbox); err != nil {
 					log.G(ctx).WithError(err).Errorf("Failed to destroy network for sandbox %q", id)
 				}
 
diff -Nru containerd-1.4.5~ds1/vendor/github.com/containerd/cri/vendor.conf containerd-1.4.12~ds1/vendor/github.com/containerd/cri/vendor.conf
--- containerd-1.4.5~ds1/vendor/github.com/containerd/cri/vendor.conf	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor/github.com/containerd/cri/vendor.conf	2021-11-18 03:52:12.000000000 +0800
@@ -10,8 +10,8 @@
 github.com/cespare/xxhash/v2                        v2.1.1
 github.com/containerd/cgroups                       318312a373405e5e91134d8063d04d59768a1bff
 github.com/containerd/console                       v1.0.0
-github.com/containerd/containerd                    v1.4.1
-github.com/containerd/continuity                    efbc4488d8fe1bdc16bde3b2d2990d9b3a899165
+github.com/containerd/containerd                    8263eb3eaee447b16856eeb8839d5df4c9cca71a
+github.com/containerd/continuity                    1d9893e5674b5260c3fc11316d0d5fc0d12ea9e2
 github.com/containerd/fifo                          f15a3290365b9d2627d189e619ab4008e0069caf
 github.com/containerd/go-runc                       7016d3ce2328dd2cb1192b2076ebd565c4e8df0c
 github.com/containerd/ttrpc                         v1.0.1
@@ -33,11 +33,11 @@
 github.com/imdario/mergo                            v0.3.7
 github.com/konsorten/go-windows-terminal-sequences  v1.0.3
 github.com/matttproud/golang_protobuf_extensions    v1.0.1
-github.com/Microsoft/go-winio                       v0.4.14
-github.com/Microsoft/hcsshim                        v0.8.9
+github.com/Microsoft/go-winio                       v0.4.19
+github.com/Microsoft/hcsshim                        v0.8.16
 github.com/opencontainers/go-digest                 v1.0.0
 github.com/opencontainers/image-spec                v1.0.1
-github.com/opencontainers/runc                      v1.0.0-rc92
+github.com/opencontainers/runc                      v1.0.0-rc94
 github.com/opencontainers/runtime-spec              4d89ac9fbff6c455f46a5bb59c6b1bb7184a5e43 # v1.0.3-0.20200728170252-4d89ac9fbff6
 github.com/pkg/errors                               v0.9.1
 github.com/prometheus/client_golang                 v1.6.0
@@ -51,9 +51,9 @@
 github.com/urfave/cli                               v1.22.1 # NOTE: urfave/cli must be <= v1.22.1 due to a regression: https://github.com/urfave/cli/issues/1092
 go.etcd.io/bbolt                                    v1.3.5
 go.opencensus.io                                    v0.22.0
-golang.org/x/net                                    ab34263943818b32f575efc978a3d24e80b04bd7
-golang.org/x/sync                                   42b317875d0fa942474b76e1b46a6060d720ae6e
-golang.org/x/sys                                    ed371f2e16b4b305ee99df548828de367527b76b
+golang.org/x/net                                    69a78807bb2bb6d1599c68698c6b009505012083
+golang.org/x/sync                                   67f06af15bc961c363a7260195bcd53487529a21
+golang.org/x/sys                                    d19ff857e887eacb631721f188c7d365c2331456
 golang.org/x/text                                   v0.3.3
 google.golang.org/genproto                          e50cd9704f63023d62cd06a1994b98227fc4d21a
 google.golang.org/grpc                              v1.27.1
@@ -77,15 +77,15 @@
 golang.org/x/time                                   555d28b269f0569763d25dbe1a237ae74c6bcc82
 gopkg.in/inf.v0                                     v0.9.1
 gopkg.in/yaml.v2                                    v2.2.8
-k8s.io/api                                          v0.19.4
-k8s.io/apiserver                                    v0.19.4
-k8s.io/apimachinery                                 v0.19.4
-k8s.io/client-go                                    v0.19.4
-k8s.io/component-base                               v0.19.4
-k8s.io/cri-api                                      v0.19.4
+k8s.io/api                                          v0.19.10
+k8s.io/apiserver                                    v0.19.10
+k8s.io/apimachinery                                 v0.19.10
+k8s.io/client-go                                    v0.19.10
+k8s.io/component-base                               v0.19.10
+k8s.io/cri-api                                      v0.19.10
 k8s.io/klog/v2                                      v2.2.0
 k8s.io/utils                                        d5654de09c73da55eb19ae4ab4f734f7a61747a6
-sigs.k8s.io/structured-merge-diff/v4                v4.0.1
+sigs.k8s.io/structured-merge-diff/v4                v4.0.3
 sigs.k8s.io/yaml                                    v1.2.0
 
 # cni dependencies
diff -Nru containerd-1.4.5~ds1/vendor.conf containerd-1.4.12~ds1/vendor.conf
--- containerd-1.4.5~ds1/vendor.conf	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/vendor.conf	2021-11-18 03:52:12.000000000 +0800
@@ -27,11 +27,11 @@
 github.com/imdario/mergo                            v0.3.7
 github.com/konsorten/go-windows-terminal-sequences  v1.0.3
 github.com/matttproud/golang_protobuf_extensions    v1.0.1
-github.com/Microsoft/go-winio                       v0.4.14
-github.com/Microsoft/hcsshim                        v0.8.10
+github.com/Microsoft/go-winio                       v0.4.19
+github.com/Microsoft/hcsshim                        v0.8.21
 github.com/opencontainers/go-digest                 v1.0.0
 github.com/opencontainers/image-spec                v1.0.1
-github.com/opencontainers/runc                      v1.0.0-rc92
+github.com/opencontainers/runc                      v1.0.0-rc94
 github.com/opencontainers/runtime-spec              4d89ac9fbff6c455f46a5bb59c6b1bb7184a5e43 # v1.0.3-0.20200728170252-4d89ac9fbff6
 github.com/pkg/errors                               v0.9.1
 github.com/prometheus/client_golang                 v1.6.0
@@ -47,7 +47,7 @@
 go.opencensus.io                                    v0.22.0
 golang.org/x/net                                    69a78807bb2bb6d1599c68698c6b009505012083
 golang.org/x/sync                                   67f06af15bc961c363a7260195bcd53487529a21
-golang.org/x/sys                                    5cba982894dd4e8879e3ef0a0c308ceff39f6154
+golang.org/x/sys                                    d19ff857e887eacb631721f188c7d365c2331456
 golang.org/x/text                                   v0.3.3
 google.golang.org/genproto                          e50cd9704f63023d62cd06a1994b98227fc4d21a
 google.golang.org/grpc                              v1.27.1
@@ -57,7 +57,7 @@
 github.com/cilium/ebpf                              1c8d4c9ef7759622653a1d319284a44652333b28
 
 # cri dependencies
-github.com/containerd/cri                           1360416eca4fef15c763444914e60fe1eaedbc3d # release/1.4
+github.com/containerd/cri                           3b02bec1603179debe2cde54509b2bfc45fc27d3 # release/1.4
 github.com/davecgh/go-spew                          v1.1.1
 github.com/docker/docker                            4634ce647cf2ce2c6031129ccd109e557244986f
 github.com/docker/spdystream                        449fdfce4d962303d702fec724ef0ad181c92528
diff -Nru containerd-1.4.5~ds1/version/version.go containerd-1.4.12~ds1/version/version.go
--- containerd-1.4.5~ds1/version/version.go	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/version/version.go	2021-11-18 03:52:12.000000000 +0800
@@ -23,7 +23,7 @@
 	Package = "github.com/containerd/containerd"
 
 	// Version holds the complete version number. Filled in at linking time.
-	Version = "1.4.5+unknown"
+	Version = "1.4.12+unknown"
 
 	// Revision is filled with the VCS (e.g. git) revision being used to build
 	// the program at linking time.
diff -Nru containerd-1.4.5~ds1/.zuul/playbooks/containerd-build/run.yaml containerd-1.4.12~ds1/.zuul/playbooks/containerd-build/run.yaml
--- containerd-1.4.5~ds1/.zuul/playbooks/containerd-build/run.yaml	2021-05-12 12:30:30.000000000 +0800
+++ containerd-1.4.12~ds1/.zuul/playbooks/containerd-build/run.yaml	2021-11-18 03:52:12.000000000 +0800
@@ -2,7 +2,7 @@
   become: yes
   roles:
   - role: config-golang
-    go_version: '1.15.11'
+    go_version: '1.16.10'
     arch: arm64
   tasks:
   - name: Build containerd

--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 11.2

Hi,

Each of the updates referenced by these requests was included in
today's bullseye point release, but my original closure mail failed to
correctly handle 7-digit bug numbers. Fixing that omission now.

Regards,

Adam

--- End Message ---

Reply to: