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

landlock: Change landlock_add_rule(2) argument check ordering

This makes more sense to first check the ruleset FD and then the rule
attribute. It will be useful to factor out code for other rule types.

Add inval_add_rule_arguments tests, extension of empty_path_beneath_attr
tests, to also check error ordering for landlock_add_rule(2).

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

+45 -11
+13 -9
security/landlock/syscalls.c
··· 318 318 if (flags) 319 319 return -EINVAL; 320 320 321 - if (rule_type != LANDLOCK_RULE_PATH_BENEATH) 322 - return -EINVAL; 323 - 324 - /* Copies raw user space buffer, only one type for now. */ 325 - res = copy_from_user(&path_beneath_attr, rule_attr, 326 - sizeof(path_beneath_attr)); 327 - if (res) 328 - return -EFAULT; 329 - 330 321 /* Gets and checks the ruleset. */ 331 322 ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_WRITE); 332 323 if (IS_ERR(ruleset)) 333 324 return PTR_ERR(ruleset); 325 + 326 + if (rule_type != LANDLOCK_RULE_PATH_BENEATH) { 327 + err = -EINVAL; 328 + goto out_put_ruleset; 329 + } 330 + 331 + /* Copies raw user space buffer, only one type for now. */ 332 + res = copy_from_user(&path_beneath_attr, rule_attr, 333 + sizeof(path_beneath_attr)); 334 + if (res) { 335 + err = -EFAULT; 336 + goto out_put_ruleset; 337 + } 334 338 335 339 /* 336 340 * Informs about useless rule: empty allowed_access (i.e. deny rules)
+32 -2
tools/testing/selftests/landlock/base_test.c
··· 121 121 ASSERT_EQ(EINVAL, errno); 122 122 } 123 123 124 - TEST(empty_path_beneath_attr) 124 + /* Tests ordering of syscall argument checks. */ 125 + TEST(add_rule_checks_ordering) 125 126 { 126 127 const struct landlock_ruleset_attr ruleset_attr = { 127 128 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 129 + }; 130 + struct landlock_path_beneath_attr path_beneath_attr = { 131 + .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 132 + .parent_fd = -1, 128 133 }; 129 134 const int ruleset_fd = 130 135 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 131 136 132 137 ASSERT_LE(0, ruleset_fd); 133 138 134 - /* Similar to struct landlock_path_beneath_attr.parent_fd = 0 */ 139 + /* Checks invalid flags. */ 140 + ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1)); 141 + ASSERT_EQ(EINVAL, errno); 142 + 143 + /* Checks invalid ruleset FD. */ 144 + ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0)); 145 + ASSERT_EQ(EBADF, errno); 146 + 147 + /* Checks invalid rule type. */ 148 + ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0)); 149 + ASSERT_EQ(EINVAL, errno); 150 + 151 + /* Checks invalid rule attr. */ 135 152 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 136 153 NULL, 0)); 137 154 ASSERT_EQ(EFAULT, errno); 155 + 156 + /* Checks invalid path_beneath.parent_fd. */ 157 + ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 158 + &path_beneath_attr, 0)); 159 + ASSERT_EQ(EBADF, errno); 160 + 161 + /* Checks valid call. */ 162 + path_beneath_attr.parent_fd = 163 + open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 164 + ASSERT_LE(0, path_beneath_attr.parent_fd); 165 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 166 + &path_beneath_attr, 0)); 167 + ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 138 168 ASSERT_EQ(0, close(ruleset_fd)); 139 169 } 140 170