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

landlock: Reduce the maximum number of layers to 16

The maximum number of nested Landlock domains is currently 64. Because
of the following fix and to help reduce the stack size, let's reduce it
to 16. This seems large enough for a lot of use cases (e.g. sandboxed
init service, spawning a sandboxed SSH service, in nested sandboxed
containers). Reducing the number of nested domains may also help to
discover misuse of Landlock (e.g. creating a domain per rule).

Add and use a dedicated layer_mask_t typedef to fit with the number of
layers. This might be useful when changing it and to keep it consistent
with the maximum number of layers.

Reviewed-by: Paul Moore <paul@paul-moore.com>
Link: https://lore.kernel.org/r/20220506161102.525323-3-mic@digikod.net
Cc: stable@vger.kernel.org
Signed-off-by: Mickaël Salaün <mic@digikod.net>

+15 -14
+2 -2
Documentation/userspace-api/landlock.rst
··· 267 267 Ruleset layers 268 268 -------------- 269 269 270 - There is a limit of 64 layers of stacked rulesets. This can be an issue for a 271 - task willing to enforce a new ruleset in complement to its 64 inherited 270 + There is a limit of 16 layers of stacked rulesets. This can be an issue for a 271 + task willing to enforce a new ruleset in complement to its 16 inherited 272 272 rulesets. Once this limit is reached, sys_landlock_restrict_self() returns 273 273 E2BIG. It is then strongly suggested to carefully build rulesets once in the 274 274 life of a thread, especially for applications able to launch other applications
+7 -10
security/landlock/fs.c
··· 183 183 184 184 /* Access-control management */ 185 185 186 - static inline u64 unmask_layers(const struct landlock_ruleset *const domain, 187 - const struct path *const path, 188 - const access_mask_t access_request, 189 - u64 layer_mask) 186 + static inline layer_mask_t 187 + unmask_layers(const struct landlock_ruleset *const domain, 188 + const struct path *const path, const access_mask_t access_request, 189 + layer_mask_t layer_mask) 190 190 { 191 191 const struct landlock_rule *rule; 192 192 const struct inode *inode; ··· 212 212 */ 213 213 for (i = 0; i < rule->num_layers; i++) { 214 214 const struct landlock_layer *const layer = &rule->layers[i]; 215 - const u64 layer_level = BIT_ULL(layer->level - 1); 215 + const layer_mask_t layer_bit = BIT_ULL(layer->level - 1); 216 216 217 217 /* Checks that the layer grants access to the full request. */ 218 218 if ((layer->access & access_request) == access_request) { 219 - layer_mask &= ~layer_level; 219 + layer_mask &= ~layer_bit; 220 220 221 221 if (layer_mask == 0) 222 222 return layer_mask; ··· 231 231 { 232 232 bool allowed = false; 233 233 struct path walker_path; 234 - u64 layer_mask; 234 + layer_mask_t layer_mask; 235 235 size_t i; 236 - 237 - /* Make sure all layers can be checked. */ 238 - BUILD_BUG_ON(BITS_PER_TYPE(layer_mask) < LANDLOCK_MAX_NUM_LAYERS); 239 236 240 237 if (!access_request) 241 238 return 0;
+1 -1
security/landlock/limits.h
··· 15 15 16 16 /* clang-format off */ 17 17 18 - #define LANDLOCK_MAX_NUM_LAYERS 64 18 + #define LANDLOCK_MAX_NUM_LAYERS 16 19 19 #define LANDLOCK_MAX_NUM_RULES U32_MAX 20 20 21 21 #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM
+4
security/landlock/ruleset.h
··· 23 23 /* Makes sure all filesystem access rights can be stored. */ 24 24 static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS); 25 25 26 + typedef u16 layer_mask_t; 27 + /* Makes sure all layers can be checked. */ 28 + static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS); 29 + 26 30 /** 27 31 * struct landlock_layer - Access rights for a given layer 28 32 */
+1 -1
tools/testing/selftests/landlock/fs_test.c
··· 1159 1159 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1160 1160 1161 1161 ASSERT_LE(0, ruleset_fd); 1162 - for (i = 0; i < 64; i++) 1162 + for (i = 0; i < 16; i++) 1163 1163 enforce_ruleset(_metadata, ruleset_fd); 1164 1164 1165 1165 for (i = 0; i < 2; i++) {