Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 */
32static 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 */
52static 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 */
70static 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 */
92static 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 */
112static 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 */
136static 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 */
199static 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 */
235static 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
268static 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
279static struct kunit_suite commoncap_test_suite = {
280 .name = "commoncap",
281 .test_cases = commoncap_test_cases,
282};
283
284kunit_test_suite(commoncap_test_suite);
285
286MODULE_LICENSE("GPL");
287
288#endif /* CONFIG_SECURITY_COMMONCAP_KUNIT_TEST */