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