Replace tomoyo_sb_mount() with granular mount hooks. Each hook reconstructs the MS_* flags expected by tomoyo_mount_permission() using the original flags parameter where available. Key changes: - mount_bind: passes the pre-resolved source path to tomoyo_mount_acl() via a new dev_path parameter, instead of re-resolving dev_name via kern_path(). This eliminates a TOCTOU vulnerability. - mount_new, mount_remount, mount_reconfigure: use the original mount(2) flags for policy matching. - mount_move: passes pre-resolved paths for both source and destination. - mount_change_type: passes raw ms_flags directly. Also removes the unused data_page parameter from tomoyo_mount_permission(). Code generated with the assistance of Claude, reviewed by human. Signed-off-by: Song Liu --- security/tomoyo/common.h | 2 +- security/tomoyo/mount.c | 31 +++++++++++++------- security/tomoyo/tomoyo.c | 63 ++++++++++++++++++++++++++++++---------- 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 4f1704c911ef..e40441844eab 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1013,7 +1013,7 @@ int tomoyo_mkdev_perm(const u8 operation, const struct path *path, const unsigned int mode, unsigned int dev); int tomoyo_mount_permission(const char *dev_name, const struct path *path, const char *type, unsigned long flags, - void *data_page); + const struct path *dev_path); int tomoyo_open_control(const u8 type, struct file *file); int tomoyo_path2_perm(const u8 operation, const struct path *path1, const struct path *path2); diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 322dfd188ada..82ffe7d02814 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -70,6 +70,7 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, * @dir: Pointer to "struct path". * @type: Name of filesystem type. * @flags: Mount options. + * @dev_path: Pre-resolved device/source path. Maybe NULL. * * Returns 0 on success, negative value otherwise. * @@ -78,11 +79,11 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, static int tomoyo_mount_acl(struct tomoyo_request_info *r, const char *dev_name, const struct path *dir, const char *type, - unsigned long flags) + unsigned long flags, + const struct path *dev_path) __must_hold_shared(&tomoyo_ss) { struct tomoyo_obj_info obj = { }; - struct path path; struct file_system_type *fstype = NULL; const char *requested_type = NULL; const char *requested_dir_name = NULL; @@ -134,13 +135,23 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, need_dev = 1; } if (need_dev) { - /* Get mount point or device file. */ - if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) { + if (dev_path) { + /* Use pre-resolved path to avoid TOCTOU issues. */ + obj.path1 = *dev_path; + path_get(&obj.path1); + } else if (!dev_name) { error = -ENOENT; goto out; + } else { + struct path path; + + if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) { + error = -ENOENT; + goto out; + } + obj.path1 = path; } - obj.path1 = path; - requested_dev_name = tomoyo_realpath_from_path(&path); + requested_dev_name = tomoyo_realpath_from_path(&obj.path1); if (!requested_dev_name) { error = -ENOENT; goto out; @@ -173,7 +184,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, if (fstype) put_filesystem(fstype); kfree(requested_type); - /* Drop refcount obtained by kern_path(). */ + /* Drop refcount obtained by kern_path() or path_get(). */ if (obj.path1.dentry) path_put(&obj.path1); return error; @@ -186,13 +197,13 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, * @path: Pointer to "struct path". * @type: Name of filesystem type. Maybe NULL. * @flags: Mount options. - * @data_page: Optional data. Maybe NULL. + * @dev_path: Pre-resolved device/source path. Maybe NULL. * * Returns 0 on success, negative value otherwise. */ int tomoyo_mount_permission(const char *dev_name, const struct path *path, const char *type, unsigned long flags, - void *data_page) + const struct path *dev_path) { struct tomoyo_request_info r; int error; @@ -236,7 +247,7 @@ int tomoyo_mount_permission(const char *dev_name, const struct path *path, if (!type) type = ""; idx = tomoyo_read_lock(); - error = tomoyo_mount_acl(&r, dev_name, path, type, flags); + error = tomoyo_mount_acl(&r, dev_name, path, type, flags, dev_path); tomoyo_read_unlock(idx); return error; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index c66e02ed8ee3..ac84e1f03d5e 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include "common.h" @@ -398,21 +400,47 @@ static int tomoyo_path_chroot(const struct path *path) return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); } -/** - * tomoyo_sb_mount - Target for security_sb_mount(). - * - * @dev_name: Name of device file. Maybe NULL. - * @path: Pointer to "struct path". - * @type: Name of filesystem type. Maybe NULL. - * @flags: Mount options. - * @data: Optional data. Maybe NULL. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data) +static int tomoyo_mount_bind(const struct path *from, const struct path *to, + bool recurse) +{ + unsigned long flags = MS_BIND | (recurse ? MS_REC : 0); + + return tomoyo_mount_permission(NULL, to, NULL, flags, from); +} + +static int tomoyo_mount_new(struct fs_context *fc, const struct path *mp, + int mnt_flags, unsigned long flags, void *data) +{ + /* Use original MS_* flags for policy matching */ + return tomoyo_mount_permission(fc->source, mp, fc->fs_type->name, + flags, NULL); +} + +static int tomoyo_mount_remount(struct fs_context *fc, const struct path *mp, + int mnt_flags, unsigned long flags, void *data) +{ + /* Use original MS_* flags for policy matching */ + return tomoyo_mount_permission(NULL, mp, NULL, flags, NULL); +} + +static int tomoyo_mount_reconfigure(const struct path *mp, + unsigned int mnt_flags, + unsigned long flags) +{ + /* Use original MS_* flags for policy matching */ + return tomoyo_mount_permission(NULL, mp, NULL, flags, NULL); +} + +static int tomoyo_mount_change_type(const struct path *mp, int ms_flags) +{ + return tomoyo_mount_permission(NULL, mp, NULL, ms_flags, NULL); +} + +static int tomoyo_move_mount(const struct path *from_path, + const struct path *to_path) { - return tomoyo_mount_permission(dev_name, path, type, flags, data); + return tomoyo_mount_permission(NULL, to_path, NULL, MS_MOVE, + from_path); } /** @@ -576,7 +604,12 @@ static struct security_hook_list tomoyo_hooks[] __ro_after_init = { LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod), LSM_HOOK_INIT(path_chown, tomoyo_path_chown), LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot), - LSM_HOOK_INIT(sb_mount, tomoyo_sb_mount), + LSM_HOOK_INIT(mount_bind, tomoyo_mount_bind), + LSM_HOOK_INIT(mount_new, tomoyo_mount_new), + LSM_HOOK_INIT(mount_remount, tomoyo_mount_remount), + LSM_HOOK_INIT(mount_reconfigure, tomoyo_mount_reconfigure), + LSM_HOOK_INIT(mount_change_type, tomoyo_mount_change_type), + LSM_HOOK_INIT(mount_move, tomoyo_move_mount), LSM_HOOK_INIT(sb_umount, tomoyo_sb_umount), LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot), LSM_HOOK_INIT(socket_bind, tomoyo_socket_bind), -- 2.52.0