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