summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheo GAIGE <tgaige.opensource@witekio.com>2025-10-02 10:05:07 +0200
committerBruce Ashfield <bruce.ashfield@gmail.com>2025-10-13 21:57:54 -0400
commit16155ae737d96f0f53721ad7270c3fe19729d496 (patch)
tree21b75b2070fa71a3d954fdff4fb2e23368566239
parent5429fc0f5c2ebd7187e54913220f579417fcbaed (diff)
downloadmeta-virtualization-16155ae737d96f0f53721ad7270c3fe19729d496.tar.gz
containerd-opencontainers: fix CVE-2024-40635
Upstream-Status: Backport from https://github.com/containerd/containerd/commit/9639b9625554183d0c4d8d072dccb84fedd2320f Signed-off-by: Theo GAIGE <tgaige.opensource@witekio.com> Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
-rw-r--r--recipes-containers/containerd/containerd-opencontainers/CVE-2024-40635.patch180
-rw-r--r--recipes-containers/containerd/containerd-opencontainers_git.bb1
2 files changed, 181 insertions, 0 deletions
diff --git a/recipes-containers/containerd/containerd-opencontainers/CVE-2024-40635.patch b/recipes-containers/containerd/containerd-opencontainers/CVE-2024-40635.patch
new file mode 100644
index 00000000..71a0f8b6
--- /dev/null
+++ b/recipes-containers/containerd/containerd-opencontainers/CVE-2024-40635.patch
@@ -0,0 +1,180 @@
1From 6727fad7cc608f47304c073d758a04ca516e08fd Mon Sep 17 00:00:00 2001
2From: Craig Ingram <Cjingram@google.com>
3Date: Fri, 7 Mar 2025 13:27:58 +0000
4Subject: [PATCH] validate uid/gid
5
6Upstream-Status: Backport [https://github.com/containerd/containerd/commit/9639b9625554183d0c4d8d072dccb84fedd2320f]
7CVE: CVE-2024-40635
8
9Signed-off-by: Theo GAIGE <tgaige.opensource@witekio.com>
10---
11 oci/spec_opts.go | 24 ++++++++--
12 oci/spec_opts_linux_test.go | 92 +++++++++++++++++++++++++++++++++++++
13 2 files changed, 112 insertions(+), 4 deletions(-)
14
15diff --git a/oci/spec_opts.go b/oci/spec_opts.go
16index 3330ad108..1f10b24c6 100644
17--- a/oci/spec_opts.go
18+++ b/oci/spec_opts.go
19@@ -22,6 +22,7 @@ import (
20 "encoding/json"
21 "errors"
22 "fmt"
23+ "math"
24 "os"
25 "path/filepath"
26 "runtime"
27@@ -536,6 +537,20 @@ func WithUser(userstr string) SpecOpts {
28 defer ensureAdditionalGids(s)
29 setProcess(s)
30 s.Process.User.AdditionalGids = nil
31+ // While the Linux kernel allows the max UID to be MaxUint32 - 2,
32+ // and the OCI Runtime Spec has no definition about the max UID,
33+ // the runc implementation is known to require the UID to be <= MaxInt32.
34+ //
35+ // containerd follows runc's limitation here.
36+ //
37+ // In future we may relax this limitation to allow MaxUint32 - 2,
38+ // or, amend the OCI Runtime Spec to codify the implementation limitation.
39+ const (
40+ minUserID = 0
41+ maxUserID = math.MaxInt32
42+ minGroupID = 0
43+ maxGroupID = math.MaxInt32
44+ )
45
46 // For LCOW it's a bit harder to confirm that the user actually exists on the host as a rootfs isn't
47 // mounted on the host and shared into the guest, but rather the rootfs is constructed entirely in the
48@@ -552,8 +567,8 @@ func WithUser(userstr string) SpecOpts {
49 switch len(parts) {
50 case 1:
51 v, err := strconv.Atoi(parts[0])
52- if err != nil {
53- // if we cannot parse as a uint they try to see if it is a username
54+ if err != nil || v < minUserID || v > maxUserID {
55+ // if we cannot parse as an int32 then try to see if it is a username
56 return WithUsername(userstr)(ctx, client, c, s)
57 }
58 return WithUserID(uint32(v))(ctx, client, c, s)
59@@ -564,12 +579,13 @@ func WithUser(userstr string) SpecOpts {
60 )
61 var uid, gid uint32
62 v, err := strconv.Atoi(parts[0])
63- if err != nil {
64+ if err != nil || v < minUserID || v > maxUserID {
65 username = parts[0]
66 } else {
67 uid = uint32(v)
68 }
69- if v, err = strconv.Atoi(parts[1]); err != nil {
70+ v, err = strconv.Atoi(parts[1])
71+ if err != nil || v < minGroupID || v > maxGroupID {
72 groupname = parts[1]
73 } else {
74 gid = uint32(v)
75diff --git a/oci/spec_opts_linux_test.go b/oci/spec_opts_linux_test.go
76index 904edcb42..f3be5ef27 100644
77--- a/oci/spec_opts_linux_test.go
78+++ b/oci/spec_opts_linux_test.go
79@@ -31,6 +31,98 @@ import (
80 "golang.org/x/sys/unix"
81 )
82
83+// nolint:gosec
84+func TestWithUser(t *testing.T) {
85+ t.Parallel()
86+
87+ expectedPasswd := `root:x:0:0:root:/root:/bin/ash
88+guest:x:405:100:guest:/dev/null:/sbin/nologin
89+`
90+ expectedGroup := `root:x:0:root
91+bin:x:1:root,bin,daemon
92+daemon:x:2:root,bin,daemon
93+sys:x:3:root,bin,adm
94+guest:x:100:guest
95+`
96+ td := t.TempDir()
97+ apply := fstest.Apply(
98+ fstest.CreateDir("/etc", 0777),
99+ fstest.CreateFile("/etc/passwd", []byte(expectedPasswd), 0777),
100+ fstest.CreateFile("/etc/group", []byte(expectedGroup), 0777),
101+ )
102+ if err := apply.Apply(td); err != nil {
103+ t.Fatalf("failed to apply: %v", err)
104+ }
105+ c := containers.Container{ID: t.Name()}
106+ testCases := []struct {
107+ user string
108+ expectedUID uint32
109+ expectedGID uint32
110+ err string
111+ }{
112+ {
113+ user: "0",
114+ expectedUID: 0,
115+ expectedGID: 0,
116+ },
117+ {
118+ user: "root:root",
119+ expectedUID: 0,
120+ expectedGID: 0,
121+ },
122+ {
123+ user: "guest",
124+ expectedUID: 405,
125+ expectedGID: 100,
126+ },
127+ {
128+ user: "guest:guest",
129+ expectedUID: 405,
130+ expectedGID: 100,
131+ },
132+ {
133+ user: "guest:nobody",
134+ err: "no groups found",
135+ },
136+ {
137+ user: "405:100",
138+ expectedUID: 405,
139+ expectedGID: 100,
140+ },
141+ {
142+ user: "405:2147483648",
143+ err: "no groups found",
144+ },
145+ {
146+ user: "-1000",
147+ err: "no users found",
148+ },
149+ {
150+ user: "2147483648",
151+ err: "no users found",
152+ },
153+ }
154+ for _, testCase := range testCases {
155+ testCase := testCase
156+ t.Run(testCase.user, func(t *testing.T) {
157+ t.Parallel()
158+ s := Spec{
159+ Version: specs.Version,
160+ Root: &specs.Root{
161+ Path: td,
162+ },
163+ Linux: &specs.Linux{},
164+ }
165+ err := WithUser(testCase.user)(context.Background(), nil, &c, &s)
166+ if err != nil {
167+ assert.EqualError(t, err, testCase.err)
168+ }
169+ assert.Equal(t, testCase.expectedUID, s.Process.User.UID)
170+ assert.Equal(t, testCase.expectedGID, s.Process.User.GID)
171+ })
172+ }
173+}
174+
175 // nolint:gosec
176 func TestWithUserID(t *testing.T) {
177 t.Parallel()
178--
1792.43.0
180
diff --git a/recipes-containers/containerd/containerd-opencontainers_git.bb b/recipes-containers/containerd/containerd-opencontainers_git.bb
index 6c0266ac..dd621705 100644
--- a/recipes-containers/containerd/containerd-opencontainers_git.bb
+++ b/recipes-containers/containerd/containerd-opencontainers_git.bb
@@ -9,6 +9,7 @@ SRCREV = "1e1ea6e986c6c86565bc33d52e34b81b3e2bc71f"
9SRC_URI = "git://github.com/containerd/containerd;branch=release/1.6;protocol=https;destsuffix=git/src/github.com/containerd/containerd \ 9SRC_URI = "git://github.com/containerd/containerd;branch=release/1.6;protocol=https;destsuffix=git/src/github.com/containerd/containerd \
10 file://0001-Makefile-allow-GO_BUILD_FLAGS-to-be-externally-speci.patch \ 10 file://0001-Makefile-allow-GO_BUILD_FLAGS-to-be-externally-speci.patch \
11 file://0001-build-don-t-use-gcflags-to-define-trimpath.patch \ 11 file://0001-build-don-t-use-gcflags-to-define-trimpath.patch \
12 file://CVE-2024-40635.patch \
12 " 13 "
13 14
14# Apache-2.0 for containerd 15# Apache-2.0 for containerd