From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=83.166.143.168 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794342508; b=Ceo4hLrPUOgOdqaUEC4XFx6tTKyWbC4/Qn2plDSpGq8SkfijsO5khS4kZwiTwEd2nskK d2SNiBNB4Z9vYe0ISsE72FxGyWNfUfQPfKPhjuQXBCBlYD2pPghIJXXwlt19GwObdGAek rvg2f8kN176wuiblxGIoSzfaR0ddOToEp1Gv7Hy6PY6sdghFOfObLN8vh0iqSAGi2fogV 2De8QUvDwrj3ESwBBvAvLmPK2YTdIV2pJfUbTeQ3/u39OS6G4ZmUVTwSxew83XYbR4aJn 7m3RtPV55W2oDdZvIc/6WDVMM4WrWX9Tnt22z6qen/kKH8vaUh0NZrTnsqA8ochvnKw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794342508; h=DMARC-Filter:Received:DKIM-Signature:Received:From:To:Cc:Subject: Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Type: Content-Transfer-Encoding:X-Infomaniak-Routing; bh=VC/yA8LuQFAXhdzNtcFAIsxI36LebW6JYbNmaan7FZU=; b=zRt4M3oaa+yoqpnnC3LKtXMBYT9IXc/6tL8iMpvHkomfLN3G77uG0rfSF9PnXKQe/j8G JUZSUOw1lAfjbjnWJt+K1BX+SAl5DCuxKnRQI5EB3U9mI20Di+GlSTnE1TM5Eix6p8vgO 2iXdjMEKuMO8zOilHGAGTRZxYX+7Kg/uGt8+8YRWCAzvtPlw7XRPdHCdQZ78vopc1JnxM oRAR9CPryb6RZTGXcZT8mOXw+PduE3SVrdWRqdOfKsL6ql7xePTc8Fo4pk7T4kf1p4hho 3wcFGA/ZeQIpNmvjYcLk0Ddk68iEF7QmojMRUr3XvFS6XyUeS/s4rA4dANfl0W/p/+g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none header.from=digikod.net; spf=pass smtp.mailfrom=digikod.net; dkim=pass header.d=digikod.net header.i=@digikod.net header.a=rsa-sha256 header.s=20191114 header.b=A+Ugosja; arc=none smtp.remote-ip=83.166.143.168 Received: from smtp-8fa8.mail.infomaniak.ch (smtp-8fa8.mail.infomaniak.ch [83.166.143.168]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 782AF606BA57 for ; Tue, 10 Nov 2026 20:28:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 782AF606BA57 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=digikod.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.a=rsa-sha256 header.s=20191114 header.b=A+Ugosja Received: from smtp-3-0000.mail.infomaniak.ch (unknown [IPv6:2001:1600:4:17::246b]) by smtp-3-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4jPJBX2l52zH03; Tue, 10 Nov 2026 21:28:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=digikod.net; s=20191114; t=1794342500; bh=VC/yA8LuQFAXhdzNtcFAIsxI36LebW6JYbNmaan7FZU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=A+Ugosja4GAF8/VgKl3H3LDZlGbWeNoudrRHsjeiE9gDTWy69vSexuBLIv8X8hiZ7 k8y9O4Sz26di+XVdJWTBgNM4j0XYTcxAnQGTOhR0xF4/eCGqUKMXfzHvsQg01t9Yw7 4evPLA+RC2a344MuyHazXj8/Wasra9MhUHYco9Ig= Received: from unknown by smtp-3-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4jPJBW05gvzxdn; Tue, 10 Nov 2026 21:28:18 +0100 (CET) From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= To: James Morris , Paul Moore , Serge Hallyn Cc: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Ada Smith , Christian Brauner , =?UTF-8?q?G=C3=BCnther=20Noack?= , John Johansen , KP Singh , Matt Bobrowski , Stephen Smalley , apparmor@lists.ubuntu.com, bpf@vger.kernel.org, kernel-team@cloudflare.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@vger.kernel.org Subject: [PATCH 2/2] selftests/landlock: Test PR_SET_SECUREBITS mediation Date: Tue, 10 Nov 2026 21:28:07 +0100 Message-ID: <20261110202811.2409395-3-mic@digikod.net> In-Reply-To: <20261110202811.2409395-1-mic@digikod.net> References: <20261110202811.2409395-1-mic@digikod.net> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Infomaniak-Routing: alpha The preceding commoncap fix routes the CAP_SETPCAP check for privileged PR_SET_SECUREBITS requests through the ordinary capable hooks. Add a focused Landlock regression test for this path. Keep CAP_SETPCAP effective to isolate Landlock mediation and run the audit case in a child domain. A privileged change returns EPERM and emits an exact CAP_SETPCAP record, then an unprivileged-only change succeeds. After the child exits, require the domain deallocation record to report exactly one denial; this proves that the second operation did not create a hidden denial without relying on an asynchronous no-record timeout. The existing check-exec securebits fixture already covers commoncap's privileged, unprivileged, locked, and user-namespace semantics. Without the preceding fix, this Landlock audit test fails. Cc: Christian Brauner Cc: Günther Noack Cc: Paul Moore Cc: Serge Hallyn Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/cap_test.c | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tools/testing/selftests/landlock/cap_test.c b/tools/testing/selftests/landlock/cap_test.c index c79bb42c6282..741567c5ab41 100644 --- a/tools/testing/selftests/landlock/cap_test.c +++ b/tools/testing/selftests/landlock/cap_test.c @@ -1275,6 +1275,75 @@ TEST_F(cap_audit, denied) EXPECT_EQ(0, records.domain); } +/* + * A privileged denial allocates the domain ID. The following unprivileged-only + * change must not create a hidden Landlock denial, so the domain's deallocation + * record must report exactly one denial. + */ +TEST_F(cap_audit, securebits) +{ + const unsigned long unpriv = SECBIT_EXEC_RESTRICT_FILE | + SECBIT_EXEC_RESTRICT_FILE_LOCKED; + __u64 *domain_id, deallocated_dom = 0; + unsigned long bits; + int err, ruleset_fd, status; + pid_t child; + + domain_id = mmap(NULL, sizeof(*domain_id), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, domain_id); + *domain_id = 0; + + ruleset_fd = create_cap_ruleset(); + ASSERT_LE(0, ruleset_fd); + /* Allow the child to replace the audit filter before exiting. */ + ASSERT_EQ(0, add_cap_rule(ruleset_fd, CAP_AUDIT_CONTROL)); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + set_cap(_metadata, CAP_SETPCAP); + bits = prctl(PR_GET_SECUREBITS); + EXPECT_EQ(-1, prctl(PR_SET_SECUREBITS, + bits | SECBIT_NO_CAP_AMBIENT_RAISE)); + EXPECT_EQ(EPERM, errno); + + EXPECT_EQ(0, matches_log_cap(self->audit_fd, CAP_SETPCAP)); + EXPECT_EQ(0, matches_log_domain_allocated(self->audit_fd, + getpid(), domain_id)); + + EXPECT_EQ(0, prctl(PR_SET_SECUREBITS, bits | unpriv)); + clear_cap(_metadata, CAP_SETPCAP); + + /* Receive the asynchronous domain deallocation record. */ + set_cap(_metadata, CAP_AUDIT_CONTROL); + EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE)); + EXPECT_EQ(0, + audit_filter_exe(self->audit_fd, &self->audit_filter, + AUDIT_DEL_RULE)); + clear_cap(_metadata, CAP_AUDIT_CONTROL); + + _exit(_metadata->exit_code); + return; + } + + ASSERT_EQ(child, waitpid(child, &status, 0)); + if (WIFSIGNALED(status) || !WIFEXITED(status) || + WEXITSTATUS(status) != EXIT_SUCCESS) + _metadata->exit_code = KSFT_FAIL; + + EXPECT_NE(0, *domain_id); + err = matches_log_domain_deallocated(self->audit_fd, 1, *domain_id, + &deallocated_dom); + EXPECT_EQ(0, err); + EXPECT_EQ(*domain_id, deallocated_dom); + EXPECT_EQ(0, munmap(domain_id, sizeof(*domain_id))); + EXPECT_EQ(0, close(ruleset_fd)); +} + /* * Denials in the capset and mmap_addr paths are audited like capable hook * denials. The vm_enough_memory hook only withholds the admin reserve, with -- 2.56.0