file.c revision 0df7e8b8f1c25c10820bdc679555f2fbfb897ca0
1/*
2 * security/tomoyo/file.c
3 *
4 * Pathname restriction functions.
5 *
6 * Copyright (C) 2005-2010  NTT DATA CORPORATION
7 */
8
9#include "common.h"
10#include <linux/slab.h>
11
12/* Keyword array for operations with one pathname. */
13const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
14	[TOMOYO_TYPE_EXECUTE]    = "execute",
15	[TOMOYO_TYPE_READ]       = "read",
16	[TOMOYO_TYPE_WRITE]      = "write",
17	[TOMOYO_TYPE_APPEND]     = "append",
18	[TOMOYO_TYPE_UNLINK]     = "unlink",
19	[TOMOYO_TYPE_GETATTR]    = "getattr",
20	[TOMOYO_TYPE_RMDIR]      = "rmdir",
21	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
22	[TOMOYO_TYPE_SYMLINK]    = "symlink",
23	[TOMOYO_TYPE_CHROOT]     = "chroot",
24	[TOMOYO_TYPE_UMOUNT]     = "unmount",
25};
26
27/* Keyword array for operations with one pathname and three numbers. */
28const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
29	[TOMOYO_TYPE_MKBLOCK]    = "mkblock",
30	[TOMOYO_TYPE_MKCHAR]     = "mkchar",
31};
32
33/* Keyword array for operations with two pathnames. */
34const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
35	[TOMOYO_TYPE_LINK]       = "link",
36	[TOMOYO_TYPE_RENAME]     = "rename",
37	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
38};
39
40/* Keyword array for operations with one pathname and one number. */
41const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
42	[TOMOYO_TYPE_CREATE]     = "create",
43	[TOMOYO_TYPE_MKDIR]      = "mkdir",
44	[TOMOYO_TYPE_MKFIFO]     = "mkfifo",
45	[TOMOYO_TYPE_MKSOCK]     = "mksock",
46	[TOMOYO_TYPE_IOCTL]      = "ioctl",
47	[TOMOYO_TYPE_CHMOD]      = "chmod",
48	[TOMOYO_TYPE_CHOWN]      = "chown",
49	[TOMOYO_TYPE_CHGRP]      = "chgrp",
50};
51
52/*
53 * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
54 */
55static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
56	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
57	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
58	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
59	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
60	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
61	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
62	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
63	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
64	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
65	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
66	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
67};
68
69/*
70 * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
71 */
72static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
73	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
74	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
75};
76
77/*
78 * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
79 */
80static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
81	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
82	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
83	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
84};
85
86/*
87 * Mapping table from "enum tomoyo_path_number_acl_index" to
88 * "enum tomoyo_mac_index".
89 */
90static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
91	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
92	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
93	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
94	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
95	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
96	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
97	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
98	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
99};
100
101/**
102 * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
103 *
104 * @ptr: Pointer to "struct tomoyo_name_union".
105 *
106 * Returns nothing.
107 */
108void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
109{
110	tomoyo_put_group(ptr->group);
111	tomoyo_put_name(ptr->filename);
112}
113
114/**
115 * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
116 *
117 * @name: Pointer to "struct tomoyo_path_info".
118 * @ptr:  Pointer to "struct tomoyo_name_union".
119 *
120 * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
121 */
122const struct tomoyo_path_info *
123tomoyo_compare_name_union(const struct tomoyo_path_info *name,
124			  const struct tomoyo_name_union *ptr)
125{
126	if (ptr->group)
127		return tomoyo_path_matches_group(name, ptr->group);
128	if (tomoyo_path_matches_pattern(name, ptr->filename))
129		return ptr->filename;
130	return NULL;
131}
132
133/**
134 * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
135 *
136 * @ptr: Pointer to "struct tomoyo_number_union".
137 *
138 * Returns nothing.
139 */
140void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
141{
142	tomoyo_put_group(ptr->group);
143}
144
145/**
146 * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
147 *
148 * @value: Number to check.
149 * @ptr:   Pointer to "struct tomoyo_number_union".
150 *
151 * Returns true if @value matches @ptr, false otherwise.
152 */
153bool tomoyo_compare_number_union(const unsigned long value,
154				 const struct tomoyo_number_union *ptr)
155{
156	if (ptr->group)
157		return tomoyo_number_matches_group(value, value, ptr->group);
158	return value >= ptr->values[0] && value <= ptr->values[1];
159}
160
161/**
162 * tomoyo_add_slash - Add trailing '/' if needed.
163 *
164 * @buf: Pointer to "struct tomoyo_path_info".
165 *
166 * Returns nothing.
167 *
168 * @buf must be generated by tomoyo_encode() because this function does not
169 * allocate memory for adding '/'.
170 */
171static void tomoyo_add_slash(struct tomoyo_path_info *buf)
172{
173	if (buf->is_dir)
174		return;
175	/*
176	 * This is OK because tomoyo_encode() reserves space for appending "/".
177	 */
178	strcat((char *) buf->name, "/");
179	tomoyo_fill_path_info(buf);
180}
181
182/**
183 * tomoyo_get_realpath - Get realpath.
184 *
185 * @buf:  Pointer to "struct tomoyo_path_info".
186 * @path: Pointer to "struct path".
187 *
188 * Returns true on success, false otherwise.
189 */
190static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
191{
192	buf->name = tomoyo_realpath_from_path(path);
193	if (buf->name) {
194		tomoyo_fill_path_info(buf);
195		return true;
196	}
197        return false;
198}
199
200/**
201 * tomoyo_audit_path_log - Audit path request log.
202 *
203 * @r: Pointer to "struct tomoyo_request_info".
204 *
205 * Returns 0 on success, negative value otherwise.
206 */
207static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
208{
209	const char *operation = tomoyo_path_keyword[r->param.path.operation];
210	const struct tomoyo_path_info *filename = r->param.path.filename;
211	if (r->granted)
212		return 0;
213	tomoyo_warn_log(r, "%s %s", operation, filename->name);
214	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
215				 filename->name);
216}
217
218/**
219 * tomoyo_audit_path2_log - Audit path/path request log.
220 *
221 * @r: Pointer to "struct tomoyo_request_info".
222 *
223 * Returns 0 on success, negative value otherwise.
224 */
225static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
226{
227	const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
228	const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
229	const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
230	if (r->granted)
231		return 0;
232	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
233			filename2->name);
234	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
235				 filename1->name, filename2->name);
236}
237
238/**
239 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
240 *
241 * @r: Pointer to "struct tomoyo_request_info".
242 *
243 * Returns 0 on success, negative value otherwise.
244 */
245static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
246{
247	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
248	const struct tomoyo_path_info *filename = r->param.mkdev.filename;
249	const unsigned int major = r->param.mkdev.major;
250	const unsigned int minor = r->param.mkdev.minor;
251	const unsigned int mode = r->param.mkdev.mode;
252	if (r->granted)
253		return 0;
254	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
255			major, minor);
256	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
257				 filename->name, mode, major, minor);
258}
259
260/**
261 * tomoyo_audit_path_number_log - Audit path/number request log.
262 *
263 * @r: Pointer to "struct tomoyo_request_info".
264 *
265 * Returns 0 on success, negative value otherwise.
266 */
267static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
268{
269	const u8 type = r->param.path_number.operation;
270	u8 radix;
271	const struct tomoyo_path_info *filename = r->param.path_number.filename;
272	const char *operation = tomoyo_path_number_keyword[type];
273	char buffer[64];
274	if (r->granted)
275		return 0;
276	switch (type) {
277	case TOMOYO_TYPE_CREATE:
278	case TOMOYO_TYPE_MKDIR:
279	case TOMOYO_TYPE_MKFIFO:
280	case TOMOYO_TYPE_MKSOCK:
281	case TOMOYO_TYPE_CHMOD:
282		radix = TOMOYO_VALUE_TYPE_OCTAL;
283		break;
284	case TOMOYO_TYPE_IOCTL:
285		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
286		break;
287	default:
288		radix = TOMOYO_VALUE_TYPE_DECIMAL;
289		break;
290	}
291	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
292			   radix);
293	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
294	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
295				 filename->name, buffer);
296}
297
298/**
299 * tomoyo_check_path_acl - Check permission for path operation.
300 *
301 * @r:   Pointer to "struct tomoyo_request_info".
302 * @ptr: Pointer to "struct tomoyo_acl_info".
303 *
304 * Returns true if granted, false otherwise.
305 *
306 * To be able to use wildcard for domain transition, this function sets
307 * matching entry on success. Since the caller holds tomoyo_read_lock(),
308 * it is safe to set matching entry.
309 */
310static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
311				  const struct tomoyo_acl_info *ptr)
312{
313	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
314							 head);
315	if (acl->perm & (1 << r->param.path.operation)) {
316		r->param.path.matched_path =
317			tomoyo_compare_name_union(r->param.path.filename,
318						  &acl->name);
319		return r->param.path.matched_path != NULL;
320	}
321	return false;
322}
323
324/**
325 * tomoyo_check_path_number_acl - Check permission for path number operation.
326 *
327 * @r:   Pointer to "struct tomoyo_request_info".
328 * @ptr: Pointer to "struct tomoyo_acl_info".
329 *
330 * Returns true if granted, false otherwise.
331 */
332static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
333					 const struct tomoyo_acl_info *ptr)
334{
335	const struct tomoyo_path_number_acl *acl =
336		container_of(ptr, typeof(*acl), head);
337	return (acl->perm & (1 << r->param.path_number.operation)) &&
338		tomoyo_compare_number_union(r->param.path_number.number,
339					    &acl->number) &&
340		tomoyo_compare_name_union(r->param.path_number.filename,
341					  &acl->name);
342}
343
344/**
345 * tomoyo_check_path2_acl - Check permission for path path operation.
346 *
347 * @r:   Pointer to "struct tomoyo_request_info".
348 * @ptr: Pointer to "struct tomoyo_acl_info".
349 *
350 * Returns true if granted, false otherwise.
351 */
352static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
353				   const struct tomoyo_acl_info *ptr)
354{
355	const struct tomoyo_path2_acl *acl =
356		container_of(ptr, typeof(*acl), head);
357	return (acl->perm & (1 << r->param.path2.operation)) &&
358		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
359		&& tomoyo_compare_name_union(r->param.path2.filename2,
360					     &acl->name2);
361}
362
363/**
364 * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
365 *
366 * @r:   Pointer to "struct tomoyo_request_info".
367 * @ptr: Pointer to "struct tomoyo_acl_info".
368 *
369 * Returns true if granted, false otherwise.
370 */
371static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
372				   const struct tomoyo_acl_info *ptr)
373{
374	const struct tomoyo_mkdev_acl *acl =
375		container_of(ptr, typeof(*acl), head);
376	return (acl->perm & (1 << r->param.mkdev.operation)) &&
377		tomoyo_compare_number_union(r->param.mkdev.mode,
378					    &acl->mode) &&
379		tomoyo_compare_number_union(r->param.mkdev.major,
380					    &acl->major) &&
381		tomoyo_compare_number_union(r->param.mkdev.minor,
382					    &acl->minor) &&
383		tomoyo_compare_name_union(r->param.mkdev.filename,
384					  &acl->name);
385}
386
387/**
388 * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
389 *
390 * @a: Pointer to "struct tomoyo_acl_info".
391 * @b: Pointer to "struct tomoyo_acl_info".
392 *
393 * Returns true if @a == @b except permission bits, false otherwise.
394 */
395static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
396				 const struct tomoyo_acl_info *b)
397{
398	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
399	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
400	return tomoyo_same_name_union(&p1->name, &p2->name);
401}
402
403/**
404 * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
405 *
406 * @a:         Pointer to "struct tomoyo_acl_info".
407 * @b:         Pointer to "struct tomoyo_acl_info".
408 * @is_delete: True for @a &= ~@b, false for @a |= @b.
409 *
410 * Returns true if @a is empty, false otherwise.
411 */
412static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
413				  struct tomoyo_acl_info *b,
414				  const bool is_delete)
415{
416	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
417		->perm;
418	u16 perm = *a_perm;
419	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
420	if (is_delete)
421		perm &= ~b_perm;
422	else
423		perm |= b_perm;
424	*a_perm = perm;
425	return !perm;
426}
427
428/**
429 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
430 *
431 * @type:      Type of operation.
432 * @filename:  Filename.
433 * @domain:    Pointer to "struct tomoyo_domain_info".
434 * @is_delete: True if it is a delete request.
435 *
436 * Returns 0 on success, negative value otherwise.
437 *
438 * Caller holds tomoyo_read_lock().
439 */
440static int tomoyo_update_path_acl(const u8 type, const char *filename,
441				  struct tomoyo_domain_info * const domain,
442				  const bool is_delete)
443{
444	struct tomoyo_path_acl e = {
445		.head.type = TOMOYO_TYPE_PATH_ACL,
446		.perm = 1 << type
447	};
448	int error;
449	if (!tomoyo_parse_name_union(filename, &e.name))
450		return -EINVAL;
451	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
452				     tomoyo_same_path_acl,
453				     tomoyo_merge_path_acl);
454	tomoyo_put_name_union(&e.name);
455	return error;
456}
457
458/**
459 * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
460 *
461 * @a: Pointer to "struct tomoyo_acl_info".
462 * @b: Pointer to "struct tomoyo_acl_info".
463 *
464 * Returns true if @a == @b except permission bits, false otherwise.
465 */
466static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
467					 const struct tomoyo_acl_info *b)
468{
469	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
470	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
471	return tomoyo_same_name_union(&p1->name, &p2->name) &&
472		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
473		tomoyo_same_number_union(&p1->major, &p2->major) &&
474		tomoyo_same_number_union(&p1->minor, &p2->minor);
475}
476
477/**
478 * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
479 *
480 * @a:         Pointer to "struct tomoyo_acl_info".
481 * @b:         Pointer to "struct tomoyo_acl_info".
482 * @is_delete: True for @a &= ~@b, false for @a |= @b.
483 *
484 * Returns true if @a is empty, false otherwise.
485 */
486static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
487				   struct tomoyo_acl_info *b,
488				   const bool is_delete)
489{
490	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
491					 head)->perm;
492	u8 perm = *a_perm;
493	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
494		->perm;
495	if (is_delete)
496		perm &= ~b_perm;
497	else
498		perm |= b_perm;
499	*a_perm = perm;
500	return !perm;
501}
502
503/**
504 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
505 *
506 * @type:      Type of operation.
507 * @filename:  Filename.
508 * @mode:      Create mode.
509 * @major:     Device major number.
510 * @minor:     Device minor number.
511 * @domain:    Pointer to "struct tomoyo_domain_info".
512 * @is_delete: True if it is a delete request.
513 *
514 * Returns 0 on success, negative value otherwise.
515 *
516 * Caller holds tomoyo_read_lock().
517 */
518static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
519				   char *mode, char *major, char *minor,
520				   struct tomoyo_domain_info * const domain,
521				   const bool is_delete)
522{
523	struct tomoyo_mkdev_acl e = {
524		.head.type = TOMOYO_TYPE_MKDEV_ACL,
525		.perm = 1 << type
526	};
527	int error = is_delete ? -ENOENT : -ENOMEM;
528	if (!tomoyo_parse_name_union(filename, &e.name) ||
529	    !tomoyo_parse_number_union(mode, &e.mode) ||
530	    !tomoyo_parse_number_union(major, &e.major) ||
531	    !tomoyo_parse_number_union(minor, &e.minor))
532		goto out;
533	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
534				     tomoyo_same_mkdev_acl,
535				     tomoyo_merge_mkdev_acl);
536 out:
537	tomoyo_put_name_union(&e.name);
538	tomoyo_put_number_union(&e.mode);
539	tomoyo_put_number_union(&e.major);
540	tomoyo_put_number_union(&e.minor);
541	return error;
542}
543
544/**
545 * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
546 *
547 * @a: Pointer to "struct tomoyo_acl_info".
548 * @b: Pointer to "struct tomoyo_acl_info".
549 *
550 * Returns true if @a == @b except permission bits, false otherwise.
551 */
552static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
553				  const struct tomoyo_acl_info *b)
554{
555	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
556	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
557	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
558		tomoyo_same_name_union(&p1->name2, &p2->name2);
559}
560
561/**
562 * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
563 *
564 * @a:         Pointer to "struct tomoyo_acl_info".
565 * @b:         Pointer to "struct tomoyo_acl_info".
566 * @is_delete: True for @a &= ~@b, false for @a |= @b.
567 *
568 * Returns true if @a is empty, false otherwise.
569 */
570static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
571				   struct tomoyo_acl_info *b,
572				   const bool is_delete)
573{
574	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
575		->perm;
576	u8 perm = *a_perm;
577	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
578	if (is_delete)
579		perm &= ~b_perm;
580	else
581		perm |= b_perm;
582	*a_perm = perm;
583	return !perm;
584}
585
586/**
587 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
588 *
589 * @type:      Type of operation.
590 * @filename1: First filename.
591 * @filename2: Second filename.
592 * @domain:    Pointer to "struct tomoyo_domain_info".
593 * @is_delete: True if it is a delete request.
594 *
595 * Returns 0 on success, negative value otherwise.
596 *
597 * Caller holds tomoyo_read_lock().
598 */
599static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
600				   const char *filename2,
601				   struct tomoyo_domain_info * const domain,
602				   const bool is_delete)
603{
604	struct tomoyo_path2_acl e = {
605		.head.type = TOMOYO_TYPE_PATH2_ACL,
606		.perm = 1 << type
607	};
608	int error = is_delete ? -ENOENT : -ENOMEM;
609	if (!tomoyo_parse_name_union(filename1, &e.name1) ||
610	    !tomoyo_parse_name_union(filename2, &e.name2))
611		goto out;
612	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
613				     tomoyo_same_path2_acl,
614				     tomoyo_merge_path2_acl);
615 out:
616	tomoyo_put_name_union(&e.name1);
617	tomoyo_put_name_union(&e.name2);
618	return error;
619}
620
621/**
622 * tomoyo_path_permission - Check permission for single path operation.
623 *
624 * @r:         Pointer to "struct tomoyo_request_info".
625 * @operation: Type of operation.
626 * @filename:  Filename to check.
627 *
628 * Returns 0 on success, negative value otherwise.
629 *
630 * Caller holds tomoyo_read_lock().
631 */
632int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
633			   const struct tomoyo_path_info *filename)
634{
635	int error;
636
637	r->type = tomoyo_p2mac[operation];
638	r->mode = tomoyo_get_mode(r->profile, r->type);
639	if (r->mode == TOMOYO_CONFIG_DISABLED)
640		return 0;
641	r->param_type = TOMOYO_TYPE_PATH_ACL;
642	r->param.path.filename = filename;
643	r->param.path.operation = operation;
644	do {
645		tomoyo_check_acl(r, tomoyo_check_path_acl);
646		error = tomoyo_audit_path_log(r);
647		/*
648		 * Do not retry for execute request, for alias may have
649		 * changed.
650		 */
651	} while (error == TOMOYO_RETRY_REQUEST &&
652		 operation != TOMOYO_TYPE_EXECUTE);
653	return error;
654}
655
656/**
657 * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
658 *
659 * @a: Pointer to "struct tomoyo_acl_info".
660 * @b: Pointer to "struct tomoyo_acl_info".
661 *
662 * Returns true if @a == @b except permission bits, false otherwise.
663 */
664static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
665					const struct tomoyo_acl_info *b)
666{
667	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
668							       head);
669	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
670							       head);
671	return tomoyo_same_name_union(&p1->name, &p2->name) &&
672		tomoyo_same_number_union(&p1->number, &p2->number);
673}
674
675/**
676 * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
677 *
678 * @a:         Pointer to "struct tomoyo_acl_info".
679 * @b:         Pointer to "struct tomoyo_acl_info".
680 * @is_delete: True for @a &= ~@b, false for @a |= @b.
681 *
682 * Returns true if @a is empty, false otherwise.
683 */
684static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
685					 struct tomoyo_acl_info *b,
686					 const bool is_delete)
687{
688	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
689					  head)->perm;
690	u8 perm = *a_perm;
691	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
692		->perm;
693	if (is_delete)
694		perm &= ~b_perm;
695	else
696		perm |= b_perm;
697	*a_perm = perm;
698	return !perm;
699}
700
701/**
702 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
703 *
704 * @type:      Type of operation.
705 * @filename:  Filename.
706 * @number:    Number.
707 * @domain:    Pointer to "struct tomoyo_domain_info".
708 * @is_delete: True if it is a delete request.
709 *
710 * Returns 0 on success, negative value otherwise.
711 */
712static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
713					 char *number,
714					 struct tomoyo_domain_info * const
715					 domain, const bool is_delete)
716{
717	struct tomoyo_path_number_acl e = {
718		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
719		.perm = 1 << type
720	};
721	int error = is_delete ? -ENOENT : -ENOMEM;
722	if (!tomoyo_parse_name_union(filename, &e.name))
723		return -EINVAL;
724	if (!tomoyo_parse_number_union(number, &e.number))
725		goto out;
726	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
727				     tomoyo_same_path_number_acl,
728				     tomoyo_merge_path_number_acl);
729 out:
730	tomoyo_put_name_union(&e.name);
731	tomoyo_put_number_union(&e.number);
732	return error;
733}
734
735/**
736 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
737 *
738 * @type:   Type of operation.
739 * @path:   Pointer to "struct path".
740 * @number: Number.
741 *
742 * Returns 0 on success, negative value otherwise.
743 */
744int tomoyo_path_number_perm(const u8 type, struct path *path,
745			    unsigned long number)
746{
747	struct tomoyo_request_info r;
748	int error = -ENOMEM;
749	struct tomoyo_path_info buf;
750	int idx;
751
752	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
753	    == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
754		return 0;
755	idx = tomoyo_read_lock();
756	if (!tomoyo_get_realpath(&buf, path))
757		goto out;
758	if (type == TOMOYO_TYPE_MKDIR)
759		tomoyo_add_slash(&buf);
760	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
761	r.param.path_number.operation = type;
762	r.param.path_number.filename = &buf;
763	r.param.path_number.number = number;
764	do {
765		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
766		error = tomoyo_audit_path_number_log(&r);
767	} while (error == TOMOYO_RETRY_REQUEST);
768	kfree(buf.name);
769 out:
770	tomoyo_read_unlock(idx);
771	if (r.mode != TOMOYO_CONFIG_ENFORCING)
772		error = 0;
773	return error;
774}
775
776/**
777 * tomoyo_check_open_permission - Check permission for "read" and "write".
778 *
779 * @domain: Pointer to "struct tomoyo_domain_info".
780 * @path:   Pointer to "struct path".
781 * @flag:   Flags for open().
782 *
783 * Returns 0 on success, negative value otherwise.
784 */
785int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
786				 struct path *path, const int flag)
787{
788	const u8 acc_mode = ACC_MODE(flag);
789	int error = 0;
790	struct tomoyo_path_info buf;
791	struct tomoyo_request_info r;
792	int idx;
793
794	if (!path->mnt)
795		return 0;
796	buf.name = NULL;
797	r.mode = TOMOYO_CONFIG_DISABLED;
798	idx = tomoyo_read_lock();
799	if (acc_mode &&
800	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
801	    != TOMOYO_CONFIG_DISABLED) {
802		if (!tomoyo_get_realpath(&buf, path)) {
803			error = -ENOMEM;
804			goto out;
805		}
806		if (acc_mode & MAY_READ)
807			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
808						       &buf);
809		if (!error && (acc_mode & MAY_WRITE))
810			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
811						       TOMOYO_TYPE_APPEND :
812						       TOMOYO_TYPE_WRITE,
813						       &buf);
814	}
815 out:
816	kfree(buf.name);
817	tomoyo_read_unlock(idx);
818	if (r.mode != TOMOYO_CONFIG_ENFORCING)
819		error = 0;
820	return error;
821}
822
823/**
824 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
825 *
826 * @operation: Type of operation.
827 * @path:      Pointer to "struct path".
828 *
829 * Returns 0 on success, negative value otherwise.
830 */
831int tomoyo_path_perm(const u8 operation, struct path *path)
832{
833	struct tomoyo_request_info r;
834	int error;
835	struct tomoyo_path_info buf;
836	bool is_enforce;
837	int idx;
838
839	if (!path->mnt)
840		return 0;
841	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
842	    == TOMOYO_CONFIG_DISABLED)
843		return 0;
844	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
845	error = -ENOMEM;
846	buf.name = NULL;
847	idx = tomoyo_read_lock();
848	if (!tomoyo_get_realpath(&buf, path))
849		goto out;
850	switch (operation) {
851	case TOMOYO_TYPE_RMDIR:
852	case TOMOYO_TYPE_CHROOT:
853		tomoyo_add_slash(&buf);
854		break;
855	}
856	error = tomoyo_path_permission(&r, operation, &buf);
857 out:
858	kfree(buf.name);
859	tomoyo_read_unlock(idx);
860	if (!is_enforce)
861		error = 0;
862	return error;
863}
864
865/**
866 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
867 *
868 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
869 * @path:      Pointer to "struct path".
870 * @mode:      Create mode.
871 * @dev:       Device number.
872 *
873 * Returns 0 on success, negative value otherwise.
874 */
875int tomoyo_mkdev_perm(const u8 operation, struct path *path,
876		      const unsigned int mode, unsigned int dev)
877{
878	struct tomoyo_request_info r;
879	int error = -ENOMEM;
880	struct tomoyo_path_info buf;
881	int idx;
882
883	if (!path->mnt ||
884	    tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
885	    == TOMOYO_CONFIG_DISABLED)
886		return 0;
887	idx = tomoyo_read_lock();
888	error = -ENOMEM;
889	if (tomoyo_get_realpath(&buf, path)) {
890		dev = new_decode_dev(dev);
891		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
892		r.param.mkdev.filename = &buf;
893		r.param.mkdev.operation = operation;
894		r.param.mkdev.mode = mode;
895		r.param.mkdev.major = MAJOR(dev);
896		r.param.mkdev.minor = MINOR(dev);
897		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
898		error = tomoyo_audit_mkdev_log(&r);
899		kfree(buf.name);
900	}
901	tomoyo_read_unlock(idx);
902	if (r.mode != TOMOYO_CONFIG_ENFORCING)
903		error = 0;
904	return error;
905}
906
907/**
908 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
909 *
910 * @operation: Type of operation.
911 * @path1:      Pointer to "struct path".
912 * @path2:      Pointer to "struct path".
913 *
914 * Returns 0 on success, negative value otherwise.
915 */
916int tomoyo_path2_perm(const u8 operation, struct path *path1,
917		      struct path *path2)
918{
919	int error = -ENOMEM;
920	struct tomoyo_path_info buf1;
921	struct tomoyo_path_info buf2;
922	struct tomoyo_request_info r;
923	int idx;
924
925	if (!path1->mnt || !path2->mnt ||
926	    tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
927	    == TOMOYO_CONFIG_DISABLED)
928		return 0;
929	buf1.name = NULL;
930	buf2.name = NULL;
931	idx = tomoyo_read_lock();
932	if (!tomoyo_get_realpath(&buf1, path1) ||
933	    !tomoyo_get_realpath(&buf2, path2))
934		goto out;
935	switch (operation) {
936		struct dentry *dentry;
937	case TOMOYO_TYPE_RENAME:
938        case TOMOYO_TYPE_LINK:
939		dentry = path1->dentry;
940	        if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
941                        break;
942                /* fall through */
943        case TOMOYO_TYPE_PIVOT_ROOT:
944                tomoyo_add_slash(&buf1);
945                tomoyo_add_slash(&buf2);
946		break;
947        }
948	r.param_type = TOMOYO_TYPE_PATH2_ACL;
949	r.param.path2.operation = operation;
950	r.param.path2.filename1 = &buf1;
951	r.param.path2.filename2 = &buf2;
952	do {
953		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
954		error = tomoyo_audit_path2_log(&r);
955	} while (error == TOMOYO_RETRY_REQUEST);
956 out:
957	kfree(buf1.name);
958	kfree(buf2.name);
959	tomoyo_read_unlock(idx);
960	if (r.mode != TOMOYO_CONFIG_ENFORCING)
961		error = 0;
962	return error;
963}
964
965/**
966 * tomoyo_write_file - Update file related list.
967 *
968 * @data:      String to parse.
969 * @domain:    Pointer to "struct tomoyo_domain_info".
970 * @is_delete: True if it is a delete request.
971 *
972 * Returns 0 on success, negative value otherwise.
973 *
974 * Caller holds tomoyo_read_lock().
975 */
976int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
977		      const bool is_delete)
978{
979	char *w[5];
980	u8 type;
981	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
982		return -EINVAL;
983	if (strncmp(w[0], "allow_", 6))
984		goto out;
985	w[0] += 6;
986	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
987		if (strcmp(w[0], tomoyo_path_keyword[type]))
988			continue;
989		return tomoyo_update_path_acl(type, w[1], domain, is_delete);
990	}
991	if (!w[2][0])
992		goto out;
993	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
994		if (strcmp(w[0], tomoyo_path2_keyword[type]))
995			continue;
996		return tomoyo_update_path2_acl(type, w[1], w[2], domain,
997					       is_delete);
998	}
999	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
1000		if (strcmp(w[0], tomoyo_path_number_keyword[type]))
1001			continue;
1002		return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
1003						     is_delete);
1004	}
1005	if (!w[3][0] || !w[4][0])
1006		goto out;
1007	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
1008		if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
1009			continue;
1010		return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
1011					       w[4], domain, is_delete);
1012	}
1013 out:
1014	return -EINVAL;
1015}
1016