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