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