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