Skip to content

Commit bb6f4db

Browse files
committed
selftests/landlock: Fix capability for net_test
CAP_NET_ADMIN allows to configure network interfaces, not CAP_SYS_ADMIN which only allows to call unshare(2). Without this change, running network tests as a non-root user but with all capabilities would fail at the setup_loopback() step with "RTNETLINK answers: Operation not permitted". The issue is only visible when running tests with non-root users (i.e. only relying on ambient capabilities). Indeed, when configuring the network interface, the "ip" command is called, which may lead to the special handling of capabilities for the root user by execve(2). If root is the caller, then the inherited, permitted and effective capabilities are all reset, which then includes CAP_NET_ADMIN. However, if a non-root user is the caller, then ambient capabilities are masked by the inherited ones, which were explicitly dropped. To make execution deterministic whatever users are running the tests, set the noroot secure bit for each test, and set the inheritable and ambient capabilities to CAP_NET_ADMIN, the only capability that may be required after an execve(2). Factor out _effective_cap() into _change_cap(), and use it to manage ambient capabilities with the new set_ambient_cap() and clear_ambient_cap() helpers. This makes it possible to run all Landlock tests with check-linux.sh from https://github.com/landlock-lsm/landlock-test-tools Cc: Konstantin Meskhidze <konstantin.meskhidze@huawei.com> Fixes: a549d05 ("selftests/landlock: Add network tests") Link: https://lore.kernel.org/r/20240125153230.3817165-2-mic@digikod.net [mic: Make sure SECBIT_NOROOT_LOCKED is set] Signed-off-by: Mickaël Salaün <mic@digikod.net>
1 parent 40b7835 commit bb6f4db

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

tools/testing/selftests/landlock/common.h

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <errno.h>
1111
#include <linux/landlock.h>
12+
#include <linux/securebits.h>
1213
#include <sys/capability.h>
1314
#include <sys/socket.h>
1415
#include <sys/syscall.h>
@@ -115,11 +116,16 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
115116
/* clang-format off */
116117
CAP_DAC_OVERRIDE,
117118
CAP_MKNOD,
119+
CAP_NET_ADMIN,
120+
CAP_NET_BIND_SERVICE,
118121
CAP_SYS_ADMIN,
119122
CAP_SYS_CHROOT,
120-
CAP_NET_BIND_SERVICE,
121123
/* clang-format on */
122124
};
125+
const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
126+
127+
if ((cap_get_secbits() & noroot) != noroot)
128+
EXPECT_EQ(0, cap_set_secbits(noroot));
123129

124130
cap_p = cap_get_proc();
125131
EXPECT_NE(NULL, cap_p)
@@ -137,6 +143,8 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
137143
TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
138144
}
139145
}
146+
147+
/* Automatically resets ambient capabilities. */
140148
EXPECT_NE(-1, cap_set_proc(cap_p))
141149
{
142150
TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
@@ -145,6 +153,9 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
145153
{
146154
TH_LOG("Failed to cap_free: %s", strerror(errno));
147155
}
156+
157+
/* Quickly checks that ambient capabilities are cleared. */
158+
EXPECT_NE(-1, cap_get_ambient(caps[0]));
148159
}
149160

150161
/* We cannot put such helpers in a library because of kselftest_harness.h . */
@@ -158,8 +169,9 @@ static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
158169
_init_caps(_metadata, true);
159170
}
160171

161-
static void _effective_cap(struct __test_metadata *const _metadata,
162-
const cap_value_t caps, const cap_flag_value_t value)
172+
static void _change_cap(struct __test_metadata *const _metadata,
173+
const cap_flag_t flag, const cap_value_t cap,
174+
const cap_flag_value_t value)
163175
{
164176
cap_t cap_p;
165177

@@ -168,7 +180,7 @@ static void _effective_cap(struct __test_metadata *const _metadata,
168180
{
169181
TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
170182
}
171-
EXPECT_NE(-1, cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &caps, value))
183+
EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value))
172184
{
173185
TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
174186
}
@@ -183,15 +195,35 @@ static void _effective_cap(struct __test_metadata *const _metadata,
183195
}
184196

185197
static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
186-
const cap_value_t caps)
198+
const cap_value_t cap)
187199
{
188-
_effective_cap(_metadata, caps, CAP_SET);
200+
_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET);
189201
}
190202

191203
static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
192-
const cap_value_t caps)
204+
const cap_value_t cap)
205+
{
206+
_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR);
207+
}
208+
209+
static void __maybe_unused
210+
set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap)
211+
{
212+
_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET);
213+
214+
EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET))
215+
{
216+
TH_LOG("Failed to set ambient capability %d: %s", cap,
217+
strerror(errno));
218+
}
219+
}
220+
221+
static void __maybe_unused clear_ambient_cap(
222+
struct __test_metadata *const _metadata, const cap_value_t cap)
193223
{
194-
_effective_cap(_metadata, caps, CAP_CLEAR);
224+
EXPECT_EQ(1, cap_get_ambient(cap));
225+
_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR);
226+
EXPECT_EQ(0, cap_get_ambient(cap));
195227
}
196228

197229
/* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */

tools/testing/selftests/landlock/net_test.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,11 @@ static void setup_loopback(struct __test_metadata *const _metadata)
107107
{
108108
set_cap(_metadata, CAP_SYS_ADMIN);
109109
ASSERT_EQ(0, unshare(CLONE_NEWNET));
110-
ASSERT_EQ(0, system("ip link set dev lo up"));
111110
clear_cap(_metadata, CAP_SYS_ADMIN);
111+
112+
set_ambient_cap(_metadata, CAP_NET_ADMIN);
113+
ASSERT_EQ(0, system("ip link set dev lo up"));
114+
clear_ambient_cap(_metadata, CAP_NET_ADMIN);
112115
}
113116

114117
static bool is_restricted(const struct protocol_variant *const prot,

0 commit comments

Comments
 (0)