// SPDX-License-Identifier: GPL-2.0-or-later1/*2* KUnit tests for commoncap.c security functions3*4* Tests for security-critical functions in the capability subsystem,5* particularly namespace-related capability checks.6*/78#include <kunit/test.h>9#include <linux/user_namespace.h>10#include <linux/uidgid.h>11#include <linux/cred.h>12#include <linux/mnt_idmapping.h>13#include <linux/module.h>14#include <linux/slab.h>15#include <linux/refcount.h>1617#ifdef CONFIG_SECURITY_COMMONCAP_KUNIT_TEST1819/* Functions are static in commoncap.c, but we can call them since we're20* included in the same compilation unit when tests are enabled.21*/2223/**24* test_vfsuid_root_in_currentns_init_ns - Test vfsuid_root_in_currentns with init ns25*26* Verifies that UID 0 in the init namespace correctly owns the current27* namespace when running in init_user_ns.28*29* @test: KUnit test context30*/31static void test_vfsuid_root_in_currentns_init_ns(struct kunit *test)32{33vfsuid_t vfsuid;34kuid_t kuid;3536/* Create UID 0 in init namespace */37kuid = KUIDT_INIT(0);38vfsuid = VFSUIDT_INIT(kuid);3940/* In init namespace, UID 0 should own current namespace */41KUNIT_EXPECT_TRUE(test, vfsuid_root_in_currentns(vfsuid));42}4344/**45* test_vfsuid_root_in_currentns_invalid - Test vfsuid_root_in_currentns with invalid vfsuid46*47* Verifies that an invalid vfsuid correctly returns false.48*49* @test: KUnit test context50*/51static void test_vfsuid_root_in_currentns_invalid(struct kunit *test)52{53vfsuid_t invalid_vfsuid;5455/* Use the predefined invalid vfsuid */56invalid_vfsuid = INVALID_VFSUID;5758/* Invalid vfsuid should return false */59KUNIT_EXPECT_FALSE(test, vfsuid_root_in_currentns(invalid_vfsuid));60}6162/**63* test_vfsuid_root_in_currentns_nonzero - Test vfsuid_root_in_currentns with non-zero UID64*65* Verifies that a non-zero UID correctly returns false.66*67* @test: KUnit test context68*/69static void test_vfsuid_root_in_currentns_nonzero(struct kunit *test)70{71vfsuid_t vfsuid;72kuid_t kuid;7374/* Create a non-zero UID */75kuid = KUIDT_INIT(1000);76vfsuid = VFSUIDT_INIT(kuid);7778/* Non-zero UID should return false */79KUNIT_EXPECT_FALSE(test, vfsuid_root_in_currentns(vfsuid));80}8182/**83* test_kuid_root_in_ns_init_ns_uid0 - Test kuid_root_in_ns with init namespace and UID 084*85* Verifies that kuid_root_in_ns correctly identifies UID 0 in init namespace.86* This tests the core namespace traversal logic. In init namespace, UID 087* maps to itself, so it should own the namespace.88*89* @test: KUnit test context90*/91static void test_kuid_root_in_ns_init_ns_uid0(struct kunit *test)92{93kuid_t kuid;94struct user_namespace *init_ns;9596kuid = KUIDT_INIT(0);97init_ns = &init_user_ns;9899/* UID 0 should own init namespace */100KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(kuid, init_ns));101}102103/**104* test_kuid_root_in_ns_init_ns_nonzero - Test kuid_root_in_ns with init namespace and non-zero UID105*106* Verifies that kuid_root_in_ns correctly rejects non-zero UIDs in init namespace.107* Only UID 0 should own a namespace.108*109* @test: KUnit test context110*/111static void test_kuid_root_in_ns_init_ns_nonzero(struct kunit *test)112{113kuid_t kuid;114struct user_namespace *init_ns;115116kuid = KUIDT_INIT(1000);117init_ns = &init_user_ns;118119/* Non-zero UID should not own namespace */120KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(kuid, init_ns));121}122123/**124* create_test_user_ns_with_mapping - Create a mock user namespace with UID mapping125*126* Creates a minimal user namespace structure for testing where uid 0 in the127* namespace maps to a specific kuid in the parent namespace.128*129* @test: KUnit test context130* @parent_ns: Parent namespace (typically init_user_ns)131* @mapped_kuid: The kuid that uid 0 in this namespace maps to in parent132*133* Returns: Pointer to allocated namespace, or NULL on failure134*/135static struct user_namespace *create_test_user_ns_with_mapping(struct kunit *test,136struct user_namespace *parent_ns,137kuid_t mapped_kuid)138{139struct user_namespace *ns;140struct uid_gid_extent extent;141142/* Allocate a test namespace - use kzalloc to zero all fields */143ns = kunit_kzalloc(test, sizeof(*ns), GFP_KERNEL);144if (!ns)145return NULL;146147/* Initialize basic namespace structure fields */148ns->parent = parent_ns;149ns->level = parent_ns ? parent_ns->level + 1 : 0;150ns->owner = mapped_kuid;151ns->group = KGIDT_INIT(0);152153/* Initialize ns_common structure */154refcount_set(&ns->ns.__ns_ref, 1);155ns->ns.inum = 0; /* Mock inum */156157/* Set up uid mapping: uid 0 in this namespace maps to mapped_kuid in parent158* Format: first (uid in ns) : lower_first (kuid in parent) : count159* So: uid 0 in ns -> kuid mapped_kuid in parent160* This means from_kuid(ns, mapped_kuid) returns 0161*/162extent.first = 0; /* uid 0 in this namespace */163extent.lower_first = __kuid_val(mapped_kuid); /* maps to this kuid in parent */164extent.count = 1;165166ns->uid_map.extent[0] = extent;167ns->uid_map.nr_extents = 1;168169/* Set up gid mapping: gid 0 maps to gid 0 in parent (simplified) */170extent.first = 0;171extent.lower_first = 0;172extent.count = 1;173174ns->gid_map.extent[0] = extent;175ns->gid_map.nr_extents = 1;176177return ns;178}179180/**181* test_kuid_root_in_ns_with_mapping - Test kuid_root_in_ns with namespace where uid 0182* maps to different kuid183*184* Creates a user namespace where uid 0 maps to kuid 1000 in the parent namespace.185* Verifies that kuid_root_in_ns correctly identifies kuid 1000 as owning the namespace.186*187* Note: kuid_root_in_ns walks up the namespace hierarchy, so it checks the current188* namespace first, then parent, then parent's parent, etc. So:189* - kuid 1000 owns test_ns because from_kuid(test_ns, 1000) == 0190* - kuid 0 also owns test_ns because from_kuid(init_user_ns, 0) == 0191* (checked in parent)192*193* This tests the actual functionality as requested: creating namespaces with194* different values for the namespace's uid 0.195*196* @test: KUnit test context197*/198static void test_kuid_root_in_ns_with_mapping(struct kunit *test)199{200struct user_namespace *test_ns;201struct user_namespace *parent_ns;202kuid_t mapped_kuid, other_kuid;203204parent_ns = &init_user_ns;205mapped_kuid = KUIDT_INIT(1000);206other_kuid = KUIDT_INIT(2000);207208test_ns = create_test_user_ns_with_mapping(test, parent_ns, mapped_kuid);209KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_ns);210211/* kuid 1000 should own test_ns because it maps to uid 0 in test_ns */212KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(mapped_kuid, test_ns));213214/* kuid 0 should also own test_ns (checked via parent init_user_ns) */215KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), test_ns));216217/* Other kuids should not own test_ns */218KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(other_kuid, test_ns));219KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(500), test_ns));220}221222/**223* test_kuid_root_in_ns_with_different_mappings - Test with multiple namespaces224*225* Creates multiple user namespaces with different UID mappings to verify226* that kuid_root_in_ns correctly distinguishes between namespaces.227*228* Each namespace maps uid 0 to a different kuid, and we verify that each229* kuid only owns its corresponding namespace (plus kuid 0 owns all via230* init_user_ns parent).231*232* @test: KUnit test context233*/234static void test_kuid_root_in_ns_with_different_mappings(struct kunit *test)235{236struct user_namespace *ns1, *ns2, *ns3;237238/* Create three independent namespaces, each mapping uid 0 to different kuids */239ns1 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(1000));240KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns1);241242ns2 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(2000));243KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns2);244245ns3 = create_test_user_ns_with_mapping(test, &init_user_ns, KUIDT_INIT(3000));246KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ns3);247248/* Test ns1: kuid 1000 owns it, kuid 0 owns it (via parent), others do not */249KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns1));250KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns1));251KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns1));252KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns1));253254/* Test ns2: kuid 2000 owns it, kuid 0 owns it (via parent), others do not */255KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns2));256KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns2));257KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns2));258KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns2));259260/* Test ns3: kuid 3000 owns it, kuid 0 owns it (via parent), others do not */261KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(3000), ns3));262KUNIT_EXPECT_TRUE(test, kuid_root_in_ns(KUIDT_INIT(0), ns3));263KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(1000), ns3));264KUNIT_EXPECT_FALSE(test, kuid_root_in_ns(KUIDT_INIT(2000), ns3));265}266267static struct kunit_case commoncap_test_cases[] = {268KUNIT_CASE(test_vfsuid_root_in_currentns_init_ns),269KUNIT_CASE(test_vfsuid_root_in_currentns_invalid),270KUNIT_CASE(test_vfsuid_root_in_currentns_nonzero),271KUNIT_CASE(test_kuid_root_in_ns_init_ns_uid0),272KUNIT_CASE(test_kuid_root_in_ns_init_ns_nonzero),273KUNIT_CASE(test_kuid_root_in_ns_with_mapping),274KUNIT_CASE(test_kuid_root_in_ns_with_different_mappings),275{}276};277278static struct kunit_suite commoncap_test_suite = {279.name = "commoncap",280.test_cases = commoncap_test_cases,281};282283kunit_test_suite(commoncap_test_suite);284285MODULE_LICENSE("GPL");286287#endif /* CONFIG_SECURITY_COMMONCAP_KUNIT_TEST */288289290