Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/commoncap_test.c
121769 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* KUnit tests for commoncap.c security functions
4
*
5
* Tests for security-critical functions in the capability subsystem,
6
* particularly namespace-related capability checks.
7
*/
8
9
#include <kunit/test.h>
10
#include <linux/user_namespace.h>
11
#include <linux/uidgid.h>
12
#include <linux/cred.h>
13
#include <linux/mnt_idmapping.h>
14
#include <linux/module.h>
15
#include <linux/slab.h>
16
#include <linux/refcount.h>
17
18
#ifdef CONFIG_SECURITY_COMMONCAP_KUNIT_TEST
19
20
/* Functions are static in commoncap.c, but we can call them since we're
21
* included in the same compilation unit when tests are enabled.
22
*/
23
24
/**
25
* test_vfsuid_root_in_currentns_init_ns - Test vfsuid_root_in_currentns with init ns
26
*
27
* Verifies that UID 0 in the init namespace correctly owns the current
28
* namespace when running in init_user_ns.
29
*
30
* @test: KUnit test context
31
*/
32
static void test_vfsuid_root_in_currentns_init_ns(struct kunit *test)
33
{
34
vfsuid_t vfsuid;
35
kuid_t kuid;
36
37
/* Create UID 0 in init namespace */
38
kuid = KUIDT_INIT(0);
39
vfsuid = VFSUIDT_INIT(kuid);
40
41
/* In init namespace, UID 0 should own current namespace */
42
KUNIT_EXPECT_TRUE(test, vfsuid_root_in_currentns(vfsuid));
43
}
44
45
/**
46
* test_vfsuid_root_in_currentns_invalid - Test vfsuid_root_in_currentns with invalid vfsuid
47
*
48
* Verifies that an invalid vfsuid correctly returns false.
49
*
50
* @test: KUnit test context
51
*/
52
static void test_vfsuid_root_in_currentns_invalid(struct kunit *test)
53
{
54
vfsuid_t invalid_vfsuid;
55
56
/* Use the predefined invalid vfsuid */
57
invalid_vfsuid = INVALID_VFSUID;
58
59
/* Invalid vfsuid should return false */
60
KUNIT_EXPECT_FALSE(test, vfsuid_root_in_currentns(invalid_vfsuid));
61
}
62
63
/**
64
* test_vfsuid_root_in_currentns_nonzero - Test vfsuid_root_in_currentns with non-zero UID
65
*
66
* Verifies that a non-zero UID correctly returns false.
67
*
68
* @test: KUnit test context
69
*/
70
static void test_vfsuid_root_in_currentns_nonzero(struct kunit *test)
71
{
72
vfsuid_t vfsuid;
73
kuid_t kuid;
74
75
/* Create a non-zero UID */
76
kuid = KUIDT_INIT(1000);
77
vfsuid = VFSUIDT_INIT(kuid);
78
79
/* Non-zero UID should return false */
80
KUNIT_EXPECT_FALSE(test, vfsuid_root_in_currentns(vfsuid));
81
}
82
83
/**
84
* test_kuid_root_in_ns_init_ns_uid0 - Test kuid_root_in_ns with init namespace and UID 0
85
*
86
* Verifies that kuid_root_in_ns correctly identifies UID 0 in init namespace.
87
* This tests the core namespace traversal logic. In init namespace, UID 0
88
* maps to itself, so it should own the namespace.
89
*
90
* @test: KUnit test context
91
*/
92
static void test_kuid_root_in_ns_init_ns_uid0(struct kunit *test)
93
{
94
kuid_t kuid;
95
struct user_namespace *init_ns;
96
97
kuid = KUIDT_INIT(0);
98
init_ns = &init_user_ns;
99
100
/* UID 0 should own init namespace */
101
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(kuid, init_ns));
102
}
103
104
/**
105
* test_kuid_root_in_ns_init_ns_nonzero - Test kuid_root_in_ns with init namespace and non-zero UID
106
*
107
* Verifies that kuid_root_in_ns correctly rejects non-zero UIDs in init namespace.
108
* Only UID 0 should own a namespace.
109
*
110
* @test: KUnit test context
111
*/
112
static void test_kuid_root_in_ns_init_ns_nonzero(struct kunit *test)
113
{
114
kuid_t kuid;
115
struct user_namespace *init_ns;
116
117
kuid = KUIDT_INIT(1000);
118
init_ns = &init_user_ns;
119
120
/* Non-zero UID should not own namespace */
121
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(kuid, init_ns));
122
}
123
124
/**
125
* create_test_user_ns_with_mapping - Create a mock user namespace with UID mapping
126
*
127
* Creates a minimal user namespace structure for testing where uid 0 in the
128
* namespace maps to a specific kuid in the parent namespace.
129
*
130
* @test: KUnit test context
131
* @parent_ns: Parent namespace (typically init_user_ns)
132
* @mapped_kuid: The kuid that uid 0 in this namespace maps to in parent
133
*
134
* Returns: Pointer to allocated namespace, or NULL on failure
135
*/
136
static struct user_namespace *create_test_user_ns_with_mapping(struct kunit *test,
137
struct user_namespace *parent_ns,
138
kuid_t mapped_kuid)
139
{
140
struct user_namespace *ns;
141
struct uid_gid_extent extent;
142
143
/* Allocate a test namespace - use kzalloc to zero all fields */
144
ns = kunit_kzalloc(test, sizeof(*ns), GFP_KERNEL);
145
if (!ns)
146
return NULL;
147
148
/* Initialize basic namespace structure fields */
149
ns->parent = parent_ns;
150
ns->level = parent_ns ? parent_ns->level + 1 : 0;
151
ns->owner = mapped_kuid;
152
ns->group = KGIDT_INIT(0);
153
154
/* Initialize ns_common structure */
155
refcount_set(&ns->ns.__ns_ref, 1);
156
ns->ns.inum = 0; /* Mock inum */
157
158
/* Set up uid mapping: uid 0 in this namespace maps to mapped_kuid in parent
159
* Format: first (uid in ns) : lower_first (kuid in parent) : count
160
* So: uid 0 in ns -> kuid mapped_kuid in parent
161
* This means from_kuid(ns, mapped_kuid) returns 0
162
*/
163
extent.first = 0; /* uid 0 in this namespace */
164
extent.lower_first = __kuid_val(mapped_kuid); /* maps to this kuid in parent */
165
extent.count = 1;
166
167
ns->uid_map.extent[0] = extent;
168
ns->uid_map.nr_extents = 1;
169
170
/* Set up gid mapping: gid 0 maps to gid 0 in parent (simplified) */
171
extent.first = 0;
172
extent.lower_first = 0;
173
extent.count = 1;
174
175
ns->gid_map.extent[0] = extent;
176
ns->gid_map.nr_extents = 1;
177
178
return ns;
179
}
180
181
/**
182
* test_kuid_root_in_ns_with_mapping - Test kuid_root_in_ns with namespace where uid 0
183
* maps to different kuid
184
*
185
* Creates a user namespace where uid 0 maps to kuid 1000 in the parent namespace.
186
* Verifies that kuid_root_in_ns correctly identifies kuid 1000 as owning the namespace.
187
*
188
* Note: kuid_root_in_ns walks up the namespace hierarchy, so it checks the current
189
* namespace first, then parent, then parent's parent, etc. So:
190
* - kuid 1000 owns test_ns because from_kuid(test_ns, 1000) == 0
191
* - kuid 0 also owns test_ns because from_kuid(init_user_ns, 0) == 0
192
* (checked in parent)
193
*
194
* This tests the actual functionality as requested: creating namespaces with
195
* different values for the namespace's uid 0.
196
*
197
* @test: KUnit test context
198
*/
199
static void test_kuid_root_in_ns_with_mapping(struct kunit *test)
200
{
201
struct user_namespace *test_ns;
202
struct user_namespace *parent_ns;
203
kuid_t mapped_kuid, other_kuid;
204
205
parent_ns = &init_user_ns;
206
mapped_kuid = KUIDT_INIT(1000);
207
other_kuid = KUIDT_INIT(2000);
208
209
test_ns = create_test_user_ns_with_mapping(test, parent_ns, mapped_kuid);
210
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_ns);
211
212
/* kuid 1000 should own test_ns because it maps to uid 0 in test_ns */
213
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(mapped_kuid, test_ns));
214
215
/* kuid 0 should also own test_ns (checked via parent init_user_ns) */
216
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), test_ns));
217
218
/* Other kuids should not own test_ns */
219
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(other_kuid, test_ns));
220
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(500), test_ns));
221
}
222
223
/**
224
* test_kuid_root_in_ns_with_different_mappings - Test with multiple namespaces
225
*
226
* Creates multiple user namespaces with different UID mappings to verify
227
* that kuid_root_in_ns correctly distinguishes between namespaces.
228
*
229
* Each namespace maps uid 0 to a different kuid, and we verify that each
230
* kuid only owns its corresponding namespace (plus kuid 0 owns all via
231
* init_user_ns parent).
232
*
233
* @test: KUnit test context
234
*/
235
static void test_kuid_root_in_ns_with_different_mappings(struct kunit *test)
236
{
237
struct user_namespace *ns1, *ns2, *ns3;
238
239
/* Create three independent namespaces, each mapping uid 0 to different kuids */
240
ns1 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(1000));
241
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns1);
242
243
ns2 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(2000));
244
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns2);
245
246
ns3 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(3000));
247
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns3);
248
249
/* Test ns1: kuid 1000 owns it, kuid 0 owns it (via parent), others do not */
250
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns1));
251
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns1));
252
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns1));
253
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns1));
254
255
/* Test ns2: kuid 2000 owns it, kuid 0 owns it (via parent), others do not */
256
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns2));
257
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns2));
258
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns2));
259
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns2));
260
261
/* Test ns3: kuid 3000 owns it, kuid 0 owns it (via parent), others do not */
262
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns3));
263
KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns3));
264
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns3));
265
KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns3));
266
}
267
268
static struct kunit_case commoncap_test_cases[] = {
269
KUNIT_CASE(test_vfsuid_root_in_currentns_init_ns),
270
KUNIT_CASE(test_vfsuid_root_in_currentns_invalid),
271
KUNIT_CASE(test_vfsuid_root_in_currentns_nonzero),
272
KUNIT_CASE(test_kuid_root_in_ns_init_ns_uid0),
273
KUNIT_CASE(test_kuid_root_in_ns_init_ns_nonzero),
274
KUNIT_CASE(test_kuid_root_in_ns_with_mapping),
275
KUNIT_CASE(test_kuid_root_in_ns_with_different_mappings),
276
{}
277
};
278
279
static struct kunit_suite commoncap_test_suite = {
280
.name = "commoncap",
281
.test_cases = commoncap_test_cases,
282
};
283
284
kunit_test_suite(commoncap_test_suite);
285
286
MODULE_LICENSE("GPL");
287
288
#endif /* CONFIG_SECURITY_COMMONCAP_KUNIT_TEST */
289
290