1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
22106ccd9STetsuo Handa /*
32106ccd9STetsuo Handa * security/tomoyo/mount.c
42106ccd9STetsuo Handa *
50f2a55d5STetsuo Handa * Copyright (C) 2005-2011 NTT DATA CORPORATION
62106ccd9STetsuo Handa */
72106ccd9STetsuo Handa
82106ccd9STetsuo Handa #include <linux/slab.h>
9e262e32dSDavid Howells #include <uapi/linux/mount.h>
102106ccd9STetsuo Handa #include "common.h"
112106ccd9STetsuo Handa
12b5bc60b4STetsuo Handa /* String table for special mount operations. */
13b5bc60b4STetsuo Handa static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = {
14b5bc60b4STetsuo Handa [TOMOYO_MOUNT_BIND] = "--bind",
15b5bc60b4STetsuo Handa [TOMOYO_MOUNT_MOVE] = "--move",
16b5bc60b4STetsuo Handa [TOMOYO_MOUNT_REMOUNT] = "--remount",
17b5bc60b4STetsuo Handa [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
18b5bc60b4STetsuo Handa [TOMOYO_MOUNT_MAKE_PRIVATE] = "--make-private",
19b5bc60b4STetsuo Handa [TOMOYO_MOUNT_MAKE_SLAVE] = "--make-slave",
20b5bc60b4STetsuo Handa [TOMOYO_MOUNT_MAKE_SHARED] = "--make-shared",
21b5bc60b4STetsuo Handa };
222106ccd9STetsuo Handa
232106ccd9STetsuo Handa /**
2499a85259STetsuo Handa * tomoyo_audit_mount_log - Audit mount log.
2599a85259STetsuo Handa *
2699a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info".
2799a85259STetsuo Handa *
2899a85259STetsuo Handa * Returns 0 on success, negative value otherwise.
2999a85259STetsuo Handa */
tomoyo_audit_mount_log(struct tomoyo_request_info * r)3099a85259STetsuo Handa static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
3199a85259STetsuo Handa {
32eadd99ccSTetsuo Handa return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n",
337c75964fSTetsuo Handa r->param.mount.dev->name,
34eadd99ccSTetsuo Handa r->param.mount.dir->name,
35eadd99ccSTetsuo Handa r->param.mount.type->name,
36eadd99ccSTetsuo Handa r->param.mount.flags);
3799a85259STetsuo Handa }
3899a85259STetsuo Handa
390df7e8b8STetsuo Handa /**
400df7e8b8STetsuo Handa * tomoyo_check_mount_acl - Check permission for path path path number operation.
410df7e8b8STetsuo Handa *
420df7e8b8STetsuo Handa * @r: Pointer to "struct tomoyo_request_info".
430df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_acl_info".
440df7e8b8STetsuo Handa *
450df7e8b8STetsuo Handa * Returns true if granted, false otherwise.
460df7e8b8STetsuo Handa */
tomoyo_check_mount_acl(struct tomoyo_request_info * r,const struct tomoyo_acl_info * ptr)47484ca79cSTetsuo Handa static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
4899a85259STetsuo Handa const struct tomoyo_acl_info *ptr)
4999a85259STetsuo Handa {
5099a85259STetsuo Handa const struct tomoyo_mount_acl *acl =
5199a85259STetsuo Handa container_of(ptr, typeof(*acl), head);
52*cdcf6723STetsuo Handa
530df7e8b8STetsuo Handa return tomoyo_compare_number_union(r->param.mount.flags,
540df7e8b8STetsuo Handa &acl->flags) &&
550df7e8b8STetsuo Handa tomoyo_compare_name_union(r->param.mount.type,
560df7e8b8STetsuo Handa &acl->fs_type) &&
570df7e8b8STetsuo Handa tomoyo_compare_name_union(r->param.mount.dir,
580df7e8b8STetsuo Handa &acl->dir_name) &&
5999a85259STetsuo Handa (!r->param.mount.need_dev ||
600df7e8b8STetsuo Handa tomoyo_compare_name_union(r->param.mount.dev,
610df7e8b8STetsuo Handa &acl->dev_name));
6299a85259STetsuo Handa }
6399a85259STetsuo Handa
6499a85259STetsuo Handa /**
65d795ef9eSTetsuo Handa * tomoyo_mount_acl - Check permission for mount() operation.
662106ccd9STetsuo Handa *
672106ccd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info".
680f2a55d5STetsuo Handa * @dev_name: Name of device file. Maybe NULL.
692106ccd9STetsuo Handa * @dir: Pointer to "struct path".
702106ccd9STetsuo Handa * @type: Name of filesystem type.
712106ccd9STetsuo Handa * @flags: Mount options.
722106ccd9STetsuo Handa *
732106ccd9STetsuo Handa * Returns 0 on success, negative value otherwise.
742106ccd9STetsuo Handa *
752106ccd9STetsuo Handa * Caller holds tomoyo_read_lock().
762106ccd9STetsuo Handa */
tomoyo_mount_acl(struct tomoyo_request_info * r,const char * dev_name,const struct path * dir,const char * type,unsigned long flags)77808d4e3cSAl Viro static int tomoyo_mount_acl(struct tomoyo_request_info *r,
78808d4e3cSAl Viro const char *dev_name,
79e6641eddSAl Viro const struct path *dir, const char *type,
80b5bc60b4STetsuo Handa unsigned long flags)
812106ccd9STetsuo Handa {
8297fb35e4STetsuo Handa struct tomoyo_obj_info obj = { };
832106ccd9STetsuo Handa struct path path;
842106ccd9STetsuo Handa struct file_system_type *fstype = NULL;
852106ccd9STetsuo Handa const char *requested_type = NULL;
862106ccd9STetsuo Handa const char *requested_dir_name = NULL;
872106ccd9STetsuo Handa const char *requested_dev_name = NULL;
882106ccd9STetsuo Handa struct tomoyo_path_info rtype;
892106ccd9STetsuo Handa struct tomoyo_path_info rdev;
902106ccd9STetsuo Handa struct tomoyo_path_info rdir;
912106ccd9STetsuo Handa int need_dev = 0;
922106ccd9STetsuo Handa int error = -ENOMEM;
93*cdcf6723STetsuo Handa
9497fb35e4STetsuo Handa r->obj = &obj;
952106ccd9STetsuo Handa
962106ccd9STetsuo Handa /* Get fstype. */
97c8c57e84STetsuo Handa requested_type = tomoyo_encode(type);
982106ccd9STetsuo Handa if (!requested_type)
992106ccd9STetsuo Handa goto out;
1002106ccd9STetsuo Handa rtype.name = requested_type;
1012106ccd9STetsuo Handa tomoyo_fill_path_info(&rtype);
1022106ccd9STetsuo Handa
1032106ccd9STetsuo Handa /* Get mount point. */
10497fb35e4STetsuo Handa obj.path2 = *dir;
1052106ccd9STetsuo Handa requested_dir_name = tomoyo_realpath_from_path(dir);
1062106ccd9STetsuo Handa if (!requested_dir_name) {
1072106ccd9STetsuo Handa error = -ENOMEM;
1082106ccd9STetsuo Handa goto out;
1092106ccd9STetsuo Handa }
1102106ccd9STetsuo Handa rdir.name = requested_dir_name;
1112106ccd9STetsuo Handa tomoyo_fill_path_info(&rdir);
1122106ccd9STetsuo Handa
1132106ccd9STetsuo Handa /* Compare fs name. */
114b5bc60b4STetsuo Handa if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) {
1152106ccd9STetsuo Handa /* dev_name is ignored. */
116b5bc60b4STetsuo Handa } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] ||
117b5bc60b4STetsuo Handa type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] ||
118b5bc60b4STetsuo Handa type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] ||
119b5bc60b4STetsuo Handa type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) {
1202106ccd9STetsuo Handa /* dev_name is ignored. */
121b5bc60b4STetsuo Handa } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] ||
122b5bc60b4STetsuo Handa type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) {
1232106ccd9STetsuo Handa need_dev = -1; /* dev_name is a directory */
1242106ccd9STetsuo Handa } else {
1252106ccd9STetsuo Handa fstype = get_fs_type(type);
1262106ccd9STetsuo Handa if (!fstype) {
1272106ccd9STetsuo Handa error = -ENODEV;
1282106ccd9STetsuo Handa goto out;
1292106ccd9STetsuo Handa }
1302106ccd9STetsuo Handa if (fstype->fs_flags & FS_REQUIRES_DEV)
1312106ccd9STetsuo Handa /* dev_name is a block device file. */
1322106ccd9STetsuo Handa need_dev = 1;
1332106ccd9STetsuo Handa }
1342106ccd9STetsuo Handa if (need_dev) {
1352106ccd9STetsuo Handa /* Get mount point or device file. */
1364e78c724STetsuo Handa if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
1372106ccd9STetsuo Handa error = -ENOENT;
1382106ccd9STetsuo Handa goto out;
1392106ccd9STetsuo Handa }
14097fb35e4STetsuo Handa obj.path1 = path;
1412106ccd9STetsuo Handa requested_dev_name = tomoyo_realpath_from_path(&path);
1422106ccd9STetsuo Handa if (!requested_dev_name) {
1432106ccd9STetsuo Handa error = -ENOENT;
1442106ccd9STetsuo Handa goto out;
1452106ccd9STetsuo Handa }
1462106ccd9STetsuo Handa } else {
1472106ccd9STetsuo Handa /* Map dev_name to "<NULL>" if no dev_name given. */
1482106ccd9STetsuo Handa if (!dev_name)
1492106ccd9STetsuo Handa dev_name = "<NULL>";
150c8c57e84STetsuo Handa requested_dev_name = tomoyo_encode(dev_name);
1512106ccd9STetsuo Handa if (!requested_dev_name) {
1522106ccd9STetsuo Handa error = -ENOMEM;
1532106ccd9STetsuo Handa goto out;
1542106ccd9STetsuo Handa }
1552106ccd9STetsuo Handa }
1562106ccd9STetsuo Handa rdev.name = requested_dev_name;
1572106ccd9STetsuo Handa tomoyo_fill_path_info(&rdev);
158cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_MOUNT_ACL;
159cf6e9a64STetsuo Handa r->param.mount.need_dev = need_dev;
160cf6e9a64STetsuo Handa r->param.mount.dev = &rdev;
161cf6e9a64STetsuo Handa r->param.mount.dir = &rdir;
162cf6e9a64STetsuo Handa r->param.mount.type = &rtype;
163cf6e9a64STetsuo Handa r->param.mount.flags = flags;
16499a85259STetsuo Handa do {
16599a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_mount_acl);
16699a85259STetsuo Handa error = tomoyo_audit_mount_log(r);
16799a85259STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST);
1682106ccd9STetsuo Handa out:
1692106ccd9STetsuo Handa kfree(requested_dev_name);
1702106ccd9STetsuo Handa kfree(requested_dir_name);
1712106ccd9STetsuo Handa if (fstype)
1722106ccd9STetsuo Handa put_filesystem(fstype);
1732106ccd9STetsuo Handa kfree(requested_type);
17497fb35e4STetsuo Handa /* Drop refcount obtained by kern_path(). */
17597fb35e4STetsuo Handa if (obj.path1.dentry)
17697fb35e4STetsuo Handa path_put(&obj.path1);
1772106ccd9STetsuo Handa return error;
1782106ccd9STetsuo Handa }
1792106ccd9STetsuo Handa
1802106ccd9STetsuo Handa /**
1812106ccd9STetsuo Handa * tomoyo_mount_permission - Check permission for mount() operation.
1822106ccd9STetsuo Handa *
1830f2a55d5STetsuo Handa * @dev_name: Name of device file. Maybe NULL.
1842106ccd9STetsuo Handa * @path: Pointer to "struct path".
1852106ccd9STetsuo Handa * @type: Name of filesystem type. Maybe NULL.
1862106ccd9STetsuo Handa * @flags: Mount options.
1872106ccd9STetsuo Handa * @data_page: Optional data. Maybe NULL.
1882106ccd9STetsuo Handa *
1892106ccd9STetsuo Handa * Returns 0 on success, negative value otherwise.
1902106ccd9STetsuo Handa */
tomoyo_mount_permission(const char * dev_name,const struct path * path,const char * type,unsigned long flags,void * data_page)191e6641eddSAl Viro int tomoyo_mount_permission(const char *dev_name, const struct path *path,
192b5bc60b4STetsuo Handa const char *type, unsigned long flags,
193b5bc60b4STetsuo Handa void *data_page)
1942106ccd9STetsuo Handa {
1952106ccd9STetsuo Handa struct tomoyo_request_info r;
1962106ccd9STetsuo Handa int error;
1972106ccd9STetsuo Handa int idx;
1982106ccd9STetsuo Handa
19957c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
20057c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED)
2012106ccd9STetsuo Handa return 0;
202d795ef9eSTetsuo Handa if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
203d795ef9eSTetsuo Handa flags &= ~MS_MGC_MSK;
204d795ef9eSTetsuo Handa if (flags & MS_REMOUNT) {
205b5bc60b4STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
206d795ef9eSTetsuo Handa flags &= ~MS_REMOUNT;
207df91e494STetsuo Handa } else if (flags & MS_BIND) {
208b5bc60b4STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
209d795ef9eSTetsuo Handa flags &= ~MS_BIND;
210df91e494STetsuo Handa } else if (flags & MS_SHARED) {
211df91e494STetsuo Handa if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
212df91e494STetsuo Handa return -EINVAL;
213b5bc60b4STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
214d795ef9eSTetsuo Handa flags &= ~MS_SHARED;
215df91e494STetsuo Handa } else if (flags & MS_PRIVATE) {
216df91e494STetsuo Handa if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
217df91e494STetsuo Handa return -EINVAL;
218df91e494STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
219df91e494STetsuo Handa flags &= ~MS_PRIVATE;
220df91e494STetsuo Handa } else if (flags & MS_SLAVE) {
221df91e494STetsuo Handa if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
222df91e494STetsuo Handa return -EINVAL;
223df91e494STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
224df91e494STetsuo Handa flags &= ~MS_SLAVE;
225df91e494STetsuo Handa } else if (flags & MS_UNBINDABLE) {
226df91e494STetsuo Handa if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
227df91e494STetsuo Handa return -EINVAL;
228df91e494STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
229df91e494STetsuo Handa flags &= ~MS_UNBINDABLE;
230df91e494STetsuo Handa } else if (flags & MS_MOVE) {
231df91e494STetsuo Handa type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
232df91e494STetsuo Handa flags &= ~MS_MOVE;
233d795ef9eSTetsuo Handa }
2342106ccd9STetsuo Handa if (!type)
2352106ccd9STetsuo Handa type = "<NULL>";
2362106ccd9STetsuo Handa idx = tomoyo_read_lock();
2372106ccd9STetsuo Handa error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
2382106ccd9STetsuo Handa tomoyo_read_unlock(idx);
2392106ccd9STetsuo Handa return error;
2402106ccd9STetsuo Handa }
241