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