From nobody Wed Dec 17 12:27:25 2025 Received: from smtp-bc0d.mail.infomaniak.ch (smtp-bc0d.mail.infomaniak.ch [45.157.188.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3087519F43A for ; Tue, 18 Mar 2025 16:15:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.157.188.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742314508; cv=none; b=VjCDH7WzJLfJ/oYOu2Vl+iKSuZSZIKW+qQyPBTKw/9hnhFKQJgxabYF29nH5zcer/2or7Nh0U5MNSvIrrlgatwPOMVg4P4P7ohpEdZViRomZJRONtTsAVtWDBzaxu9499U4l1C/eo3uzh75+WPRN0FAcOBfq0X2LNkxVzhcjK04= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742314508; c=relaxed/simple; bh=0qP5GqU6hxuBeipAIyWwTfxwmBhEYf4pOhwFrWR3+XI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=U/XF10x1uJ/angOjUEM6wJ0p1IJQBZr9fpu1MvJrusFQ/0x9wLJtAh0JAVSNk4t/MY/hGq8cTf8rz7ATtUTHdocSwdL00Oy10wuDhH50XH3vSu8dN3VWgA6Ebq9lp198/J7UlyTw/TpXi2azgLB+WlSX05FHR6PjuWwVVWTJrBE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net; spf=pass smtp.mailfrom=digikod.net; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b=HWN0BOVA; arc=none smtp.client-ip=45.157.188.13 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.b="HWN0BOVA" Received: from smtp-4-0001.mail.infomaniak.ch (smtp-4-0001.mail.infomaniak.ch [10.7.10.108]) by smtp-4-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4ZHH4421P9zLJx; Tue, 18 Mar 2025 17:15:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=digikod.net; s=20191114; t=1742314500; bh=c7lbP1EQsl0DIIQZtCoH5DqcB56sY5n99Bx2F2IcBNo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HWN0BOVAcXwF63j7W5D86BoY5uwFDnbZUuid85Sfcj3FLLI0sMmGbEEF0aLui1QQd 85Es3LH1fczTdZF0U5srAyiKMxC5/zo9VmvrfhTYYywWKU04SwqEYFNmEagpIjsMvE RyYqITeV2AYVSjrOidM3wj9K5lwAAsGxVpezuZek= Received: from unknown by smtp-4-0001.mail.infomaniak.ch (Postfix) with ESMTPA id 4ZHH434bfBzVqL; Tue, 18 Mar 2025 17:14:59 +0100 (CET) From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= To: Dan Carpenter , =?UTF-8?q?G=C3=BCnther=20Noack?= , Paul Moore , "Serge E . Hallyn" Cc: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Christian Brauner , Jann Horn , Jeff Xu , Kees Cook , Mikhail Ivanov , Tahera Fahimi , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH v2 7/8] selftests/landlock: Add a new test for setuid() Date: Tue, 18 Mar 2025 17:14:42 +0100 Message-ID: <20250318161443.279194-8-mic@digikod.net> In-Reply-To: <20250318161443.279194-1-mic@digikod.net> References: <20250318161443.279194-1-mic@digikod.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Infomaniak-Routing: alpha The new signal_scoping_thread_setuid tests check that the libc's setuid() function works as expected even when a thread is sandboxed with scoped signal restrictions. Before the signal scoping fix, this test would have failed with the setuid() call: [pid 65] getpid() =3D 65 [pid 65] tgkill(65, 66, SIGRT_1) =3D -1 EPERM (Operation not permi= tted) [pid 65] futex(0x40a66cdc, FUTEX_WAKE_PRIVATE, 1) =3D 0 [pid 65] setuid(1001) =3D 0 After the fix, tgkill(2) is successfully leveraged to synchronize credentials update across threads: [pid 65] getpid() =3D 65 [pid 65] tgkill(65, 66, SIGRT_1) =3D 0 [pid 66] <... read resumed>0x40a65eb7, 1) =3D ? ERESTARTSYS (To be res= tarted if SA_RESTART is set) [pid 66] --- SIGRT_1 {si_signo=3DSIGRT_1, si_code=3DSI_TKILL, si_pid= =3D65, si_uid=3D1000} --- [pid 66] getpid() =3D 65 [pid 66] setuid(1001) =3D 0 [pid 66] futex(0x40a66cdc, FUTEX_WAKE_PRIVATE, 1) =3D 0 [pid 66] rt_sigreturn({mask=3D[]}) =3D 0 [pid 66] read(3, [pid 65] setuid(1001) =3D 0 Test coverage for security/landlock is 92.9% of 1053 lines according to gcc/gcov-14. Fixes: c8994965013e ("selftests/landlock: Test signal scoping for threads") Cc: G=C3=BCnther Noack Cc: Tahera Fahimi Cc: stable@vger.kernel.org Signed-off-by: Micka=C3=ABl Sala=C3=BCn Link: https://lore.kernel.org/r/20250318161443.279194-8-mic@digikod.net --- Changes since v1: - New patch. --- tools/testing/selftests/landlock/common.h | 1 + .../selftests/landlock/scoped_signal_test.c | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/self= tests/landlock/common.h index 6064c9ac0532..076a9a625c98 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -41,6 +41,7 @@ static void _init_caps(struct __test_metadata *const _met= adata, bool drop_all) CAP_MKNOD, CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, + CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_CHROOT, /* clang-format on */ diff --git a/tools/testing/selftests/landlock/scoped_signal_test.c b/tools/= testing/selftests/landlock/scoped_signal_test.c index d313cb626225..d8bf33417619 100644 --- a/tools/testing/selftests/landlock/scoped_signal_test.c +++ b/tools/testing/selftests/landlock/scoped_signal_test.c @@ -253,6 +253,7 @@ enum thread_return { THREAD_INVALID =3D 0, THREAD_SUCCESS =3D 1, THREAD_ERROR =3D 2, + THREAD_TEST_FAILED =3D 3, }; =20 static void *thread_sync(void *arg) @@ -316,6 +317,64 @@ TEST(signal_scoping_thread_after) EXPECT_EQ(0, close(thread_pipe[1])); } =20 +struct thread_setuid_args { + int pipe_read, new_uid; +}; + +void *thread_setuid(void *ptr) +{ + const struct thread_setuid_args *arg =3D ptr; + char buf; + + if (read(arg->pipe_read, &buf, 1) !=3D 1) + return (void *)THREAD_ERROR; + + /* libc's setuid() should update all thread's credentials. */ + if (getuid() !=3D arg->new_uid) + return (void *)THREAD_TEST_FAILED; + + return (void *)THREAD_SUCCESS; +} + +TEST(signal_scoping_thread_setuid) +{ + struct thread_setuid_args arg; + pthread_t no_sandbox_thread; + enum thread_return ret =3D THREAD_INVALID; + int pipe_parent[2]; + int prev_uid; + + disable_caps(_metadata); + + /* This test does not need to be run as root. */ + prev_uid =3D getuid(); + arg.new_uid =3D prev_uid + 1; + EXPECT_LT(0, arg.new_uid); + + ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); + arg.pipe_read =3D pipe_parent[0]; + + /* Capabilities must be set before creating a new thread. */ + set_cap(_metadata, CAP_SETUID); + ASSERT_EQ(0, pthread_create(&no_sandbox_thread, NULL, thread_setuid, + &arg)); + + /* Enforces restriction after creating the thread. */ + create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); + + EXPECT_NE(arg.new_uid, getuid()); + EXPECT_EQ(0, setuid(arg.new_uid)); + EXPECT_EQ(arg.new_uid, getuid()); + EXPECT_EQ(1, write(pipe_parent[1], ".", 1)); + + EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret)); + EXPECT_EQ(THREAD_SUCCESS, ret); + + clear_cap(_metadata, CAP_SETUID); + EXPECT_EQ(0, close(pipe_parent[0])); + EXPECT_EQ(0, close(pipe_parent[1])); +} + const short backlog =3D 10; =20 static volatile sig_atomic_t signal_received; --=20 2.48.1