Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions SPECS/moby-containerd/CVE-2024-40635.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
From 9639b9625554183d0c4d8d072dccb84fedd2320f Mon Sep 17 00:00:00 2001
From: Craig Ingram <Cjingram@google.com>
Date: Fri, 7 Mar 2025 13:27:58 +0000
Subject: [PATCH] validate uid/gid

---
oci/spec_opts.go | 24 ++++++++--
oci/spec_opts_linux_test.go | 92 +++++++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/oci/spec_opts.go b/oci/spec_opts.go
index 8acb38f43b11..d2c08e0b012d 100644
--- a/oci/spec_opts.go
+++ b/oci/spec_opts.go
@@ -22,6 +22,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "math"
"os"
"path/filepath"
"runtime"
@@ -576,6 +577,20 @@ func WithUser(userstr string) SpecOpts {
defer ensureAdditionalGids(s)
setProcess(s)
s.Process.User.AdditionalGids = nil
+ // While the Linux kernel allows the max UID to be MaxUint32 - 2,
+ // and the OCI Runtime Spec has no definition about the max UID,
+ // the runc implementation is known to require the UID to be <= MaxInt32.
+ //
+ // containerd follows runc's limitation here.
+ //
+ // In future we may relax this limitation to allow MaxUint32 - 2,
+ // or, amend the OCI Runtime Spec to codify the implementation limitation.
+ const (
+ minUserID = 0
+ maxUserID = math.MaxInt32
+ minGroupID = 0
+ maxGroupID = math.MaxInt32
+ )

// For LCOW it's a bit harder to confirm that the user actually exists on the host as a rootfs isn't
// mounted on the host and shared into the guest, but rather the rootfs is constructed entirely in the
@@ -592,8 +607,8 @@ func WithUser(userstr string) SpecOpts {
switch len(parts) {
case 1:
v, err := strconv.Atoi(parts[0])
- if err != nil {
- // if we cannot parse as a uint they try to see if it is a username
+ if err != nil || v < minUserID || v > maxUserID {
+ // if we cannot parse as an int32 then try to see if it is a username
return WithUsername(userstr)(ctx, client, c, s)
}
return WithUserID(uint32(v))(ctx, client, c, s)
@@ -604,12 +619,13 @@ func WithUser(userstr string) SpecOpts {
)
var uid, gid uint32
v, err := strconv.Atoi(parts[0])
- if err != nil {
+ if err != nil || v < minUserID || v > maxUserID {
username = parts[0]
} else {
uid = uint32(v)
}
- if v, err = strconv.Atoi(parts[1]); err != nil {
+ v, err = strconv.Atoi(parts[1])
+ if err != nil || v < minGroupID || v > maxGroupID {
groupname = parts[1]
} else {
gid = uint32(v)
diff --git a/oci/spec_opts_linux_test.go b/oci/spec_opts_linux_test.go
index f4acf573ba46..c3f436e85f1a 100644
--- a/oci/spec_opts_linux_test.go
+++ b/oci/spec_opts_linux_test.go
@@ -32,6 +32,98 @@ import (
"golang.org/x/sys/unix"
)

+//nolint:gosec
+func TestWithUser(t *testing.T) {
+ t.Parallel()
+
+ expectedPasswd := `root:x:0:0:root:/root:/bin/ash
+guest:x:405:100:guest:/dev/null:/sbin/nologin
+`
+ expectedGroup := `root:x:0:root
+bin:x:1:root,bin,daemon
+daemon:x:2:root,bin,daemon
+sys:x:3:root,bin,adm
+guest:x:100:guest
+`
+ td := t.TempDir()
+ apply := fstest.Apply(
+ fstest.CreateDir("/etc", 0777),
+ fstest.CreateFile("/etc/passwd", []byte(expectedPasswd), 0777),
+ fstest.CreateFile("/etc/group", []byte(expectedGroup), 0777),
+ )
+ if err := apply.Apply(td); err != nil {
+ t.Fatalf("failed to apply: %v", err)
+ }
+ c := containers.Container{ID: t.Name()}
+ testCases := []struct {
+ user string
+ expectedUID uint32
+ expectedGID uint32
+ err string
+ }{
+ {
+ user: "0",
+ expectedUID: 0,
+ expectedGID: 0,
+ },
+ {
+ user: "root:root",
+ expectedUID: 0,
+ expectedGID: 0,
+ },
+ {
+ user: "guest",
+ expectedUID: 405,
+ expectedGID: 100,
+ },
+ {
+ user: "guest:guest",
+ expectedUID: 405,
+ expectedGID: 100,
+ },
+ {
+ user: "guest:nobody",
+ err: "no groups found",
+ },
+ {
+ user: "405:100",
+ expectedUID: 405,
+ expectedGID: 100,
+ },
+ {
+ user: "405:2147483648",
+ err: "no groups found",
+ },
+ {
+ user: "-1000",
+ err: "no users found",
+ },
+ {
+ user: "2147483648",
+ err: "no users found",
+ },
+ }
+ for _, testCase := range testCases {
+ testCase := testCase
+ t.Run(testCase.user, func(t *testing.T) {
+ t.Parallel()
+ s := Spec{
+ Version: specs.Version,
+ Root: &specs.Root{
+ Path: td,
+ },
+ Linux: &specs.Linux{},
+ }
+ err := WithUser(testCase.user)(context.Background(), nil, &c, &s)
+ if err != nil {
+ assert.EqualError(t, err, testCase.err)
+ }
+ assert.Equal(t, testCase.expectedUID, s.Process.User.UID)
+ assert.Equal(t, testCase.expectedGID, s.Process.User.GID)
+ })
+ }
+}
+
//nolint:gosec
func TestWithUserID(t *testing.T) {
t.Parallel()
6 changes: 5 additions & 1 deletion SPECS/moby-containerd/moby-containerd.spec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Summary: Industry-standard container runtime
Name: moby-%{upstream_name}
Version: 1.6.26
Release: 10%{?dist}
Release: 11%{?dist}
License: ASL 2.0
Group: Tools/Container
URL: https://www.containerd.io
Expand All @@ -22,6 +22,7 @@ Patch3: CVE-2023-45288.patch
Patch4: CVE-2024-24786.patch
Patch5: CVE-2024-28180.patch
Patch6: CVE-2025-27144.patch
Patch7: CVE-2024-40635.patch

%{?systemd_requires}

Expand Down Expand Up @@ -95,6 +96,9 @@ fi
%dir /opt/containerd/lib

%changelog
* Wed Apr 09 2025 Aadhar Agarwal <aadagarwal@microsoft.com> - 1.6.26-11
- Fix CVE-2024-40635 with an upstream patch

* Fri Feb 28 2025 Kanishk Bansal <kanbansal@microsoft.com> - 1.6.26-10
- Fix CVE-2025-27144 with an upstream patch

Expand Down
Loading