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