@@ -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);
}
@@ -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;
@@ -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 */
Add audit support for mount, move_mount, umount, remount, and pivot_root requests. Signed-off-by: Mickaël Salaün <mic@digikod.net> --- security/landlock/audit.c | 26 ++++++++++++- security/landlock/audit.h | 13 ++++++- security/landlock/fs.c | 82 ++++++++++++++++++++++++++++++++++----- 3 files changed, 109 insertions(+), 12 deletions(-)