-
Notifications
You must be signed in to change notification settings - Fork 614
Expand file tree
/
Copy pathCVE-2024-40635.patch
More file actions
174 lines (170 loc) · 4.78 KB
/
CVE-2024-40635.patch
File metadata and controls
174 lines (170 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
From 07a0b5419c408e70ed90179ea3e5825d986f80af Mon Sep 17 00:00:00 2001
From: Craig Ingram <Cjingram@google.com>
Date: Tue, 11 Mar 2025 14:52:44 +0000
Subject: [PATCH] (cherry picked from commit
de1341c201ffb0effebbf51d00376181968c8779)
---
pkg/oci/spec_opts.go | 24 +++++++--
pkg/oci/spec_opts_linux_test.go | 92 +++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 4 deletions(-)
diff --git a/pkg/oci/spec_opts.go b/pkg/oci/spec_opts.go
index 3b85d764ae10..f7b298122957 100644
--- a/pkg/oci/spec_opts.go
+++ b/pkg/oci/spec_opts.go
@@ -22,6 +22,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "math"
"os"
"path/filepath"
"runtime"
@@ -593,6 +594,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
@@ -611,8 +626,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)
@@ -623,12 +638,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/pkg/oci/spec_opts_linux_test.go b/pkg/oci/spec_opts_linux_test.go
index 9299fa1807b6..d34af356b103 100644
--- a/pkg/oci/spec_opts_linux_test.go
+++ b/pkg/oci/spec_opts_linux_test.go
@@ -33,6 +33,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()