file.c revision fdb8ebb729bbb640e64028a4f579a02ebc405727
1/*
2 * security/tomoyo/file.c
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2009  NTT DATA CORPORATION
7 *
8 * Version: 2.2.0   2009/04/01
9 *
10 */
11
12#include "common.h"
13#include "tomoyo.h"
14#include "realpath.h"
15#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
16
17/*
18 * tomoyo_globally_readable_file_entry is a structure which is used for holding
19 * "allow_read" entries.
20 * It has following fields.
21 *
22 *  (1) "list" which is linked to tomoyo_globally_readable_list .
23 *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
24 *  (3) "is_deleted" is a bool which is true if marked as deleted, false
25 *      otherwise.
26 */
27struct tomoyo_globally_readable_file_entry {
28	struct list_head list;
29	const struct tomoyo_path_info *filename;
30	bool is_deleted;
31};
32
33/*
34 * tomoyo_pattern_entry is a structure which is used for holding
35 * "tomoyo_pattern_list" entries.
36 * It has following fields.
37 *
38 *  (1) "list" which is linked to tomoyo_pattern_list .
39 *  (2) "pattern" is a pathname pattern which is used for converting pathnames
40 *      to pathname patterns during learning mode.
41 *  (3) "is_deleted" is a bool which is true if marked as deleted, false
42 *      otherwise.
43 */
44struct tomoyo_pattern_entry {
45	struct list_head list;
46	const struct tomoyo_path_info *pattern;
47	bool is_deleted;
48};
49
50/*
51 * tomoyo_no_rewrite_entry is a structure which is used for holding
52 * "deny_rewrite" entries.
53 * It has following fields.
54 *
55 *  (1) "list" which is linked to tomoyo_no_rewrite_list .
56 *  (2) "pattern" is a pathname which is by default not permitted to modify
57 *      already existing content.
58 *  (3) "is_deleted" is a bool which is true if marked as deleted, false
59 *      otherwise.
60 */
61struct tomoyo_no_rewrite_entry {
62	struct list_head list;
63	const struct tomoyo_path_info *pattern;
64	bool is_deleted;
65};
66
67/* Keyword array for single path operations. */
68static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
69	[TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
70	[TOMOYO_TYPE_EXECUTE_ACL]    = "execute",
71	[TOMOYO_TYPE_READ_ACL]       = "read",
72	[TOMOYO_TYPE_WRITE_ACL]      = "write",
73	[TOMOYO_TYPE_CREATE_ACL]     = "create",
74	[TOMOYO_TYPE_UNLINK_ACL]     = "unlink",
75	[TOMOYO_TYPE_MKDIR_ACL]      = "mkdir",
76	[TOMOYO_TYPE_RMDIR_ACL]      = "rmdir",
77	[TOMOYO_TYPE_MKFIFO_ACL]     = "mkfifo",
78	[TOMOYO_TYPE_MKSOCK_ACL]     = "mksock",
79	[TOMOYO_TYPE_MKBLOCK_ACL]    = "mkblock",
80	[TOMOYO_TYPE_MKCHAR_ACL]     = "mkchar",
81	[TOMOYO_TYPE_TRUNCATE_ACL]   = "truncate",
82	[TOMOYO_TYPE_SYMLINK_ACL]    = "symlink",
83	[TOMOYO_TYPE_REWRITE_ACL]    = "rewrite",
84	[TOMOYO_TYPE_IOCTL_ACL]      = "ioctl",
85	[TOMOYO_TYPE_CHMOD_ACL]      = "chmod",
86	[TOMOYO_TYPE_CHOWN_ACL]      = "chown",
87	[TOMOYO_TYPE_CHGRP_ACL]      = "chgrp",
88	[TOMOYO_TYPE_CHROOT_ACL]     = "chroot",
89	[TOMOYO_TYPE_MOUNT_ACL]      = "mount",
90	[TOMOYO_TYPE_UMOUNT_ACL]     = "unmount",
91};
92
93/* Keyword array for double path operations. */
94static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = {
95	[TOMOYO_TYPE_LINK_ACL]    = "link",
96	[TOMOYO_TYPE_RENAME_ACL]  = "rename",
97	[TOMOYO_TYPE_PIVOT_ROOT_ACL] = "pivot_root",
98};
99
100/**
101 * tomoyo_sp2keyword - Get the name of single path operation.
102 *
103 * @operation: Type of operation.
104 *
105 * Returns the name of single path operation.
106 */
107const char *tomoyo_sp2keyword(const u8 operation)
108{
109	return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION)
110		? tomoyo_sp_keyword[operation] : NULL;
111}
112
113/**
114 * tomoyo_dp2keyword - Get the name of double path operation.
115 *
116 * @operation: Type of operation.
117 *
118 * Returns the name of double path operation.
119 */
120const char *tomoyo_dp2keyword(const u8 operation)
121{
122	return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION)
123		? tomoyo_dp_keyword[operation] : NULL;
124}
125
126/**
127 * tomoyo_strendswith - Check whether the token ends with the given token.
128 *
129 * @name: The token to check.
130 * @tail: The token to find.
131 *
132 * Returns true if @name ends with @tail, false otherwise.
133 */
134static bool tomoyo_strendswith(const char *name, const char *tail)
135{
136	int len;
137
138	if (!name || !tail)
139		return false;
140	len = strlen(name) - strlen(tail);
141	return len >= 0 && !strcmp(name + len, tail);
142}
143
144/**
145 * tomoyo_get_path - Get realpath.
146 *
147 * @path: Pointer to "struct path".
148 *
149 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
150 */
151static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
152{
153	int error;
154	struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf));
155
156	if (!buf)
157		return NULL;
158	/* Reserve one byte for appending "/". */
159	error = tomoyo_realpath_from_path2(path, buf->body,
160					   sizeof(buf->body) - 2);
161	if (!error) {
162		buf->head.name = buf->body;
163		tomoyo_fill_path_info(&buf->head);
164		return &buf->head;
165	}
166	tomoyo_free(buf);
167	return NULL;
168}
169
170/* Lock for domain->acl_info_list. */
171DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
172
173static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
174					 const char *filename2,
175					 struct tomoyo_domain_info *
176					 const domain, const bool is_delete);
177static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
178					 struct tomoyo_domain_info *
179					 const domain, const bool is_delete);
180
181/*
182 * tomoyo_globally_readable_list is used for holding list of pathnames which
183 * are by default allowed to be open()ed for reading by any process.
184 *
185 * An entry is added by
186 *
187 * # echo 'allow_read /lib/libc-2.5.so' > \
188 *                               /sys/kernel/security/tomoyo/exception_policy
189 *
190 * and is deleted by
191 *
192 * # echo 'delete allow_read /lib/libc-2.5.so' > \
193 *                               /sys/kernel/security/tomoyo/exception_policy
194 *
195 * and all entries are retrieved by
196 *
197 * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
198 *
199 * In the example above, any process is allowed to
200 * open("/lib/libc-2.5.so", O_RDONLY).
201 * One exception is, if the domain which current process belongs to is marked
202 * as "ignore_global_allow_read", current process can't do so unless explicitly
203 * given "allow_read /lib/libc-2.5.so" to the domain which current process
204 * belongs to.
205 */
206static LIST_HEAD(tomoyo_globally_readable_list);
207static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
208
209/**
210 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
211 *
212 * @filename:  Filename unconditionally permitted to open() for reading.
213 * @is_delete: True if it is a delete request.
214 *
215 * Returns 0 on success, negative value otherwise.
216 *
217 * Caller holds tomoyo_read_lock().
218 */
219static int tomoyo_update_globally_readable_entry(const char *filename,
220						 const bool is_delete)
221{
222	struct tomoyo_globally_readable_file_entry *new_entry;
223	struct tomoyo_globally_readable_file_entry *ptr;
224	const struct tomoyo_path_info *saved_filename;
225	int error = -ENOMEM;
226
227	if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
228		return -EINVAL;
229	saved_filename = tomoyo_save_name(filename);
230	if (!saved_filename)
231		return -ENOMEM;
232	down_write(&tomoyo_globally_readable_list_lock);
233	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
234		if (ptr->filename != saved_filename)
235			continue;
236		ptr->is_deleted = is_delete;
237		error = 0;
238		goto out;
239	}
240	if (is_delete) {
241		error = -ENOENT;
242		goto out;
243	}
244	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
245	if (!new_entry)
246		goto out;
247	new_entry->filename = saved_filename;
248	list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
249	error = 0;
250 out:
251	up_write(&tomoyo_globally_readable_list_lock);
252	return error;
253}
254
255/**
256 * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
257 *
258 * @filename: The filename to check.
259 *
260 * Returns true if any domain can open @filename for reading, false otherwise.
261 *
262 * Caller holds tomoyo_read_lock().
263 */
264static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
265					     filename)
266{
267	struct tomoyo_globally_readable_file_entry *ptr;
268	bool found = false;
269
270	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
271		if (!ptr->is_deleted &&
272		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
273			found = true;
274			break;
275		}
276	}
277	return found;
278}
279
280/**
281 * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
282 *
283 * @data:      String to parse.
284 * @is_delete: True if it is a delete request.
285 *
286 * Returns 0 on success, negative value otherwise.
287 *
288 * Caller holds tomoyo_read_lock().
289 */
290int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
291{
292	return tomoyo_update_globally_readable_entry(data, is_delete);
293}
294
295/**
296 * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
297 *
298 * @head: Pointer to "struct tomoyo_io_buffer".
299 *
300 * Returns true on success, false otherwise.
301 *
302 * Caller holds tomoyo_read_lock().
303 */
304bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
305{
306	struct list_head *pos;
307	bool done = true;
308
309	list_for_each_cookie(pos, head->read_var2,
310			     &tomoyo_globally_readable_list) {
311		struct tomoyo_globally_readable_file_entry *ptr;
312		ptr = list_entry(pos,
313				 struct tomoyo_globally_readable_file_entry,
314				 list);
315		if (ptr->is_deleted)
316			continue;
317		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
318					ptr->filename->name);
319		if (!done)
320			break;
321	}
322	return done;
323}
324
325/* tomoyo_pattern_list is used for holding list of pathnames which are used for
326 * converting pathnames to pathname patterns during learning mode.
327 *
328 * An entry is added by
329 *
330 * # echo 'file_pattern /proc/\$/mounts' > \
331 *                             /sys/kernel/security/tomoyo/exception_policy
332 *
333 * and is deleted by
334 *
335 * # echo 'delete file_pattern /proc/\$/mounts' > \
336 *                             /sys/kernel/security/tomoyo/exception_policy
337 *
338 * and all entries are retrieved by
339 *
340 * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
341 *
342 * In the example above, if a process which belongs to a domain which is in
343 * learning mode requested open("/proc/1/mounts", O_RDONLY),
344 * "allow_read /proc/\$/mounts" is automatically added to the domain which that
345 * process belongs to.
346 *
347 * It is not a desirable behavior that we have to use /proc/\$/ instead of
348 * /proc/self/ when current process needs to access only current process's
349 * information. As of now, LSM version of TOMOYO is using __d_path() for
350 * calculating pathname. Non LSM version of TOMOYO is using its own function
351 * which pretends as if /proc/self/ is not a symlink; so that we can forbid
352 * current process from accessing other process's information.
353 */
354static LIST_HEAD(tomoyo_pattern_list);
355static DECLARE_RWSEM(tomoyo_pattern_list_lock);
356
357/**
358 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
359 *
360 * @pattern:   Pathname pattern.
361 * @is_delete: True if it is a delete request.
362 *
363 * Returns 0 on success, negative value otherwise.
364 *
365 * Caller holds tomoyo_read_lock().
366 */
367static int tomoyo_update_file_pattern_entry(const char *pattern,
368					    const bool is_delete)
369{
370	struct tomoyo_pattern_entry *new_entry;
371	struct tomoyo_pattern_entry *ptr;
372	const struct tomoyo_path_info *saved_pattern;
373	int error = -ENOMEM;
374
375	if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
376		return -EINVAL;
377	saved_pattern = tomoyo_save_name(pattern);
378	if (!saved_pattern)
379		return -ENOMEM;
380	down_write(&tomoyo_pattern_list_lock);
381	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
382		if (saved_pattern != ptr->pattern)
383			continue;
384		ptr->is_deleted = is_delete;
385		error = 0;
386		goto out;
387	}
388	if (is_delete) {
389		error = -ENOENT;
390		goto out;
391	}
392	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
393	if (!new_entry)
394		goto out;
395	new_entry->pattern = saved_pattern;
396	list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
397	error = 0;
398 out:
399	up_write(&tomoyo_pattern_list_lock);
400	return error;
401}
402
403/**
404 * tomoyo_get_file_pattern - Get patterned pathname.
405 *
406 * @filename: The filename to find patterned pathname.
407 *
408 * Returns pointer to pathname pattern if matched, @filename otherwise.
409 *
410 * Caller holds tomoyo_read_lock().
411 */
412static const struct tomoyo_path_info *
413tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
414{
415	struct tomoyo_pattern_entry *ptr;
416	const struct tomoyo_path_info *pattern = NULL;
417
418	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
419		if (ptr->is_deleted)
420			continue;
421		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
422			continue;
423		pattern = ptr->pattern;
424		if (tomoyo_strendswith(pattern->name, "/\\*")) {
425			/* Do nothing. Try to find the better match. */
426		} else {
427			/* This would be the better match. Use this. */
428			break;
429		}
430	}
431	if (pattern)
432		filename = pattern;
433	return filename;
434}
435
436/**
437 * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
438 *
439 * @data:      String to parse.
440 * @is_delete: True if it is a delete request.
441 *
442 * Returns 0 on success, negative value otherwise.
443 *
444 * Caller holds tomoyo_read_lock().
445 */
446int tomoyo_write_pattern_policy(char *data, const bool is_delete)
447{
448	return tomoyo_update_file_pattern_entry(data, is_delete);
449}
450
451/**
452 * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
453 *
454 * @head: Pointer to "struct tomoyo_io_buffer".
455 *
456 * Returns true on success, false otherwise.
457 *
458 * Caller holds tomoyo_read_lock().
459 */
460bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
461{
462	struct list_head *pos;
463	bool done = true;
464
465	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
466		struct tomoyo_pattern_entry *ptr;
467		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
468		if (ptr->is_deleted)
469			continue;
470		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
471					"%s\n", ptr->pattern->name);
472		if (!done)
473			break;
474	}
475	return done;
476}
477
478/*
479 * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
480 * default forbidden to modify already written content of a file.
481 *
482 * An entry is added by
483 *
484 * # echo 'deny_rewrite /var/log/messages' > \
485 *                              /sys/kernel/security/tomoyo/exception_policy
486 *
487 * and is deleted by
488 *
489 * # echo 'delete deny_rewrite /var/log/messages' > \
490 *                              /sys/kernel/security/tomoyo/exception_policy
491 *
492 * and all entries are retrieved by
493 *
494 * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
495 *
496 * In the example above, if a process requested to rewrite /var/log/messages ,
497 * the process can't rewrite unless the domain which that process belongs to
498 * has "allow_rewrite /var/log/messages" entry.
499 *
500 * It is not a desirable behavior that we have to add "\040(deleted)" suffix
501 * when we want to allow rewriting already unlink()ed file. As of now,
502 * LSM version of TOMOYO is using __d_path() for calculating pathname.
503 * Non LSM version of TOMOYO is using its own function which doesn't append
504 * " (deleted)" suffix if the file is already unlink()ed; so that we don't
505 * need to worry whether the file is already unlink()ed or not.
506 */
507static LIST_HEAD(tomoyo_no_rewrite_list);
508static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
509
510/**
511 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
512 *
513 * @pattern:   Pathname pattern that are not rewritable by default.
514 * @is_delete: True if it is a delete request.
515 *
516 * Returns 0 on success, negative value otherwise.
517 *
518 * Caller holds tomoyo_read_lock().
519 */
520static int tomoyo_update_no_rewrite_entry(const char *pattern,
521					  const bool is_delete)
522{
523	struct tomoyo_no_rewrite_entry *new_entry, *ptr;
524	const struct tomoyo_path_info *saved_pattern;
525	int error = -ENOMEM;
526
527	if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
528		return -EINVAL;
529	saved_pattern = tomoyo_save_name(pattern);
530	if (!saved_pattern)
531		return -ENOMEM;
532	down_write(&tomoyo_no_rewrite_list_lock);
533	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
534		if (ptr->pattern != saved_pattern)
535			continue;
536		ptr->is_deleted = is_delete;
537		error = 0;
538		goto out;
539	}
540	if (is_delete) {
541		error = -ENOENT;
542		goto out;
543	}
544	new_entry = tomoyo_alloc_element(sizeof(*new_entry));
545	if (!new_entry)
546		goto out;
547	new_entry->pattern = saved_pattern;
548	list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
549	error = 0;
550 out:
551	up_write(&tomoyo_no_rewrite_list_lock);
552	return error;
553}
554
555/**
556 * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
557 *
558 * @filename: Filename to check.
559 *
560 * Returns true if @filename is specified by "deny_rewrite" directive,
561 * false otherwise.
562 *
563 * Caller holds tomoyo_read_lock().
564 */
565static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
566{
567	struct tomoyo_no_rewrite_entry *ptr;
568	bool found = false;
569
570	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
571		if (ptr->is_deleted)
572			continue;
573		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
574			continue;
575		found = true;
576		break;
577	}
578	return found;
579}
580
581/**
582 * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
583 *
584 * @data:      String to parse.
585 * @is_delete: True if it is a delete request.
586 *
587 * Returns 0 on success, negative value otherwise.
588 *
589 * Caller holds tomoyo_read_lock().
590 */
591int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
592{
593	return tomoyo_update_no_rewrite_entry(data, is_delete);
594}
595
596/**
597 * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
598 *
599 * @head: Pointer to "struct tomoyo_io_buffer".
600 *
601 * Returns true on success, false otherwise.
602 *
603 * Caller holds tomoyo_read_lock().
604 */
605bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
606{
607	struct list_head *pos;
608	bool done = true;
609
610	list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
611		struct tomoyo_no_rewrite_entry *ptr;
612		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
613		if (ptr->is_deleted)
614			continue;
615		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
616					"%s\n", ptr->pattern->name);
617		if (!done)
618			break;
619	}
620	return done;
621}
622
623/**
624 * tomoyo_update_file_acl - Update file's read/write/execute ACL.
625 *
626 * @filename:  Filename.
627 * @perm:      Permission (between 1 to 7).
628 * @domain:    Pointer to "struct tomoyo_domain_info".
629 * @is_delete: True if it is a delete request.
630 *
631 * Returns 0 on success, negative value otherwise.
632 *
633 * This is legacy support interface for older policy syntax.
634 * Current policy syntax uses "allow_read/write" instead of "6",
635 * "allow_read" instead of "4", "allow_write" instead of "2",
636 * "allow_execute" instead of "1".
637 *
638 * Caller holds tomoyo_read_lock().
639 */
640static int tomoyo_update_file_acl(const char *filename, u8 perm,
641				  struct tomoyo_domain_info * const domain,
642				  const bool is_delete)
643{
644	if (perm > 7 || !perm) {
645		printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
646		       __func__, perm, filename);
647		return -EINVAL;
648	}
649	if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
650		/*
651		 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
652		 * directory permissions.
653		 */
654		return 0;
655	if (perm & 4)
656		tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename,
657					      domain, is_delete);
658	if (perm & 2)
659		tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename,
660					      domain, is_delete);
661	if (perm & 1)
662		tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL,
663					      filename, domain, is_delete);
664	return 0;
665}
666
667/**
668 * tomoyo_check_single_path_acl2 - Check permission for single path operation.
669 *
670 * @domain:          Pointer to "struct tomoyo_domain_info".
671 * @filename:        Filename to check.
672 * @perm:            Permission.
673 * @may_use_pattern: True if patterned ACL is permitted.
674 *
675 * Returns 0 on success, -EPERM otherwise.
676 *
677 * Caller holds tomoyo_read_lock().
678 */
679static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
680					 domain,
681					 const struct tomoyo_path_info *
682					 filename,
683					 const u32 perm,
684					 const bool may_use_pattern)
685{
686	struct tomoyo_acl_info *ptr;
687	int error = -EPERM;
688
689	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
690		struct tomoyo_single_path_acl_record *acl;
691		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
692			continue;
693		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
694				   head);
695		if (perm <= 0xFFFF) {
696			if (!(acl->perm & perm))
697				continue;
698		} else {
699			if (!(acl->perm_high & (perm >> 16)))
700				continue;
701		}
702		if (may_use_pattern || !acl->filename->is_patterned) {
703			if (!tomoyo_path_matches_pattern(filename,
704							 acl->filename))
705				continue;
706		} else {
707			continue;
708		}
709		error = 0;
710		break;
711	}
712	return error;
713}
714
715/**
716 * tomoyo_check_file_acl - Check permission for opening files.
717 *
718 * @domain:    Pointer to "struct tomoyo_domain_info".
719 * @filename:  Filename to check.
720 * @operation: Mode ("read" or "write" or "read/write" or "execute").
721 *
722 * Returns 0 on success, -EPERM otherwise.
723 *
724 * Caller holds tomoyo_read_lock().
725 */
726static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
727				 const struct tomoyo_path_info *filename,
728				 const u8 operation)
729{
730	u32 perm = 0;
731
732	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
733		return 0;
734	if (operation == 6)
735		perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL;
736	else if (operation == 4)
737		perm = 1 << TOMOYO_TYPE_READ_ACL;
738	else if (operation == 2)
739		perm = 1 << TOMOYO_TYPE_WRITE_ACL;
740	else if (operation == 1)
741		perm = 1 << TOMOYO_TYPE_EXECUTE_ACL;
742	else
743		BUG();
744	return tomoyo_check_single_path_acl2(domain, filename, perm,
745					     operation != 1);
746}
747
748/**
749 * tomoyo_check_file_perm2 - Check permission for opening files.
750 *
751 * @domain:    Pointer to "struct tomoyo_domain_info".
752 * @filename:  Filename to check.
753 * @perm:      Mode ("read" or "write" or "read/write" or "execute").
754 * @operation: Operation name passed used for verbose mode.
755 * @mode:      Access control mode.
756 *
757 * Returns 0 on success, negative value otherwise.
758 *
759 * Caller holds tomoyo_read_lock().
760 */
761static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
762				   const struct tomoyo_path_info *filename,
763				   const u8 perm, const char *operation,
764				   const u8 mode)
765{
766	const bool is_enforce = (mode == 3);
767	const char *msg = "<unknown>";
768	int error = 0;
769
770	if (!filename)
771		return 0;
772	error = tomoyo_check_file_acl(domain, filename, perm);
773	if (error && perm == 4 &&
774	    (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
775	    && tomoyo_is_globally_readable_file(filename))
776		error = 0;
777	if (perm == 6)
778		msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL);
779	else if (perm == 4)
780		msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL);
781	else if (perm == 2)
782		msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL);
783	else if (perm == 1)
784		msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL);
785	else
786		BUG();
787	if (!error)
788		return 0;
789	if (tomoyo_verbose_mode(domain))
790		printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
791		       "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
792		       filename->name, tomoyo_get_last_name(domain));
793	if (is_enforce)
794		return error;
795	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
796		/* Don't use patterns for execute permission. */
797		const struct tomoyo_path_info *patterned_file = (perm != 1) ?
798			tomoyo_get_file_pattern(filename) : filename;
799		tomoyo_update_file_acl(patterned_file->name, perm,
800				       domain, false);
801	}
802	return 0;
803}
804
805/**
806 * tomoyo_write_file_policy - Update file related list.
807 *
808 * @data:      String to parse.
809 * @domain:    Pointer to "struct tomoyo_domain_info".
810 * @is_delete: True if it is a delete request.
811 *
812 * Returns 0 on success, negative value otherwise.
813 *
814 * Caller holds tomoyo_read_lock().
815 */
816int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
817			     const bool is_delete)
818{
819	char *filename = strchr(data, ' ');
820	char *filename2;
821	unsigned int perm;
822	u8 type;
823
824	if (!filename)
825		return -EINVAL;
826	*filename++ = '\0';
827	if (sscanf(data, "%u", &perm) == 1)
828		return tomoyo_update_file_acl(filename, (u8) perm, domain,
829					      is_delete);
830	if (strncmp(data, "allow_", 6))
831		goto out;
832	data += 6;
833	for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) {
834		if (strcmp(data, tomoyo_sp_keyword[type]))
835			continue;
836		return tomoyo_update_single_path_acl(type, filename,
837						     domain, is_delete);
838	}
839	filename2 = strchr(filename, ' ');
840	if (!filename2)
841		goto out;
842	*filename2++ = '\0';
843	for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) {
844		if (strcmp(data, tomoyo_dp_keyword[type]))
845			continue;
846		return tomoyo_update_double_path_acl(type, filename, filename2,
847						     domain, is_delete);
848	}
849 out:
850	return -EINVAL;
851}
852
853/**
854 * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list.
855 *
856 * @type:      Type of operation.
857 * @filename:  Filename.
858 * @domain:    Pointer to "struct tomoyo_domain_info".
859 * @is_delete: True if it is a delete request.
860 *
861 * Returns 0 on success, negative value otherwise.
862 *
863 * Caller holds tomoyo_read_lock().
864 */
865static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
866					 struct tomoyo_domain_info *
867					 const domain, const bool is_delete)
868{
869	static const u32 rw_mask =
870		(1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
871	const struct tomoyo_path_info *saved_filename;
872	struct tomoyo_acl_info *ptr;
873	struct tomoyo_single_path_acl_record *acl;
874	int error = -ENOMEM;
875	const u32 perm = 1 << type;
876
877	if (!domain)
878		return -EINVAL;
879	if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
880		return -EINVAL;
881	saved_filename = tomoyo_save_name(filename);
882	if (!saved_filename)
883		return -ENOMEM;
884	down_write(&tomoyo_domain_acl_info_list_lock);
885	if (is_delete)
886		goto delete;
887	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
888		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
889			continue;
890		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
891				   head);
892		if (acl->filename != saved_filename)
893			continue;
894		/* Special case. Clear all bits if marked as deleted. */
895		if (ptr->type & TOMOYO_ACL_DELETED)
896			acl->perm = 0;
897		if (perm <= 0xFFFF)
898			acl->perm |= perm;
899		else
900			acl->perm_high |= (perm >> 16);
901		if ((acl->perm & rw_mask) == rw_mask)
902			acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL;
903		else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
904			acl->perm |= rw_mask;
905		ptr->type &= ~TOMOYO_ACL_DELETED;
906		error = 0;
907		goto out;
908	}
909	/* Not found. Append it to the tail. */
910	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
911	if (!acl)
912		goto out;
913	if (perm <= 0xFFFF)
914		acl->perm = perm;
915	else
916		acl->perm_high = (perm >> 16);
917	if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
918		acl->perm |= rw_mask;
919	acl->filename = saved_filename;
920	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
921	error = 0;
922	goto out;
923 delete:
924	error = -ENOENT;
925	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
926		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
927			continue;
928		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
929				   head);
930		if (acl->filename != saved_filename)
931			continue;
932		if (perm <= 0xFFFF)
933			acl->perm &= ~perm;
934		else
935			acl->perm_high &= ~(perm >> 16);
936		if ((acl->perm & rw_mask) != rw_mask)
937			acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL);
938		else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
939			acl->perm &= ~rw_mask;
940		if (!acl->perm && !acl->perm_high)
941			ptr->type |= TOMOYO_ACL_DELETED;
942		error = 0;
943		break;
944	}
945 out:
946	up_write(&tomoyo_domain_acl_info_list_lock);
947	return error;
948}
949
950/**
951 * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list.
952 *
953 * @type:      Type of operation.
954 * @filename1: First filename.
955 * @filename2: Second filename.
956 * @domain:    Pointer to "struct tomoyo_domain_info".
957 * @is_delete: True if it is a delete request.
958 *
959 * Returns 0 on success, negative value otherwise.
960 *
961 * Caller holds tomoyo_read_lock().
962 */
963static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
964					 const char *filename2,
965					 struct tomoyo_domain_info *
966					 const domain, const bool is_delete)
967{
968	const struct tomoyo_path_info *saved_filename1;
969	const struct tomoyo_path_info *saved_filename2;
970	struct tomoyo_acl_info *ptr;
971	struct tomoyo_double_path_acl_record *acl;
972	int error = -ENOMEM;
973	const u8 perm = 1 << type;
974
975	if (!domain)
976		return -EINVAL;
977	if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
978	    !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
979		return -EINVAL;
980	saved_filename1 = tomoyo_save_name(filename1);
981	saved_filename2 = tomoyo_save_name(filename2);
982	if (!saved_filename1 || !saved_filename2)
983		return -ENOMEM;
984	down_write(&tomoyo_domain_acl_info_list_lock);
985	if (is_delete)
986		goto delete;
987	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
988		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
989			continue;
990		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
991				   head);
992		if (acl->filename1 != saved_filename1 ||
993		    acl->filename2 != saved_filename2)
994			continue;
995		/* Special case. Clear all bits if marked as deleted. */
996		if (ptr->type & TOMOYO_ACL_DELETED)
997			acl->perm = 0;
998		acl->perm |= perm;
999		ptr->type &= ~TOMOYO_ACL_DELETED;
1000		error = 0;
1001		goto out;
1002	}
1003	/* Not found. Append it to the tail. */
1004	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
1005	if (!acl)
1006		goto out;
1007	acl->perm = perm;
1008	acl->filename1 = saved_filename1;
1009	acl->filename2 = saved_filename2;
1010	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
1011	error = 0;
1012	goto out;
1013 delete:
1014	error = -ENOENT;
1015	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1016		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
1017			continue;
1018		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
1019				   head);
1020		if (acl->filename1 != saved_filename1 ||
1021		    acl->filename2 != saved_filename2)
1022			continue;
1023		acl->perm &= ~perm;
1024		if (!acl->perm)
1025			ptr->type |= TOMOYO_ACL_DELETED;
1026		error = 0;
1027		break;
1028	}
1029 out:
1030	up_write(&tomoyo_domain_acl_info_list_lock);
1031	return error;
1032}
1033
1034/**
1035 * tomoyo_check_single_path_acl - Check permission for single path operation.
1036 *
1037 * @domain:   Pointer to "struct tomoyo_domain_info".
1038 * @type:     Type of operation.
1039 * @filename: Filename to check.
1040 *
1041 * Returns 0 on success, negative value otherwise.
1042 *
1043 * Caller holds tomoyo_read_lock().
1044 */
1045static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
1046					const u8 type,
1047					const struct tomoyo_path_info *filename)
1048{
1049	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
1050		return 0;
1051	return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1);
1052}
1053
1054/**
1055 * tomoyo_check_double_path_acl - Check permission for double path operation.
1056 *
1057 * @domain:    Pointer to "struct tomoyo_domain_info".
1058 * @type:      Type of operation.
1059 * @filename1: First filename to check.
1060 * @filename2: Second filename to check.
1061 *
1062 * Returns 0 on success, -EPERM otherwise.
1063 *
1064 * Caller holds tomoyo_read_lock().
1065 */
1066static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
1067					const u8 type,
1068					const struct tomoyo_path_info *
1069					filename1,
1070					const struct tomoyo_path_info *
1071					filename2)
1072{
1073	struct tomoyo_acl_info *ptr;
1074	const u8 perm = 1 << type;
1075	int error = -EPERM;
1076
1077	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
1078		return 0;
1079	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1080		struct tomoyo_double_path_acl_record *acl;
1081		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
1082			continue;
1083		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
1084				   head);
1085		if (!(acl->perm & perm))
1086			continue;
1087		if (!tomoyo_path_matches_pattern(filename1, acl->filename1))
1088			continue;
1089		if (!tomoyo_path_matches_pattern(filename2, acl->filename2))
1090			continue;
1091		error = 0;
1092		break;
1093	}
1094	return error;
1095}
1096
1097/**
1098 * tomoyo_check_single_path_permission2 - Check permission for single path operation.
1099 *
1100 * @domain:    Pointer to "struct tomoyo_domain_info".
1101 * @operation: Type of operation.
1102 * @filename:  Filename to check.
1103 * @mode:      Access control mode.
1104 *
1105 * Returns 0 on success, negative value otherwise.
1106 *
1107 * Caller holds tomoyo_read_lock().
1108 */
1109static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
1110						const domain, u8 operation,
1111						const struct tomoyo_path_info *
1112						filename, const u8 mode)
1113{
1114	const char *msg;
1115	int error;
1116	const bool is_enforce = (mode == 3);
1117
1118	if (!mode)
1119		return 0;
1120 next:
1121	error = tomoyo_check_single_path_acl(domain, operation, filename);
1122	msg = tomoyo_sp2keyword(operation);
1123	if (!error)
1124		goto ok;
1125	if (tomoyo_verbose_mode(domain))
1126		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
1127		       tomoyo_get_msg(is_enforce), msg, filename->name,
1128		       tomoyo_get_last_name(domain));
1129	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
1130		const char *name = tomoyo_get_file_pattern(filename)->name;
1131		tomoyo_update_single_path_acl(operation, name, domain, false);
1132	}
1133	if (!is_enforce)
1134		error = 0;
1135 ok:
1136	/*
1137	 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
1138	 * we need to check "allow_rewrite" permission if the filename is
1139	 * specified by "deny_rewrite" keyword.
1140	 */
1141	if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL &&
1142	    tomoyo_is_no_rewrite_file(filename)) {
1143		operation = TOMOYO_TYPE_REWRITE_ACL;
1144		goto next;
1145	}
1146	return error;
1147}
1148
1149/**
1150 * tomoyo_check_exec_perm - Check permission for "execute".
1151 *
1152 * @domain:   Pointer to "struct tomoyo_domain_info".
1153 * @filename: Check permission for "execute".
1154 *
1155 * Returns 0 on success, negativevalue otherwise.
1156 *
1157 * Caller holds tomoyo_read_lock().
1158 */
1159int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
1160			   const struct tomoyo_path_info *filename)
1161{
1162	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1163
1164	if (!mode)
1165		return 0;
1166	return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
1167}
1168
1169/**
1170 * tomoyo_check_open_permission - Check permission for "read" and "write".
1171 *
1172 * @domain: Pointer to "struct tomoyo_domain_info".
1173 * @path:   Pointer to "struct path".
1174 * @flag:   Flags for open().
1175 *
1176 * Returns 0 on success, negative value otherwise.
1177 */
1178int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
1179				 struct path *path, const int flag)
1180{
1181	const u8 acc_mode = ACC_MODE(flag);
1182	int error = -ENOMEM;
1183	struct tomoyo_path_info *buf;
1184	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1185	const bool is_enforce = (mode == 3);
1186	int idx;
1187
1188	if (!mode || !path->mnt)
1189		return 0;
1190	if (acc_mode == 0)
1191		return 0;
1192	if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
1193		/*
1194		 * I don't check directories here because mkdir() and rmdir()
1195		 * don't call me.
1196		 */
1197		return 0;
1198	idx = tomoyo_read_lock();
1199	buf = tomoyo_get_path(path);
1200	if (!buf)
1201		goto out;
1202	error = 0;
1203	/*
1204	 * If the filename is specified by "deny_rewrite" keyword,
1205	 * we need to check "allow_rewrite" permission when the filename is not
1206	 * opened for append mode or the filename is truncated at open time.
1207	 */
1208	if ((acc_mode & MAY_WRITE) &&
1209	    ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
1210	    (tomoyo_is_no_rewrite_file(buf))) {
1211		error = tomoyo_check_single_path_permission2(domain,
1212						     TOMOYO_TYPE_REWRITE_ACL,
1213							     buf, mode);
1214	}
1215	if (!error)
1216		error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
1217						mode);
1218	if (!error && (flag & O_TRUNC))
1219		error = tomoyo_check_single_path_permission2(domain,
1220						     TOMOYO_TYPE_TRUNCATE_ACL,
1221							     buf, mode);
1222 out:
1223	tomoyo_free(buf);
1224	tomoyo_read_unlock(idx);
1225	if (!is_enforce)
1226		error = 0;
1227	return error;
1228}
1229
1230/**
1231 * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
1232 *
1233 * @domain:    Pointer to "struct tomoyo_domain_info".
1234 * @operation: Type of operation.
1235 * @path:      Pointer to "struct path".
1236 *
1237 * Returns 0 on success, negative value otherwise.
1238 */
1239int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
1240			    const u8 operation, struct path *path)
1241{
1242	int error = -ENOMEM;
1243	struct tomoyo_path_info *buf;
1244	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1245	const bool is_enforce = (mode == 3);
1246	int idx;
1247
1248	if (!mode || !path->mnt)
1249		return 0;
1250	idx = tomoyo_read_lock();
1251	buf = tomoyo_get_path(path);
1252	if (!buf)
1253		goto out;
1254	switch (operation) {
1255	case TOMOYO_TYPE_MKDIR_ACL:
1256	case TOMOYO_TYPE_RMDIR_ACL:
1257	case TOMOYO_TYPE_CHROOT_ACL:
1258		if (!buf->is_dir) {
1259			/*
1260			 * tomoyo_get_path() reserves space for appending "/."
1261			 */
1262			strcat((char *) buf->name, "/");
1263			tomoyo_fill_path_info(buf);
1264		}
1265	}
1266	error = tomoyo_check_single_path_permission2(domain, operation, buf,
1267						     mode);
1268 out:
1269	tomoyo_free(buf);
1270	tomoyo_read_unlock(idx);
1271	if (!is_enforce)
1272		error = 0;
1273	return error;
1274}
1275
1276/**
1277 * tomoyo_check_rewrite_permission - Check permission for "rewrite".
1278 *
1279 * @domain: Pointer to "struct tomoyo_domain_info".
1280 * @filp: Pointer to "struct file".
1281 *
1282 * Returns 0 on success, negative value otherwise.
1283 */
1284int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
1285				    struct file *filp)
1286{
1287	int error = -ENOMEM;
1288	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1289	const bool is_enforce = (mode == 3);
1290	struct tomoyo_path_info *buf;
1291	int idx;
1292
1293	if (!mode || !filp->f_path.mnt)
1294		return 0;
1295
1296	idx = tomoyo_read_lock();
1297	buf = tomoyo_get_path(&filp->f_path);
1298	if (!buf)
1299		goto out;
1300	if (!tomoyo_is_no_rewrite_file(buf)) {
1301		error = 0;
1302		goto out;
1303	}
1304	error = tomoyo_check_single_path_permission2(domain,
1305						     TOMOYO_TYPE_REWRITE_ACL,
1306						     buf, mode);
1307 out:
1308	tomoyo_free(buf);
1309	tomoyo_read_unlock(idx);
1310	if (!is_enforce)
1311		error = 0;
1312	return error;
1313}
1314
1315/**
1316 * tomoyo_check_2path_perm - Check permission for "rename", "link" and "pivot_root".
1317 *
1318 * @domain:    Pointer to "struct tomoyo_domain_info".
1319 * @operation: Type of operation.
1320 * @path1:      Pointer to "struct path".
1321 * @path2:      Pointer to "struct path".
1322 *
1323 * Returns 0 on success, negative value otherwise.
1324 */
1325int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
1326			    const u8 operation, struct path *path1,
1327			    struct path *path2)
1328{
1329	int error = -ENOMEM;
1330	struct tomoyo_path_info *buf1, *buf2;
1331	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1332	const bool is_enforce = (mode == 3);
1333	const char *msg;
1334	int idx;
1335
1336	if (!mode || !path1->mnt || !path2->mnt)
1337		return 0;
1338	idx = tomoyo_read_lock();
1339	buf1 = tomoyo_get_path(path1);
1340	buf2 = tomoyo_get_path(path2);
1341	if (!buf1 || !buf2)
1342		goto out;
1343	{
1344		struct dentry *dentry = path1->dentry;
1345		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
1346			/*
1347			 * tomoyo_get_path() reserves space for appending "/."
1348			 */
1349			if (!buf1->is_dir) {
1350				strcat((char *) buf1->name, "/");
1351				tomoyo_fill_path_info(buf1);
1352			}
1353			if (!buf2->is_dir) {
1354				strcat((char *) buf2->name, "/");
1355				tomoyo_fill_path_info(buf2);
1356			}
1357		}
1358	}
1359	error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2);
1360	msg = tomoyo_dp2keyword(operation);
1361	if (!error)
1362		goto out;
1363	if (tomoyo_verbose_mode(domain))
1364		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
1365		       "denied for %s\n", tomoyo_get_msg(is_enforce),
1366		       msg, buf1->name, buf2->name,
1367		       tomoyo_get_last_name(domain));
1368	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
1369		const char *name1 = tomoyo_get_file_pattern(buf1)->name;
1370		const char *name2 = tomoyo_get_file_pattern(buf2)->name;
1371		tomoyo_update_double_path_acl(operation, name1, name2, domain,
1372					      false);
1373	}
1374 out:
1375	tomoyo_free(buf1);
1376	tomoyo_free(buf2);
1377	tomoyo_read_unlock(idx);
1378	if (!is_enforce)
1379		error = 0;
1380	return error;
1381}
1382