Add audit support for mount, move_mount, umount, remount, and pivot_root requests.
Signed-off-by: Mickaël Salaün <[email protected]> --- security/landlock/audit.c | 26 ++++++++++++- security/landlock/audit.h | 13 ++++++- security/landlock/fs.c | 82 ++++++++++++++++++++++++++++++++++----- 3 files changed, 109 insertions(+), 12 deletions(-) diff --git a/security/landlock/audit.c b/security/landlock/audit.c index 148fc0fafef4..89bd701d124f 100644 --- a/security/landlock/audit.c +++ b/security/landlock/audit.c @@ -18,6 +18,11 @@ static const char *op_to_string(enum landlock_operation operation) { const char *const desc[] = { [0] = "", + [LANDLOCK_OP_MOUNT] = "mount", + [LANDLOCK_OP_MOVE_MOUNT] = "move_mount", + [LANDLOCK_OP_UMOUNT] = "umount", + [LANDLOCK_OP_REMOUNT] = "remount", + [LANDLOCK_OP_PIVOT_ROOT] = "pivot_root", [LANDLOCK_OP_MKDIR] = "mkdir", [LANDLOCK_OP_MKNOD] = "mknod", [LANDLOCK_OP_SYMLINK] = "symlink", @@ -33,6 +38,20 @@ static const char *op_to_string(enum landlock_operation operation) return desc[operation]; } +static const char *perm_to_string(enum landlock_permission permission) +{ + const char *const desc[] = { + [0] = "", + [LANDLOCK_PERM_PTRACE] = "ptrace", + [LANDLOCK_PERM_FS_LAYOUT] = "fs_layout", + }; + + if (WARN_ON_ONCE(permission < 0 || permission > ARRAY_SIZE(desc))) + return "unknown"; + + return desc[permission]; +} + #define BIT_INDEX(bit) HWEIGHT(bit - 1) static void log_accesses(struct audit_buffer *const ab, @@ -177,8 +196,11 @@ update_request(struct landlock_request *const request, WARN_ON_ONCE(request->youngest_domain); WARN_ON_ONCE(request->missing_access); - if (WARN_ON_ONCE(!access_request)) + if (!access_request) { + /* No missing accesses. */ + request->youngest_domain = node->id; return; + } if (WARN_ON_ONCE(!layer_masks)) return; @@ -240,6 +262,8 @@ log_request(const int error, struct landlock_request *const request, request->youngest_domain, op_to_string(request->operation), -error); log_accesses(ab, request->missing_access); + audit_log_format(ab, " missing-permission=%s", + perm_to_string(request->missing_permission)); audit_log_lsm_data(ab, &request->audit); audit_log_end(ab); } diff --git a/security/landlock/audit.h b/security/landlock/audit.h index 8edc68b98fca..e559fb6a89dd 100644 --- a/security/landlock/audit.h +++ b/security/landlock/audit.h @@ -14,7 +14,12 @@ #include "ruleset.h" enum landlock_operation { - LANDLOCK_OP_MKDIR = 1, + LANDLOCK_OP_MOUNT = 1, + LANDLOCK_OP_MOVE_MOUNT, + LANDLOCK_OP_UMOUNT, + LANDLOCK_OP_REMOUNT, + LANDLOCK_OP_PIVOT_ROOT, + LANDLOCK_OP_MKDIR, LANDLOCK_OP_MKNOD, LANDLOCK_OP_SYMLINK, LANDLOCK_OP_UNLINK, @@ -23,8 +28,14 @@ enum landlock_operation { LANDLOCK_OP_OPEN, }; +enum landlock_permission { + LANDLOCK_PERM_PTRACE = 1, + LANDLOCK_PERM_FS_LAYOUT, +}; + struct landlock_request { const enum landlock_operation operation; + const enum landlock_permission missing_permission; access_mask_t missing_access; u64 youngest_domain; struct common_audit_data audit; diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 104dfb2abc32..8600530e304c 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -1050,17 +1050,41 @@ static int hook_sb_mount(const char *const dev_name, const struct path *const path, const char *const type, const unsigned long flags, void *const data) { - if (!landlock_get_current_domain()) + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + struct landlock_request request = { + .operation = LANDLOCK_OP_MOUNT, + .missing_permission = LANDLOCK_PERM_FS_LAYOUT, + .audit = { + .type = LSM_AUDIT_DATA_PATH, + .u.path = *path, + }, + }; + + if (!dom) return 0; - return -EPERM; + + return landlock_log_request(-EPERM, &request, dom, 0, NULL); } static int hook_move_mount(const struct path *const from_path, const struct path *const to_path) { - if (!landlock_get_current_domain()) + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + struct landlock_request request = { + .operation = LANDLOCK_OP_MOVE_MOUNT, + .missing_permission = LANDLOCK_PERM_FS_LAYOUT, + .audit = { + .type = LSM_AUDIT_DATA_PATH, + .u.path = *to_path, + }, + }; + + if (!dom) return 0; - return -EPERM; + + return landlock_log_request(-EPERM, &request, dom, 0, NULL); } /* @@ -1069,16 +1093,42 @@ static int hook_move_mount(const struct path *const from_path, */ static int hook_sb_umount(struct vfsmount *const mnt, const int flags) { - if (!landlock_get_current_domain()) + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + struct landlock_request request = { + .operation = LANDLOCK_OP_UMOUNT, + .missing_permission = LANDLOCK_PERM_FS_LAYOUT, + .audit = { + // TODO: try to print the mounted path + // cf. dentry_path() + .type = LSM_AUDIT_DATA_DENTRY, + .u.dentry = mnt->mnt_root, + }, + }; + + if (!dom) return 0; - return -EPERM; + + return landlock_log_request(-EPERM, &request, dom, 0, NULL); } static int hook_sb_remount(struct super_block *const sb, void *const mnt_opts) { - if (!landlock_get_current_domain()) + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + struct landlock_request request = { + .operation = LANDLOCK_OP_REMOUNT, + .missing_permission = LANDLOCK_PERM_FS_LAYOUT, + .audit = { + .type = LSM_AUDIT_DATA_DENTRY, + .u.dentry = sb->s_root, + }, + }; + + if (!dom) return 0; - return -EPERM; + + return landlock_log_request(-EPERM, &request, dom, 0, NULL); } /* @@ -1092,9 +1142,21 @@ static int hook_sb_remount(struct super_block *const sb, void *const mnt_opts) static int hook_sb_pivotroot(const struct path *const old_path, const struct path *const new_path) { - if (!landlock_get_current_domain()) + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + struct landlock_request request = { + .operation = LANDLOCK_OP_PIVOT_ROOT, + .missing_permission = LANDLOCK_PERM_FS_LAYOUT, + .audit = { + .type = LSM_AUDIT_DATA_PATH, + .u.path = *new_path, + }, + }; + + if (!dom) return 0; - return -EPERM; + + return landlock_log_request(-EPERM, &request, dom, 0, NULL); } /* Path hooks */ -- 2.42.0
