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