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

Configure Feed

Select the types of activity you want to include in your feed.

landlock: Log mount-related denials

Add audit support for sb_mount, move_mount, sb_umount, sb_remount, and
sb_pivot_root hooks.

The new related blocker is "fs.change_topology".

Audit event sample:

type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=fs.change_topology name="/" dev="tmpfs" ino=1

Remove landlock_get_applicable_domain() and get_current_fs_domain()
which are now fully replaced with landlock_get_applicable_subject().

Cc: Günther Noack <gnoack@google.com>
Link: https://lore.kernel.org/r/20250320190717.2287696-12-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>

+74 -41
+3
security/landlock/audit.c
··· 21 21 switch (type) { 22 22 case LANDLOCK_REQUEST_PTRACE: 23 23 return "ptrace"; 24 + 25 + case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY: 26 + return "fs.change_topology"; 24 27 } 25 28 26 29 WARN_ON_ONCE(1);
+1
security/landlock/audit.h
··· 15 15 16 16 enum landlock_request_type { 17 17 LANDLOCK_REQUEST_PTRACE = 1, 18 + LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY, 18 19 }; 19 20 20 21 /*
+70 -11
security/landlock/fs.c
··· 23 23 #include <linux/kernel.h> 24 24 #include <linux/limits.h> 25 25 #include <linux/list.h> 26 + #include <linux/lsm_audit.h> 26 27 #include <linux/lsm_hooks.h> 27 28 #include <linux/mount.h> 28 29 #include <linux/namei.h> ··· 40 39 #include <uapi/linux/landlock.h> 41 40 42 41 #include "access.h" 42 + #include "audit.h" 43 43 #include "common.h" 44 44 #include "cred.h" 45 45 #include "fs.h" ··· 396 394 static const struct access_masks any_fs = { 397 395 .fs = ~0, 398 396 }; 399 - 400 - static const struct landlock_ruleset *get_current_fs_domain(void) 401 - { 402 - return landlock_get_applicable_domain(landlock_get_current_domain(), 403 - any_fs); 404 - } 405 397 406 398 /* 407 399 * Check that a destination file hierarchy has more restrictions than a source ··· 1331 1335 !atomic_long_read(&landlock_superblock(sb)->inode_refs)); 1332 1336 } 1333 1337 1338 + static void 1339 + log_fs_change_topology_path(const struct landlock_cred_security *const subject, 1340 + size_t handle_layer, const struct path *const path) 1341 + { 1342 + landlock_log_denial(subject, &(struct landlock_request) { 1343 + .type = LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY, 1344 + .audit = { 1345 + .type = LSM_AUDIT_DATA_PATH, 1346 + .u.path = *path, 1347 + }, 1348 + .layer_plus_one = handle_layer + 1, 1349 + }); 1350 + } 1351 + 1352 + static void log_fs_change_topology_dentry( 1353 + const struct landlock_cred_security *const subject, size_t handle_layer, 1354 + struct dentry *const dentry) 1355 + { 1356 + landlock_log_denial(subject, &(struct landlock_request) { 1357 + .type = LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY, 1358 + .audit = { 1359 + .type = LSM_AUDIT_DATA_DENTRY, 1360 + .u.dentry = dentry, 1361 + }, 1362 + .layer_plus_one = handle_layer + 1, 1363 + }); 1364 + } 1365 + 1334 1366 /* 1335 1367 * Because a Landlock security policy is defined according to the filesystem 1336 1368 * topology (i.e. the mount namespace), changing it may grant access to files ··· 1381 1357 const struct path *const path, const char *const type, 1382 1358 const unsigned long flags, void *const data) 1383 1359 { 1384 - if (!get_current_fs_domain()) 1360 + size_t handle_layer; 1361 + const struct landlock_cred_security *const subject = 1362 + landlock_get_applicable_subject(current_cred(), any_fs, 1363 + &handle_layer); 1364 + 1365 + if (!subject) 1385 1366 return 0; 1367 + 1368 + log_fs_change_topology_path(subject, handle_layer, path); 1386 1369 return -EPERM; 1387 1370 } 1388 1371 1389 1372 static int hook_move_mount(const struct path *const from_path, 1390 1373 const struct path *const to_path) 1391 1374 { 1392 - if (!get_current_fs_domain()) 1375 + size_t handle_layer; 1376 + const struct landlock_cred_security *const subject = 1377 + landlock_get_applicable_subject(current_cred(), any_fs, 1378 + &handle_layer); 1379 + 1380 + if (!subject) 1393 1381 return 0; 1382 + 1383 + log_fs_change_topology_path(subject, handle_layer, to_path); 1394 1384 return -EPERM; 1395 1385 } 1396 1386 ··· 1414 1376 */ 1415 1377 static int hook_sb_umount(struct vfsmount *const mnt, const int flags) 1416 1378 { 1417 - if (!get_current_fs_domain()) 1379 + size_t handle_layer; 1380 + const struct landlock_cred_security *const subject = 1381 + landlock_get_applicable_subject(current_cred(), any_fs, 1382 + &handle_layer); 1383 + 1384 + if (!subject) 1418 1385 return 0; 1386 + 1387 + log_fs_change_topology_dentry(subject, handle_layer, mnt->mnt_root); 1419 1388 return -EPERM; 1420 1389 } 1421 1390 1422 1391 static int hook_sb_remount(struct super_block *const sb, void *const mnt_opts) 1423 1392 { 1424 - if (!get_current_fs_domain()) 1393 + size_t handle_layer; 1394 + const struct landlock_cred_security *const subject = 1395 + landlock_get_applicable_subject(current_cred(), any_fs, 1396 + &handle_layer); 1397 + 1398 + if (!subject) 1425 1399 return 0; 1400 + 1401 + log_fs_change_topology_dentry(subject, handle_layer, sb->s_root); 1426 1402 return -EPERM; 1427 1403 } 1428 1404 ··· 1451 1399 static int hook_sb_pivotroot(const struct path *const old_path, 1452 1400 const struct path *const new_path) 1453 1401 { 1454 - if (!get_current_fs_domain()) 1402 + size_t handle_layer; 1403 + const struct landlock_cred_security *const subject = 1404 + landlock_get_applicable_subject(current_cred(), any_fs, 1405 + &handle_layer); 1406 + 1407 + if (!subject) 1455 1408 return 0; 1409 + 1410 + log_fs_change_topology_path(subject, handle_layer, new_path); 1456 1411 return -EPERM; 1457 1412 } 1458 1413
-30
security/landlock/ruleset.h
··· 243 243 return matches.masks; 244 244 } 245 245 246 - /** 247 - * landlock_get_applicable_domain - Return @domain if it applies to (handles) 248 - * at least one of the access rights specified 249 - * in @masks 250 - * 251 - * @domain: Landlock ruleset (used as a domain) 252 - * @masks: access masks 253 - * 254 - * Returns: @domain if any access rights specified in @masks is handled, or 255 - * NULL otherwise. 256 - */ 257 - static inline const struct landlock_ruleset * 258 - landlock_get_applicable_domain(const struct landlock_ruleset *const domain, 259 - const struct access_masks masks) 260 - { 261 - const union access_masks_all masks_all = { 262 - .masks = masks, 263 - }; 264 - union access_masks_all merge = {}; 265 - 266 - if (!domain) 267 - return NULL; 268 - 269 - merge.masks = landlock_union_access_masks(domain); 270 - if (merge.all & masks_all.all) 271 - return domain; 272 - 273 - return NULL; 274 - } 275 - 276 246 static inline void 277 247 landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, 278 248 const access_mask_t fs_access_mask,