xref: /openbmc/linux/security/tomoyo/mount.c (revision 565485b8)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * security/tomoyo/mount.c
4  *
5  * Copyright (C) 2005-2011  NTT DATA CORPORATION
6  */
7 
8 #include <linux/slab.h>
9 #include <uapi/linux/mount.h>
10 #include "common.h"
11 
12 /* String table for special mount operations. */
13 static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = {
14 	[TOMOYO_MOUNT_BIND]            = "--bind",
15 	[TOMOYO_MOUNT_MOVE]            = "--move",
16 	[TOMOYO_MOUNT_REMOUNT]         = "--remount",
17 	[TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
18 	[TOMOYO_MOUNT_MAKE_PRIVATE]    = "--make-private",
19 	[TOMOYO_MOUNT_MAKE_SLAVE]      = "--make-slave",
20 	[TOMOYO_MOUNT_MAKE_SHARED]     = "--make-shared",
21 };
22 
23 /**
24  * tomoyo_audit_mount_log - Audit mount log.
25  *
26  * @r: Pointer to "struct tomoyo_request_info".
27  *
28  * Returns 0 on success, negative value otherwise.
29  */
30 static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
31 {
32 	return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n",
33 				 r->param.mount.dev->name,
34 				 r->param.mount.dir->name,
35 				 r->param.mount.type->name,
36 				 r->param.mount.flags);
37 }
38 
39 /**
40  * tomoyo_check_mount_acl - Check permission for path path path number operation.
41  *
42  * @r:   Pointer to "struct tomoyo_request_info".
43  * @ptr: Pointer to "struct tomoyo_acl_info".
44  *
45  * Returns true if granted, false otherwise.
46  */
47 static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
48 				   const struct tomoyo_acl_info *ptr)
49 {
50 	const struct tomoyo_mount_acl *acl =
51 		container_of(ptr, typeof(*acl), head);
52 	return tomoyo_compare_number_union(r->param.mount.flags,
53 					   &acl->flags) &&
54 		tomoyo_compare_name_union(r->param.mount.type,
55 					  &acl->fs_type) &&
56 		tomoyo_compare_name_union(r->param.mount.dir,
57 					  &acl->dir_name) &&
58 		(!r->param.mount.need_dev ||
59 		 tomoyo_compare_name_union(r->param.mount.dev,
60 					   &acl->dev_name));
61 }
62 
63 /**
64  * tomoyo_mount_acl - Check permission for mount() operation.
65  *
66  * @r:        Pointer to "struct tomoyo_request_info".
67  * @dev_name: Name of device file. Maybe NULL.
68  * @dir:      Pointer to "struct path".
69  * @type:     Name of filesystem type.
70  * @flags:    Mount options.
71  *
72  * Returns 0 on success, negative value otherwise.
73  *
74  * Caller holds tomoyo_read_lock().
75  */
76 static int tomoyo_mount_acl(struct tomoyo_request_info *r,
77 			    const char *dev_name,
78 			    const struct path *dir, const char *type,
79 			    unsigned long flags)
80 {
81 	struct tomoyo_obj_info obj = { };
82 	struct path path;
83 	struct file_system_type *fstype = NULL;
84 	const char *requested_type = NULL;
85 	const char *requested_dir_name = NULL;
86 	const char *requested_dev_name = NULL;
87 	struct tomoyo_path_info rtype;
88 	struct tomoyo_path_info rdev;
89 	struct tomoyo_path_info rdir;
90 	int need_dev = 0;
91 	int error = -ENOMEM;
92 	r->obj = &obj;
93 
94 	/* Get fstype. */
95 	requested_type = tomoyo_encode(type);
96 	if (!requested_type)
97 		goto out;
98 	rtype.name = requested_type;
99 	tomoyo_fill_path_info(&rtype);
100 
101 	/* Get mount point. */
102 	obj.path2 = *dir;
103 	requested_dir_name = tomoyo_realpath_from_path(dir);
104 	if (!requested_dir_name) {
105 		error = -ENOMEM;
106 		goto out;
107 	}
108 	rdir.name = requested_dir_name;
109 	tomoyo_fill_path_info(&rdir);
110 
111 	/* Compare fs name. */
112 	if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) {
113 		/* dev_name is ignored. */
114 	} else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] ||
115 		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] ||
116 		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] ||
117 		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) {
118 		/* dev_name is ignored. */
119 	} else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] ||
120 		   type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) {
121 		need_dev = -1; /* dev_name is a directory */
122 	} else {
123 		fstype = get_fs_type(type);
124 		if (!fstype) {
125 			error = -ENODEV;
126 			goto out;
127 		}
128 		if (fstype->fs_flags & FS_REQUIRES_DEV)
129 			/* dev_name is a block device file. */
130 			need_dev = 1;
131 	}
132 	if (need_dev) {
133 		/* Get mount point or device file. */
134 		if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
135 			error = -ENOENT;
136 			goto out;
137 		}
138 		obj.path1 = path;
139 		requested_dev_name = tomoyo_realpath_from_path(&path);
140 		if (!requested_dev_name) {
141 			error = -ENOENT;
142 			goto out;
143 		}
144 	} else {
145 		/* Map dev_name to "<NULL>" if no dev_name given. */
146 		if (!dev_name)
147 			dev_name = "<NULL>";
148 		requested_dev_name = tomoyo_encode(dev_name);
149 		if (!requested_dev_name) {
150 			error = -ENOMEM;
151 			goto out;
152 		}
153 	}
154 	rdev.name = requested_dev_name;
155 	tomoyo_fill_path_info(&rdev);
156 	r->param_type = TOMOYO_TYPE_MOUNT_ACL;
157 	r->param.mount.need_dev = need_dev;
158 	r->param.mount.dev = &rdev;
159 	r->param.mount.dir = &rdir;
160 	r->param.mount.type = &rtype;
161 	r->param.mount.flags = flags;
162 	do {
163 		tomoyo_check_acl(r, tomoyo_check_mount_acl);
164 		error = tomoyo_audit_mount_log(r);
165 	} while (error == TOMOYO_RETRY_REQUEST);
166  out:
167 	kfree(requested_dev_name);
168 	kfree(requested_dir_name);
169 	if (fstype)
170 		put_filesystem(fstype);
171 	kfree(requested_type);
172 	/* Drop refcount obtained by kern_path(). */
173 	if (obj.path1.dentry)
174 		path_put(&obj.path1);
175 	return error;
176 }
177 
178 /**
179  * tomoyo_mount_permission - Check permission for mount() operation.
180  *
181  * @dev_name:  Name of device file. Maybe NULL.
182  * @path:      Pointer to "struct path".
183  * @type:      Name of filesystem type. Maybe NULL.
184  * @flags:     Mount options.
185  * @data_page: Optional data. Maybe NULL.
186  *
187  * Returns 0 on success, negative value otherwise.
188  */
189 int tomoyo_mount_permission(const char *dev_name, const struct path *path,
190 			    const char *type, unsigned long flags,
191 			    void *data_page)
192 {
193 	struct tomoyo_request_info r;
194 	int error;
195 	int idx;
196 
197 	if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
198 	    == TOMOYO_CONFIG_DISABLED)
199 		return 0;
200 	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
201 		flags &= ~MS_MGC_MSK;
202 	if (flags & MS_REMOUNT) {
203 		type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
204 		flags &= ~MS_REMOUNT;
205 	} else if (flags & MS_BIND) {
206 		type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
207 		flags &= ~MS_BIND;
208 	} else if (flags & MS_SHARED) {
209 		if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
210 			return -EINVAL;
211 		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
212 		flags &= ~MS_SHARED;
213 	} else if (flags & MS_PRIVATE) {
214 		if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
215 			return -EINVAL;
216 		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
217 		flags &= ~MS_PRIVATE;
218 	} else if (flags & MS_SLAVE) {
219 		if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
220 			return -EINVAL;
221 		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
222 		flags &= ~MS_SLAVE;
223 	} else if (flags & MS_UNBINDABLE) {
224 		if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
225 			return -EINVAL;
226 		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
227 		flags &= ~MS_UNBINDABLE;
228 	} else if (flags & MS_MOVE) {
229 		type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
230 		flags &= ~MS_MOVE;
231 	}
232 	if (!type)
233 		type = "<NULL>";
234 	idx = tomoyo_read_lock();
235 	error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
236 	tomoyo_read_unlock(idx);
237 	return error;
238 }
239