Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

landlock: Change landlock_restrict_self(2) check ordering

According to the Landlock goal to be a security feature available to
unprivileges processes, it makes more sense to first check for
no_new_privs before checking anything else (i.e. syscall arguments).

Merge inval_fd_enforce and unpriv_enforce_without_no_new_privs tests
into the new restrict_self_checks_ordering. This is similar to the
previous commit checking other syscalls.

Link: https://lore.kernel.org/r/20220506160820.524344-10-mic@digikod.net
Cc: stable@vger.kernel.org
Signed-off-by: Mickaël Salaün <mic@digikod.net>

+41 -14
+4 -4
security/landlock/syscalls.c
··· 405 405 if (!landlock_initialized) 406 406 return -EOPNOTSUPP; 407 407 408 - /* No flag for now. */ 409 - if (flags) 410 - return -EINVAL; 411 - 412 408 /* 413 409 * Similar checks as for seccomp(2), except that an -EPERM may be 414 410 * returned. ··· 412 416 if (!task_no_new_privs(current) && 413 417 !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN)) 414 418 return -EPERM; 419 + 420 + /* No flag for now. */ 421 + if (flags) 422 + return -EINVAL; 415 423 416 424 /* Gets and checks the ruleset. */ 417 425 ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);
+37 -10
tools/testing/selftests/landlock/base_test.c
··· 168 168 ASSERT_EQ(0, close(ruleset_fd)); 169 169 } 170 170 171 - TEST(inval_fd_enforce) 171 + /* Tests ordering of syscall argument and permission checks. */ 172 + TEST(restrict_self_checks_ordering) 172 173 { 174 + const struct landlock_ruleset_attr ruleset_attr = { 175 + .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 176 + }; 177 + struct landlock_path_beneath_attr path_beneath_attr = { 178 + .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 179 + .parent_fd = -1, 180 + }; 181 + const int ruleset_fd = 182 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 183 + 184 + ASSERT_LE(0, ruleset_fd); 185 + path_beneath_attr.parent_fd = 186 + open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 187 + ASSERT_LE(0, path_beneath_attr.parent_fd); 188 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 189 + &path_beneath_attr, 0)); 190 + ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 191 + 192 + /* Checks unprivileged enforcement without no_new_privs. */ 193 + drop_caps(_metadata); 194 + ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 195 + ASSERT_EQ(EPERM, errno); 196 + ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 197 + ASSERT_EQ(EPERM, errno); 198 + ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0)); 199 + ASSERT_EQ(EPERM, errno); 200 + 173 201 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 174 202 203 + /* Checks invalid flags. */ 204 + ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 205 + ASSERT_EQ(EINVAL, errno); 206 + 207 + /* Checks invalid ruleset FD. */ 175 208 ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 176 209 ASSERT_EQ(EBADF, errno); 177 - } 178 210 179 - TEST(unpriv_enforce_without_no_new_privs) 180 - { 181 - int err; 182 - 183 - drop_caps(_metadata); 184 - err = landlock_restrict_self(-1, 0); 185 - ASSERT_EQ(EPERM, errno); 186 - ASSERT_EQ(err, -1); 211 + /* Checks valid call. */ 212 + ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 213 + ASSERT_EQ(0, close(ruleset_fd)); 187 214 } 188 215 189 216 TEST(ruleset_fd_io)