]> asedeno.scripts.mit.edu Git - linux.git/blob - security/tomoyo/mount.c
Merge tag 'stm32-dt-for-v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / security / tomoyo / mount.c
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 }