162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * security/tomoyo/mount.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2011 NTT DATA CORPORATION 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <uapi/linux/mount.h> 1062306a36Sopenharmony_ci#include "common.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* String table for special mount operations. */ 1362306a36Sopenharmony_cistatic const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = { 1462306a36Sopenharmony_ci [TOMOYO_MOUNT_BIND] = "--bind", 1562306a36Sopenharmony_ci [TOMOYO_MOUNT_MOVE] = "--move", 1662306a36Sopenharmony_ci [TOMOYO_MOUNT_REMOUNT] = "--remount", 1762306a36Sopenharmony_ci [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable", 1862306a36Sopenharmony_ci [TOMOYO_MOUNT_MAKE_PRIVATE] = "--make-private", 1962306a36Sopenharmony_ci [TOMOYO_MOUNT_MAKE_SLAVE] = "--make-slave", 2062306a36Sopenharmony_ci [TOMOYO_MOUNT_MAKE_SHARED] = "--make-shared", 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * tomoyo_audit_mount_log - Audit mount log. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistatic int tomoyo_audit_mount_log(struct tomoyo_request_info *r) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n", 3362306a36Sopenharmony_ci r->param.mount.dev->name, 3462306a36Sopenharmony_ci r->param.mount.dir->name, 3562306a36Sopenharmony_ci r->param.mount.type->name, 3662306a36Sopenharmony_ci r->param.mount.flags); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/** 4062306a36Sopenharmony_ci * tomoyo_check_mount_acl - Check permission for path path path number operation. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 4362306a36Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_acl_info". 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Returns true if granted, false otherwise. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, 4862306a36Sopenharmony_ci const struct tomoyo_acl_info *ptr) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci const struct tomoyo_mount_acl *acl = 5162306a36Sopenharmony_ci container_of(ptr, typeof(*acl), head); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return tomoyo_compare_number_union(r->param.mount.flags, 5462306a36Sopenharmony_ci &acl->flags) && 5562306a36Sopenharmony_ci tomoyo_compare_name_union(r->param.mount.type, 5662306a36Sopenharmony_ci &acl->fs_type) && 5762306a36Sopenharmony_ci tomoyo_compare_name_union(r->param.mount.dir, 5862306a36Sopenharmony_ci &acl->dir_name) && 5962306a36Sopenharmony_ci (!r->param.mount.need_dev || 6062306a36Sopenharmony_ci tomoyo_compare_name_union(r->param.mount.dev, 6162306a36Sopenharmony_ci &acl->dev_name)); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * tomoyo_mount_acl - Check permission for mount() operation. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 6862306a36Sopenharmony_ci * @dev_name: Name of device file. Maybe NULL. 6962306a36Sopenharmony_ci * @dir: Pointer to "struct path". 7062306a36Sopenharmony_ci * @type: Name of filesystem type. 7162306a36Sopenharmony_ci * @flags: Mount options. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise. 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * Caller holds tomoyo_read_lock(). 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic int tomoyo_mount_acl(struct tomoyo_request_info *r, 7862306a36Sopenharmony_ci const char *dev_name, 7962306a36Sopenharmony_ci const struct path *dir, const char *type, 8062306a36Sopenharmony_ci unsigned long flags) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct tomoyo_obj_info obj = { }; 8362306a36Sopenharmony_ci struct path path; 8462306a36Sopenharmony_ci struct file_system_type *fstype = NULL; 8562306a36Sopenharmony_ci const char *requested_type = NULL; 8662306a36Sopenharmony_ci const char *requested_dir_name = NULL; 8762306a36Sopenharmony_ci const char *requested_dev_name = NULL; 8862306a36Sopenharmony_ci struct tomoyo_path_info rtype; 8962306a36Sopenharmony_ci struct tomoyo_path_info rdev; 9062306a36Sopenharmony_ci struct tomoyo_path_info rdir; 9162306a36Sopenharmony_ci int need_dev = 0; 9262306a36Sopenharmony_ci int error = -ENOMEM; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci r->obj = &obj; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Get fstype. */ 9762306a36Sopenharmony_ci requested_type = tomoyo_encode(type); 9862306a36Sopenharmony_ci if (!requested_type) 9962306a36Sopenharmony_ci goto out; 10062306a36Sopenharmony_ci rtype.name = requested_type; 10162306a36Sopenharmony_ci tomoyo_fill_path_info(&rtype); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Get mount point. */ 10462306a36Sopenharmony_ci obj.path2 = *dir; 10562306a36Sopenharmony_ci requested_dir_name = tomoyo_realpath_from_path(dir); 10662306a36Sopenharmony_ci if (!requested_dir_name) { 10762306a36Sopenharmony_ci error = -ENOMEM; 10862306a36Sopenharmony_ci goto out; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci rdir.name = requested_dir_name; 11162306a36Sopenharmony_ci tomoyo_fill_path_info(&rdir); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* Compare fs name. */ 11462306a36Sopenharmony_ci if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) { 11562306a36Sopenharmony_ci /* dev_name is ignored. */ 11662306a36Sopenharmony_ci } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] || 11762306a36Sopenharmony_ci type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] || 11862306a36Sopenharmony_ci type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] || 11962306a36Sopenharmony_ci type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) { 12062306a36Sopenharmony_ci /* dev_name is ignored. */ 12162306a36Sopenharmony_ci } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] || 12262306a36Sopenharmony_ci type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { 12362306a36Sopenharmony_ci need_dev = -1; /* dev_name is a directory */ 12462306a36Sopenharmony_ci } else { 12562306a36Sopenharmony_ci fstype = get_fs_type(type); 12662306a36Sopenharmony_ci if (!fstype) { 12762306a36Sopenharmony_ci error = -ENODEV; 12862306a36Sopenharmony_ci goto out; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if (fstype->fs_flags & FS_REQUIRES_DEV) 13162306a36Sopenharmony_ci /* dev_name is a block device file. */ 13262306a36Sopenharmony_ci need_dev = 1; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci if (need_dev) { 13562306a36Sopenharmony_ci /* Get mount point or device file. */ 13662306a36Sopenharmony_ci if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) { 13762306a36Sopenharmony_ci error = -ENOENT; 13862306a36Sopenharmony_ci goto out; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci obj.path1 = path; 14162306a36Sopenharmony_ci requested_dev_name = tomoyo_realpath_from_path(&path); 14262306a36Sopenharmony_ci if (!requested_dev_name) { 14362306a36Sopenharmony_ci error = -ENOENT; 14462306a36Sopenharmony_ci goto out; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci } else { 14762306a36Sopenharmony_ci /* Map dev_name to "<NULL>" if no dev_name given. */ 14862306a36Sopenharmony_ci if (!dev_name) 14962306a36Sopenharmony_ci dev_name = "<NULL>"; 15062306a36Sopenharmony_ci requested_dev_name = tomoyo_encode(dev_name); 15162306a36Sopenharmony_ci if (!requested_dev_name) { 15262306a36Sopenharmony_ci error = -ENOMEM; 15362306a36Sopenharmony_ci goto out; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci rdev.name = requested_dev_name; 15762306a36Sopenharmony_ci tomoyo_fill_path_info(&rdev); 15862306a36Sopenharmony_ci r->param_type = TOMOYO_TYPE_MOUNT_ACL; 15962306a36Sopenharmony_ci r->param.mount.need_dev = need_dev; 16062306a36Sopenharmony_ci r->param.mount.dev = &rdev; 16162306a36Sopenharmony_ci r->param.mount.dir = &rdir; 16262306a36Sopenharmony_ci r->param.mount.type = &rtype; 16362306a36Sopenharmony_ci r->param.mount.flags = flags; 16462306a36Sopenharmony_ci do { 16562306a36Sopenharmony_ci tomoyo_check_acl(r, tomoyo_check_mount_acl); 16662306a36Sopenharmony_ci error = tomoyo_audit_mount_log(r); 16762306a36Sopenharmony_ci } while (error == TOMOYO_RETRY_REQUEST); 16862306a36Sopenharmony_ci out: 16962306a36Sopenharmony_ci kfree(requested_dev_name); 17062306a36Sopenharmony_ci kfree(requested_dir_name); 17162306a36Sopenharmony_ci if (fstype) 17262306a36Sopenharmony_ci put_filesystem(fstype); 17362306a36Sopenharmony_ci kfree(requested_type); 17462306a36Sopenharmony_ci /* Drop refcount obtained by kern_path(). */ 17562306a36Sopenharmony_ci if (obj.path1.dentry) 17662306a36Sopenharmony_ci path_put(&obj.path1); 17762306a36Sopenharmony_ci return error; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/** 18162306a36Sopenharmony_ci * tomoyo_mount_permission - Check permission for mount() operation. 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * @dev_name: Name of device file. Maybe NULL. 18462306a36Sopenharmony_ci * @path: Pointer to "struct path". 18562306a36Sopenharmony_ci * @type: Name of filesystem type. Maybe NULL. 18662306a36Sopenharmony_ci * @flags: Mount options. 18762306a36Sopenharmony_ci * @data_page: Optional data. Maybe NULL. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ciint tomoyo_mount_permission(const char *dev_name, const struct path *path, 19262306a36Sopenharmony_ci const char *type, unsigned long flags, 19362306a36Sopenharmony_ci void *data_page) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct tomoyo_request_info r; 19662306a36Sopenharmony_ci int error; 19762306a36Sopenharmony_ci int idx; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) 20062306a36Sopenharmony_ci == TOMOYO_CONFIG_DISABLED) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci if ((flags & MS_MGC_MSK) == MS_MGC_VAL) 20362306a36Sopenharmony_ci flags &= ~MS_MGC_MSK; 20462306a36Sopenharmony_ci if (flags & MS_REMOUNT) { 20562306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; 20662306a36Sopenharmony_ci flags &= ~MS_REMOUNT; 20762306a36Sopenharmony_ci } else if (flags & MS_BIND) { 20862306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; 20962306a36Sopenharmony_ci flags &= ~MS_BIND; 21062306a36Sopenharmony_ci } else if (flags & MS_SHARED) { 21162306a36Sopenharmony_ci if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; 21462306a36Sopenharmony_ci flags &= ~MS_SHARED; 21562306a36Sopenharmony_ci } else if (flags & MS_PRIVATE) { 21662306a36Sopenharmony_ci if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE)) 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; 21962306a36Sopenharmony_ci flags &= ~MS_PRIVATE; 22062306a36Sopenharmony_ci } else if (flags & MS_SLAVE) { 22162306a36Sopenharmony_ci if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE)) 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; 22462306a36Sopenharmony_ci flags &= ~MS_SLAVE; 22562306a36Sopenharmony_ci } else if (flags & MS_UNBINDABLE) { 22662306a36Sopenharmony_ci if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE)) 22762306a36Sopenharmony_ci return -EINVAL; 22862306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; 22962306a36Sopenharmony_ci flags &= ~MS_UNBINDABLE; 23062306a36Sopenharmony_ci } else if (flags & MS_MOVE) { 23162306a36Sopenharmony_ci type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; 23262306a36Sopenharmony_ci flags &= ~MS_MOVE; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci if (!type) 23562306a36Sopenharmony_ci type = "<NULL>"; 23662306a36Sopenharmony_ci idx = tomoyo_read_lock(); 23762306a36Sopenharmony_ci error = tomoyo_mount_acl(&r, dev_name, path, type, flags); 23862306a36Sopenharmony_ci tomoyo_read_unlock(idx); 23962306a36Sopenharmony_ci return error; 24062306a36Sopenharmony_ci} 241