CVE-2021-43816 (published 2022-01-05T19:15Z)

containerd is an open source container runtime. On installations using SELinux, such as EL8 (CentOS, RHEL), Fedora, or SUSE MicroOS, with containerd since v1.5.0-beta.0 as the backing container runtime interface (CRI), an unprivileged pod scheduled to the node may bind mount, via hostPath volume, any privileged, regular file on disk for complete read/write access (sans delete). Such is achieved by placing the in-container location of the hostPath volume mount at either `/etc/hosts`, `/etc/hostname`, or `/etc/resolv.conf`. These locations are being relabeled indiscriminately to match the container process-label which effectively elevates permissions for savvy containers that would not normally be able to access privileged host files. This issue has been resolved in version 1.5.9. Users are advised to upgrade as soon as possible.

Severity: MEDIUM
CVSS v2 base score: 6.0 (AV:N/AC:M/Au:S/C:P/I:P/A:P)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-281
cwe_name: Improper Preservation of Permissions
description: The product does not preserve permissions or incorrectly preserves permissions when copying, restoring, or sharing objects, which can cause them to have less restrictive permissions than intended.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/dweomer/containerd
commit_details: repo_url: https://github.com/dweomer/containerd
author: Jacob Blain Christen
author_date: 2021-11-02 12:38:43-07:00
msg: Revert "[cri] label etc files for selinux containers"

This reverts commit a731039238c62be081eb8c31525b988415745eea.
repository: repo_url: https://github.com/dweomer/containerd
repo_name: dweomer/containerd
description: An open and reliable container runtime
repo_language: Go
owner: dweomer
file_changes: filename: spec_linux.go
change_type: ModificationType.MODIFY
diff: @@ -225,30 +225,6 @@ func WithMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*ru
 	}
 }
 
-const (
-	etcHosts       = "/etc/hosts"
-	etcHostname    = "/etc/hostname"
-	resolvConfPath = "/etc/resolv.conf"
-)
-
-// WithRelabeledContainerMounts relabels the default container mounts for files in /etc
-func WithRelabeledContainerMounts(mountLabel string) oci.SpecOpts {
-	return func(ctx context.Context, client oci.Client, _ *containers.Container, s *runtimespec.Spec) (err error) {
-		if mountLabel == "" {
-			return nil
-		}
-		for _, m := range s.Mounts {
-			switch m.Destination {
-			case etcHosts, etcHostname, resolvConfPath:
-				if err := label.Relabel(m.Source, mountLabel, false); err != nil {
-					return err
-				}
-			}
-		}
-		return nil
-	}
-}
-
 // Ensure mount point on which path is mounted, is shared.
 func ensureShared(path string, lookupMount func(string) (mount.Info, error)) error {
 	mountInfo, err := lookupMount(path)

programming_language: Go
filename: container_create_linux.go
change_type: ModificationType.MODIFY
diff: @@ -192,7 +192,7 @@ func (c *criService) containerSpec(
 		}
 	}()
 
-	specOpts = append(specOpts, customopts.WithMounts(c.os, config, extraMounts, mountLabel), customopts.WithRelabeledContainerMounts(mountLabel))
+	specOpts = append(specOpts, customopts.WithMounts(c.os, config, extraMounts, mountLabel))
 
 	if !c.config.DisableProcMount {
 		// Change the default masked/readonly paths to empty slices

programming_language: Go
repo_url: https://github.com/containerd/containerd
commit_details: repo_url: https://github.com/containerd/containerd
author: Michael Crosby
author_date: 2021-01-19 13:42:09-05:00
msg: [cri] label etc files for selinux containers

Signed-off-by: Michael Crosby <michael@thepasture.io>
repository: repo_url: https://github.com/containerd/containerd
repo_name: containerd/containerd
description: An open and reliable container runtime
repo_language: Go
owner: containerd
file_changes: filename: spec_linux.go
change_type: ModificationType.MODIFY
diff: @@ -242,6 +242,30 @@ func WithMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*ru
 	}
 }
 
+const (
+	etcHosts       = "/etc/hosts"
+	etcHostname    = "/etc/hostname"
+	resolvConfPath = "/etc/resolv.conf"
+)
+
+// WithRelabeledContainerMounts relabels the default container mounts for files in /etc
+func WithRelabeledContainerMounts(mountLabel string) oci.SpecOpts {
+	return func(ctx context.Context, client oci.Client, _ *containers.Container, s *runtimespec.Spec) (err error) {
+		if mountLabel == "" {
+			return nil
+		}
+		for _, m := range s.Mounts {
+			switch m.Destination {
+			case etcHosts, etcHostname, resolvConfPath:
+				if err := label.Relabel(m.Source, mountLabel, false); err != nil {
+					return err
+				}
+			}
+		}
+		return nil
+	}
+}
+
 // Ensure mount point on which path is mounted, is shared.
 func ensureShared(path string, lookupMount func(string) (mount.Info, error)) error {
 	mountInfo, err := lookupMount(path)

programming_language: Go
filename: container_create_linux.go
change_type: ModificationType.MODIFY
diff: @@ -183,7 +183,7 @@ func (c *criService) containerSpec(id string, sandboxID string, sandboxPid uint3
 		}
 	}()
 
-	specOpts = append(specOpts, customopts.WithMounts(c.os, config, extraMounts, mountLabel))
+	specOpts = append(specOpts, customopts.WithMounts(c.os, config, extraMounts, mountLabel), customopts.WithRelabeledContainerMounts(mountLabel))
 
 	if !c.config.DisableProcMount {
 		// Apply masked paths if specified.

programming_language: Go