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