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