From fe70d9e0048502addcbeea5399f2da554a14bd78 Mon Sep 17 00:00:00 2001
From: xiadanni <xiadanni1@huawei.com>
Date: Tue, 9 Nov 2021 16:25:09 +0800
Subject: [PATCH] [Backport]containerd:reduce permissions for bundle dir to fix
 CVE-2021-41103

reduce permissions for bundle dir
reduce permissions on plugin directories
fix CVE-2021-41103

Conflict:NA
Reference:https://github.com/containerd/containerd/commit/6886c6a2ec0c70dde1aa64e77b64a5ad47b983c3
https://github.com/containerd/containerd/commit/7c621e1fcc08bcf5a1a48b837342cc22eada1685
---
 runtime/v1/linux/bundle.go | 56 +++++++++++++++++++++++++++++++++++++-
 snapshots/btrfs/btrfs.go   |  8 ++++--
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/runtime/v1/linux/bundle.go b/runtime/v1/linux/bundle.go
index 0442246f9..90a10862e 100644
--- a/runtime/v1/linux/bundle.go
+++ b/runtime/v1/linux/bundle.go
@@ -20,6 +20,7 @@ package linux
 
 import (
 	"context"
+	"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"
 	"github.com/sirupsen/logrus"
 )
@@ -63,7 +65,7 @@ func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
 		time.Sleep(waitTime)
 	}
 
-	if err := os.Mkdir(path, 0711); err != nil {
+	if err := os.Mkdir(path, 0700); err != nil {
 		return nil, err
 	}
 	defer func() {
@@ -71,6 +73,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
+	}
 	if err := os.MkdirAll(workDir, 0711); err != nil {
 		return nil, err
 	}
@@ -90,6 +95,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/snapshots/btrfs/btrfs.go b/snapshots/btrfs/btrfs.go
index a89b55129..da6f8220e 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
 		}
 	}
-- 
2.27.0

