From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.218.72 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793225900; b=GIzaQRpbHytK0wcCHxBTkdPF23aw9TX3a59ZWOgIJ0SSdxBeZrO7YTk39jLvwpOLKxhf L7mdMfpjlvulB6OIDzi9Gk8ZikEWRNfCPyOLNpPDU8e1fZMZCQDBHT+bbB4SGWdGxndBO 9QvMT62bRYx72sfqyHSZ7Ui08nnIYQphP+zW9TAX129gcRd4OQeQeoEeqT2UAymdM82tn 7qrKxw0c5xvhUGAAcmMS3ulD73hrPfVw3nJQ260QmqgAUGfrqySbIw/Wkj4v9H+lSQz5Y E44H41zUYSYBXyYwv6Hp7uetBLE2sDAqLp9rO2e41opxOsg/1YkJ39s1Fzb4pa+Qb2w== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793225900; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Received:Date:In-Reply-To: Mime-Version:References:X-Mailer:Message-ID:Subject:From:To:Cc: Content-Type; bh=uR8d+2KzOCc+PCIXuOJ1VzHWTSd8KrcryDy/HkQ7hhE=; b=3xI11YV0OREN4MQ7CgOmy7/T4m4sOHR/gf3g6E/MABtPjypFxG6NUC+DROUHF0n8ccqo CJX6b1JTtvwboNmyTVDV69ZdkqEBH4g+dKcghALHow7HsG+qS9OvvZhZ17aZk9QHCmjBP qJ2yOCgeBVt3F89meJ9BctrABra90Wo9qQ6i6+1PjzZa4msnPCjThSRm9xleidNPdaf90 zFPKuf6vXOKM+kPSOcQNGYCqHoXVRQiIb8YE0nb7PGNSfzPS+ao6cpFogxoFS9a1XdlIO lZsXyMD1F9y7FKhjOAZgD4+m2fx/JaCKm3QpZYCAQGf5Z6QL0b9JtBi2C0Ol9bh7R7A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=google.com; spf=pass smtp.mailfrom=flex--halg.bounces.google.com; dkim=pass header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20260707 header.b=Naryf3Bo; arc=none smtp.remote-ip=209.85.218.72 Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8549F606A333 for ; Wed, 28 Oct 2026 22:18:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 8549F606A333 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--halg.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20260707 header.b=Naryf3Bo Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-c42f98f351eso152804066b.0 for ; Wed, 28 Oct 2026 15:18:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20260707; t=1793225898; x=1793830698; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=uR8d+2KzOCc+PCIXuOJ1VzHWTSd8KrcryDy/HkQ7hhE=; b=Naryf3BoTAgS7QAbA7uYgHtdsAfs7go5S+lar2IQfYFDv+/JIJ9a7cszrFOIZyL6tf 5oHhU63oYx1IVKr5VVmiPISjhp7vO2E584Gxm/ZlmYR4cR3jO3py+08IctQz99Ceq0b5 knm4LT9KQ5d6cLNyJdOeTTcqHGZpa2l1BhNVnLLUm+zVb547MxbQMXAjvcxSC4KBVe74 3q/OpGcIrLthHI11T5bhowkmTxjrPp0t7IOcoE0BuEFX68r9dguAB6apV5AbAu6PtQ9C 1Lso0n8Fq2kIvChHX0JFsJ+iuIEJ6dHrONLyb9LF8ShWotR9Bs9jZoyKrJyQuit9FpEP A1zA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225898; x=1793830698; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=uR8d+2KzOCc+PCIXuOJ1VzHWTSd8KrcryDy/HkQ7hhE=; b=KZ0Ejk5iMQcRkHysVMaIcxiJYu/oeetr466xfSFI9N+K3NrwNd/dSz/h1RQrmBGMaq rEPOWHi2ZbdzHb+7cWsK1xbxzwNr8Fb8iJrSx7K0H3oZxHOykK+7IYqHJ8aidGWqldEf Bo4IbOfb1mnupoKCm/ArDsrdAwkjMR8hATmIIUu4FQY/GkyXFLuulSLiMw+tNb7Tm9bK MgvEVJz66DbAdA0MgXxo5KkTCRV1Bh3rruFCbsdRlJgCeTHjF0jqClDNm4aNAujvalA+ 8HVbAobzU8nRz02ShcNbbeahpj2J3u3/ATTMwBA+gJMiue7qDP1yFY/31BolzHnEi/9B mEKw== X-Forwarded-Encrypted: i=1; AKwUvBzvpCuA2oeNWYhLkypRDpACj3c0ch/Kj0U9xEbFOVUpVUqew8F8J2tikoe5nn2VmhfR82sHoWlwYGyBRQZ1Ri0=@vger.kernel.org X-Gm-Message-State: AFq9FYIDrzdZOsGYS4CUnCvEuGFjytTeXhZSsY6nitGKUUXlRSiONs+A 70LHGBe1aJk5IN7wVMGED76FKZ3IJwLoTFXr/ZRvQZGiEfK2Tg4hU+AZadPdqwlulbzLkpv8oA= = X-Received: from ejckx26.prod.google.com ([2002:a17:907:775a:b0:c31:9629:c57e]) (user=halg job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:868c:b0:c26:1648:a06b with SMTP id a640c23a62f3a-c49bdf5c1e6mr326815366b.38.1793225897748; Wed, 28 Oct 2026 15:18:17 -0700 (PDT) Date: Wed, 28 Oct 2026 22:17:04 +0000 In-Reply-To: <20261028221705.3915340-1-halg@google.com> X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list Mime-Version: 1.0 References: <20261028221705.3915340-1-halg@google.com> X-Mailer: git-send-email 2.56.0.313.g2479322e68-goog Message-ID: <20261028221705.3915340-8-halg@google.com> Subject: [PATCH 7/8] selftests/capabilities: add clone3() tests for CLONE_NEWUSER_BSET From: "Hallgrimur H. Gunnarsson" To: Christian Brauner , Alexander Viro , Paul Moore , Serge Hallyn , Kees Cook , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Jan Kara , James Morris , Simon Horman , Jonathan Corbet , Shuah Khan , Randy Dunlap , Jann Horn , "=?UTF-8?q?G=C3=BCnther=20Noack?=" , KP Singh , Jonathan Calmels , Casey Schaufler , linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, containers@lists.linux.dev, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Hallgrimur H. Gunnarsson" Content-Type: text/plain; charset="UTF-8" Add tests to userns_bounding_set_test to verify per-namespace capability bounding via CLONE_NEWUSER_BSET. Signed-off-by: Hallgrimur H. Gunnarsson --- .../capabilities/userns_bounding_set_test.c | 146 ++++++++++++++++++ .../selftests/clone3/clone3_selftests.h | 1 + 2 files changed, 147 insertions(+) diff --git a/tools/testing/selftests/capabilities/userns_bounding_set_test.c b/tools/testing/selftests/capabilities/userns_bounding_set_test.c index 798758e0705d..140c12e16e9e 100644 --- a/tools/testing/selftests/capabilities/userns_bounding_set_test.c +++ b/tools/testing/selftests/capabilities/userns_bounding_set_test.c @@ -417,4 +417,150 @@ TEST_F(userns_bset, parent_owner_cap_restricted) EXPECT_EQ(EPERM, run_parent_owner_setns(restricted_mask)); } +/* + * Verify that CLONE_NEWUSER_BSET restricts capabilities in the child user + * namespace even when the global sysctl allows all capabilities. + */ +TEST_F(userns_bset, clone3_bset_restriction) +{ + struct __clone_args args = { + .flags = CLONE_NEWUSER | CLONE_NEWUSER_BSET, + .exit_signal = SIGCHLD, + .cap_bset = cap_full_set & ~(1ULL << CAP_NET_ADMIN), + }; + pid_t pid; + int status; + + ASSERT_EQ(0, write_sysctl_caps(cap_full_set)); + + pid = sys_clone3(&args, sizeof(args)); + ASSERT_GE(pid, 0); + + if (pid == 0) { + if (!cap_raised(CAP_SYS_ADMIN)) + _exit(1); + if (!cap_dropped(CAP_NET_ADMIN)) + _exit(2); + _exit(0); + } + + ASSERT_EQ(pid, waitpid(pid, &status, 0)); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); +} + +/* + * Verify that passing cap_bset = 0 with CLONE_NEWUSER_BSET drops all + * capabilities in the new user namespace. + */ +TEST_F(userns_bset, clone3_bset_empty) +{ + struct __clone_args args = { + .flags = CLONE_NEWUSER | CLONE_NEWUSER_BSET, + .exit_signal = SIGCHLD, + .cap_bset = 0, + }; + pid_t pid; + int status; + + ASSERT_EQ(0, write_sysctl_caps(cap_full_set)); + + pid = sys_clone3(&args, sizeof(args)); + ASSERT_GE(pid, 0); + + if (pid == 0) { + if (!cap_dropped(CAP_SYS_ADMIN)) + _exit(1); + if (!cap_dropped(CAP_NET_ADMIN)) + _exit(2); + _exit(0); + } + + ASSERT_EQ(pid, waitpid(pid, &status, 0)); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); +} + +/* + * Verify that an unprivileged caller cannot use CLONE_NEWUSER_BSET to bypass + * the global sysctl ceiling. + */ +TEST_F(userns_bset, clone3_bset_cannot_bypass_sysctl) +{ + uint64_t restricted_mask = cap_full_set & ~(1ULL << CAP_NET_ADMIN); + pid_t pid; + int status; + + ASSERT_EQ(0, write_sysctl_caps(restricted_mask)); + + pid = fork(); + ASSERT_GE(pid, 0); + + if (pid == 0) { + struct __clone_args args = { + .flags = CLONE_NEWUSER | CLONE_NEWUSER_BSET, + .exit_signal = SIGCHLD, + .cap_bset = cap_full_set, + }; + int child_status; + pid_t child; + + if (drop_privileges() != 0) + _exit(1); + + child = sys_clone3(&args, sizeof(args)); + if (child < 0) + _exit(2); + + if (child == 0) { + if (!cap_raised(CAP_SYS_ADMIN)) + _exit(3); + if (!cap_dropped(CAP_NET_ADMIN)) + _exit(4); + _exit(0); + } + + if (waitpid(child, &child_status, 0) != child || + !WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) + _exit(5); + + _exit(0); + } + + ASSERT_EQ(pid, waitpid(pid, &status, 0)); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); +} + +/* + * Verify clone3() argument validation for CLONE_NEWUSER_BSET. + */ +TEST_F(userns_bset, clone3_bset_invalid_args) +{ + struct __clone_args args; + + /* CLONE_NEWUSER_BSET without CLONE_NEWUSER must fail */ + memset(&args, 0, sizeof(args)); + args.flags = CLONE_NEWUSER_BSET; + args.exit_signal = SIGCHLD; + args.cap_bset = cap_full_set; + EXPECT_EQ(-1, sys_clone3(&args, sizeof(args))); + EXPECT_EQ(EINVAL, errno); + + /* Non-zero cap_bset without CLONE_NEWUSER_BSET must fail */ + memset(&args, 0, sizeof(args)); + args.flags = CLONE_NEWUSER; + args.exit_signal = SIGCHLD; + args.cap_bset = cap_full_set; + EXPECT_EQ(-1, sys_clone3(&args, sizeof(args))); + EXPECT_EQ(EINVAL, errno); + + /* CLONE_NEWUSER_BSET with struct size < VER3 must fail */ + memset(&args, 0, sizeof(args)); + args.flags = CLONE_NEWUSER | CLONE_NEWUSER_BSET; + args.exit_signal = SIGCHLD; + EXPECT_EQ(-1, sys_clone3(&args, CLONE_ARGS_SIZE_VER2)); + EXPECT_EQ(EINVAL, errno); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/clone3/clone3_selftests.h b/tools/testing/selftests/clone3/clone3_selftests.h index a0593e8950f0..2145d14956e5 100644 --- a/tools/testing/selftests/clone3/clone3_selftests.h +++ b/tools/testing/selftests/clone3/clone3_selftests.h @@ -31,6 +31,7 @@ struct __clone_args { __aligned_u64 set_tid; __aligned_u64 set_tid_size; __aligned_u64 cgroup; + __aligned_u64 cap_bset; }; static pid_t sys_clone3(struct __clone_args *args, size_t size) -- 2.56.0.313.g2479322e68-goog