2 * security/tomoyo/mount.c
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
7 #include <linux/slab.h>
10 /* Keywords for mount restrictions. */
12 /* Allow to call 'mount --bind /source_dir /dest_dir' */
13 #define TOMOYO_MOUNT_BIND_KEYWORD "--bind"
14 /* Allow to call 'mount --move /old_dir /new_dir ' */
15 #define TOMOYO_MOUNT_MOVE_KEYWORD "--move"
16 /* Allow to call 'mount -o remount /dir ' */
17 #define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount"
18 /* Allow to call 'mount --make-unbindable /dir' */
19 #define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable"
20 /* Allow to call 'mount --make-private /dir' */
21 #define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private"
22 /* Allow to call 'mount --make-slave /dir' */
23 #define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave"
24 /* Allow to call 'mount --make-shared /dir' */
25 #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
28 * tomoyo_encode2: Encode binary string to ascii string.
30 * @str: String in binary format.
32 * Returns pointer to @str in ascii format on success, NULL otherwise.
34 * This function uses kzalloc(), so caller must kfree() if this function
37 static char *tomoyo_encode2(const char *str
)
46 const unsigned char c
= *p
++;
49 else if (c
> ' ' && c
< 127)
55 /* Reserve space for appending "/". */
56 cp
= kzalloc(len
+ 10, GFP_NOFS
);
62 const unsigned char c
= *p
++;
66 } else if (c
> ' ' && c
< 127) {
70 *cp
++ = (c
>> 6) + '0';
71 *cp
++ = ((c
>> 3) & 7) + '0';
72 *cp
++ = (c
& 7) + '0';
79 * tomoyo_mount_acl2 - Check permission for mount() operation.
81 * @r: Pointer to "struct tomoyo_request_info".
82 * @dev_name: Name of device file.
83 * @dir: Pointer to "struct path".
84 * @type: Name of filesystem type.
85 * @flags: Mount options.
87 * Returns 0 on success, negative value otherwise.
89 * Caller holds tomoyo_read_lock().
91 static int tomoyo_mount_acl2(struct tomoyo_request_info
*r
, char *dev_name
,
92 struct path
*dir
, char *type
, unsigned long flags
)
95 struct tomoyo_acl_info
*ptr
;
96 struct file_system_type
*fstype
= NULL
;
97 const char *requested_type
= NULL
;
98 const char *requested_dir_name
= NULL
;
99 const char *requested_dev_name
= NULL
;
100 struct tomoyo_path_info rtype
;
101 struct tomoyo_path_info rdev
;
102 struct tomoyo_path_info rdir
;
107 requested_type
= tomoyo_encode2(type
);
110 rtype
.name
= requested_type
;
111 tomoyo_fill_path_info(&rtype
);
113 /* Get mount point. */
114 requested_dir_name
= tomoyo_realpath_from_path(dir
);
115 if (!requested_dir_name
) {
119 rdir
.name
= requested_dir_name
;
120 tomoyo_fill_path_info(&rdir
);
122 /* Compare fs name. */
123 if (!strcmp(type
, TOMOYO_MOUNT_REMOUNT_KEYWORD
)) {
124 /* dev_name is ignored. */
125 } else if (!strcmp(type
, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD
) ||
126 !strcmp(type
, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD
) ||
127 !strcmp(type
, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD
) ||
128 !strcmp(type
, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD
)) {
129 /* dev_name is ignored. */
130 } else if (!strcmp(type
, TOMOYO_MOUNT_BIND_KEYWORD
) ||
131 !strcmp(type
, TOMOYO_MOUNT_MOVE_KEYWORD
)) {
132 need_dev
= -1; /* dev_name is a directory */
134 fstype
= get_fs_type(type
);
139 if (fstype
->fs_flags
& FS_REQUIRES_DEV
)
140 /* dev_name is a block device file. */
144 /* Get mount point or device file. */
145 if (kern_path(dev_name
, LOOKUP_FOLLOW
, &path
)) {
149 requested_dev_name
= tomoyo_realpath_from_path(&path
);
150 if (!requested_dev_name
) {
155 /* Map dev_name to "<NULL>" if no dev_name given. */
158 requested_dev_name
= tomoyo_encode2(dev_name
);
159 if (!requested_dev_name
) {
164 rdev
.name
= requested_dev_name
;
165 tomoyo_fill_path_info(&rdev
);
166 list_for_each_entry_rcu(ptr
, &r
->domain
->acl_info_list
, list
) {
167 struct tomoyo_mount_acl
*acl
;
168 if (ptr
->type
!= TOMOYO_TYPE_MOUNT_ACL
)
170 acl
= container_of(ptr
, struct tomoyo_mount_acl
, head
);
171 if (acl
->is_deleted
||
172 !tomoyo_compare_number_union(flags
, &acl
->flags
) ||
173 !tomoyo_compare_name_union(&rtype
, &acl
->fs_type
) ||
174 !tomoyo_compare_name_union(&rdir
, &acl
->dir_name
) ||
176 !tomoyo_compare_name_union(&rdev
, &acl
->dev_name
)))
182 error
= tomoyo_supervisor(r
, TOMOYO_KEYWORD_ALLOW_MOUNT
184 tomoyo_file_pattern(&rdev
),
185 tomoyo_file_pattern(&rdir
),
186 requested_type
, flags
);
188 kfree(requested_dev_name
);
189 kfree(requested_dir_name
);
191 put_filesystem(fstype
);
192 kfree(requested_type
);
197 * tomoyo_mount_acl - Check permission for mount() operation.
199 * @r: Pointer to "struct tomoyo_request_info".
200 * @dev_name: Name of device file.
201 * @dir: Pointer to "struct path".
202 * @type: Name of filesystem type.
203 * @flags: Mount options.
205 * Returns 0 on success, negative value otherwise.
207 * Caller holds tomoyo_read_lock().
209 static int tomoyo_mount_acl(struct tomoyo_request_info
*r
, char *dev_name
,
210 struct path
*dir
, char *type
, unsigned long flags
)
214 if ((flags
& MS_MGC_MSK
) == MS_MGC_VAL
)
215 flags
&= ~MS_MGC_MSK
;
216 switch (flags
& (MS_REMOUNT
| MS_MOVE
| MS_BIND
)) {
223 printk(KERN_WARNING
"ERROR: "
224 "%s%s%sare given for single mount operation.\n",
225 flags
& MS_REMOUNT
? "'remount' " : "",
226 flags
& MS_MOVE
? "'move' " : "",
227 flags
& MS_BIND
? "'bind' " : "");
230 switch (flags
& (MS_UNBINDABLE
| MS_PRIVATE
| MS_SLAVE
| MS_SHARED
)) {
238 printk(KERN_WARNING
"ERROR: "
239 "%s%s%s%sare given for single mount operation.\n",
240 flags
& MS_UNBINDABLE
? "'unbindable' " : "",
241 flags
& MS_PRIVATE
? "'private' " : "",
242 flags
& MS_SLAVE
? "'slave' " : "",
243 flags
& MS_SHARED
? "'shared' " : "");
246 if (flags
& MS_REMOUNT
)
247 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
248 TOMOYO_MOUNT_REMOUNT_KEYWORD
,
249 flags
& ~MS_REMOUNT
);
250 else if (flags
& MS_MOVE
)
251 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
252 TOMOYO_MOUNT_MOVE_KEYWORD
,
254 else if (flags
& MS_BIND
)
255 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
256 TOMOYO_MOUNT_BIND_KEYWORD
,
258 else if (flags
& MS_UNBINDABLE
)
259 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
260 TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD
,
261 flags
& ~MS_UNBINDABLE
);
262 else if (flags
& MS_PRIVATE
)
263 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
264 TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD
,
265 flags
& ~MS_PRIVATE
);
266 else if (flags
& MS_SLAVE
)
267 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
268 TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD
,
270 else if (flags
& MS_SHARED
)
271 error
= tomoyo_mount_acl(r
, dev_name
, dir
,
272 TOMOYO_MOUNT_MAKE_SHARED_KEYWORD
,
276 error
= tomoyo_mount_acl2(r
, dev_name
, dir
, type
,
278 } while (error
== TOMOYO_RETRY_REQUEST
);
279 if (r
->mode
!= TOMOYO_CONFIG_ENFORCING
)
285 * tomoyo_mount_permission - Check permission for mount() operation.
287 * @dev_name: Name of device file.
288 * @path: Pointer to "struct path".
289 * @type: Name of filesystem type. May be NULL.
290 * @flags: Mount options.
291 * @data_page: Optional data. May be NULL.
293 * Returns 0 on success, negative value otherwise.
295 int tomoyo_mount_permission(char *dev_name
, struct path
*path
, char *type
,
296 unsigned long flags
, void *data_page
)
298 struct tomoyo_request_info r
;
302 if (tomoyo_init_request_info(&r
, NULL
) == TOMOYO_CONFIG_DISABLED
)
306 idx
= tomoyo_read_lock();
307 error
= tomoyo_mount_acl(&r
, dev_name
, path
, type
, flags
);
308 tomoyo_read_unlock(idx
);
313 * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list.
315 * @data: String to parse.
316 * @domain: Pointer to "struct tomoyo_domain_info".
317 * @is_delete: True if it is a delete request.
319 * Returns 0 on success, negative value otherwise.
321 int tomoyo_write_mount_policy(char *data
, struct tomoyo_domain_info
*domain
,
322 const bool is_delete
)
324 struct tomoyo_acl_info
*ptr
;
325 struct tomoyo_mount_acl e
= { .head
.type
= TOMOYO_TYPE_MOUNT_ACL
};
326 int error
= is_delete
? -ENOENT
: -ENOMEM
;
328 if (!tomoyo_tokenize(data
, w
, sizeof(w
)) || !w
[3][0])
330 if (!tomoyo_parse_name_union(w
[0], &e
.dev_name
) ||
331 !tomoyo_parse_name_union(w
[1], &e
.dir_name
) ||
332 !tomoyo_parse_name_union(w
[2], &e
.fs_type
) ||
333 !tomoyo_parse_number_union(w
[3], &e
.flags
))
335 if (mutex_lock_interruptible(&tomoyo_policy_lock
))
337 list_for_each_entry_rcu(ptr
, &domain
->acl_info_list
, list
) {
338 struct tomoyo_mount_acl
*acl
=
339 container_of(ptr
, struct tomoyo_mount_acl
, head
);
340 if (!tomoyo_is_same_mount_acl(acl
, &e
))
342 acl
->is_deleted
= is_delete
;
346 if (!is_delete
&& error
) {
347 struct tomoyo_mount_acl
*entry
=
348 tomoyo_commit_ok(&e
, sizeof(e
));
350 list_add_tail_rcu(&entry
->head
.list
,
351 &domain
->acl_info_list
);
355 mutex_unlock(&tomoyo_policy_lock
);
357 tomoyo_put_name_union(&e
.dev_name
);
358 tomoyo_put_name_union(&e
.dir_name
);
359 tomoyo_put_name_union(&e
.fs_type
);
360 tomoyo_put_number_union(&e
.flags
);