diff options
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 1143 |
1 files changed, 23 insertions, 1120 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ee46aaa3566f..57ddfc5d9c52 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -3,10 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Common functions for TOMOYO. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION |
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
@@ -15,12 +12,6 @@ | |||
15 | #include <linux/hardirq.h> | 12 | #include <linux/hardirq.h> |
16 | #include "common.h" | 13 | #include "common.h" |
17 | 14 | ||
18 | /* Lock for protecting policy. */ | ||
19 | DEFINE_MUTEX(tomoyo_policy_lock); | ||
20 | |||
21 | /* Has loading policy done? */ | ||
22 | bool tomoyo_policy_loaded; | ||
23 | |||
24 | /* String table for functionality that takes 4 modes. */ | 15 | /* String table for functionality that takes 4 modes. */ |
25 | static const char *tomoyo_mode_4[4] = { | 16 | static const char *tomoyo_mode_4[4] = { |
26 | "disabled", "learning", "permissive", "enforcing" | 17 | "disabled", "learning", "permissive", "enforcing" |
@@ -64,42 +55,6 @@ static bool tomoyo_manage_by_non_root; | |||
64 | 55 | ||
65 | /* Utility functions. */ | 56 | /* Utility functions. */ |
66 | 57 | ||
67 | /* Open operation for /sys/kernel/security/tomoyo/ interface. */ | ||
68 | static int tomoyo_open_control(const u8 type, struct file *file); | ||
69 | /* Close /sys/kernel/security/tomoyo/ interface. */ | ||
70 | static int tomoyo_close_control(struct file *file); | ||
71 | /* Read operation for /sys/kernel/security/tomoyo/ interface. */ | ||
72 | static int tomoyo_read_control(struct file *file, char __user *buffer, | ||
73 | const int buffer_len); | ||
74 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ | ||
75 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | ||
76 | const int buffer_len); | ||
77 | /* Check whether the domain has too many ACL entries to hold. */ | ||
78 | static bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); | ||
79 | |||
80 | /** | ||
81 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | ||
82 | * | ||
83 | * @filename: Name or name group. | ||
84 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
85 | * | ||
86 | * Returns true on success, false otherwise. | ||
87 | */ | ||
88 | bool tomoyo_parse_name_union(const char *filename, | ||
89 | struct tomoyo_name_union *ptr) | ||
90 | { | ||
91 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) | ||
92 | return false; | ||
93 | if (filename[0] == '@') { | ||
94 | ptr->group = tomoyo_get_path_group(filename + 1); | ||
95 | ptr->is_group = true; | ||
96 | return ptr->group != NULL; | ||
97 | } | ||
98 | ptr->filename = tomoyo_get_name(filename); | ||
99 | ptr->is_group = false; | ||
100 | return ptr->filename != NULL; | ||
101 | } | ||
102 | |||
103 | /** | 58 | /** |
104 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 59 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
105 | * | 60 | * |
@@ -121,69 +76,6 @@ static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, | |||
121 | } | 76 | } |
122 | 77 | ||
123 | /** | 78 | /** |
124 | * tomoyo_parse_ulong - Parse an "unsigned long" value. | ||
125 | * | ||
126 | * @result: Pointer to "unsigned long". | ||
127 | * @str: Pointer to string to parse. | ||
128 | * | ||
129 | * Returns value type on success, 0 otherwise. | ||
130 | * | ||
131 | * The @src is updated to point the first character after the value | ||
132 | * on success. | ||
133 | */ | ||
134 | u8 tomoyo_parse_ulong(unsigned long *result, char **str) | ||
135 | { | ||
136 | const char *cp = *str; | ||
137 | char *ep; | ||
138 | int base = 10; | ||
139 | if (*cp == '0') { | ||
140 | char c = *(cp + 1); | ||
141 | if (c == 'x' || c == 'X') { | ||
142 | base = 16; | ||
143 | cp += 2; | ||
144 | } else if (c >= '0' && c <= '7') { | ||
145 | base = 8; | ||
146 | cp++; | ||
147 | } | ||
148 | } | ||
149 | *result = simple_strtoul(cp, &ep, base); | ||
150 | if (cp == ep) | ||
151 | return 0; | ||
152 | *str = ep; | ||
153 | switch (base) { | ||
154 | case 16: | ||
155 | return TOMOYO_VALUE_TYPE_HEXADECIMAL; | ||
156 | case 8: | ||
157 | return TOMOYO_VALUE_TYPE_OCTAL; | ||
158 | default: | ||
159 | return TOMOYO_VALUE_TYPE_DECIMAL; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * tomoyo_print_ulong - Print an "unsigned long" value. | ||
165 | * | ||
166 | * @buffer: Pointer to buffer. | ||
167 | * @buffer_len: Size of @buffer. | ||
168 | * @value: An "unsigned long" value. | ||
169 | * @type: Type of @value. | ||
170 | * | ||
171 | * Returns nothing. | ||
172 | */ | ||
173 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | ||
174 | const unsigned long value, const u8 type) | ||
175 | { | ||
176 | if (type == TOMOYO_VALUE_TYPE_DECIMAL) | ||
177 | snprintf(buffer, buffer_len, "%lu", value); | ||
178 | else if (type == TOMOYO_VALUE_TYPE_OCTAL) | ||
179 | snprintf(buffer, buffer_len, "0%lo", value); | ||
180 | else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) | ||
181 | snprintf(buffer, buffer_len, "0x%lX", value); | ||
182 | else | ||
183 | snprintf(buffer, buffer_len, "type(%u)", type); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * tomoyo_print_number_union - Print a tomoyo_number_union. | 79 | * tomoyo_print_number_union - Print a tomoyo_number_union. |
188 | * | 80 | * |
189 | * @head: Pointer to "struct tomoyo_io_buffer". | 81 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -234,704 +126,6 @@ bool tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
234 | } | 126 | } |
235 | 127 | ||
236 | /** | 128 | /** |
237 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. | ||
238 | * | ||
239 | * @data: Number or number range or number group. | ||
240 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
241 | * | ||
242 | * Returns true on success, false otherwise. | ||
243 | */ | ||
244 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) | ||
245 | { | ||
246 | u8 type; | ||
247 | unsigned long v; | ||
248 | memset(num, 0, sizeof(*num)); | ||
249 | if (data[0] == '@') { | ||
250 | if (!tomoyo_is_correct_path(data, 0, 0, 0)) | ||
251 | return false; | ||
252 | num->group = tomoyo_get_number_group(data + 1); | ||
253 | num->is_group = true; | ||
254 | return num->group != NULL; | ||
255 | } | ||
256 | type = tomoyo_parse_ulong(&v, &data); | ||
257 | if (!type) | ||
258 | return false; | ||
259 | num->values[0] = v; | ||
260 | num->min_type = type; | ||
261 | if (!*data) { | ||
262 | num->values[1] = v; | ||
263 | num->max_type = type; | ||
264 | return true; | ||
265 | } | ||
266 | if (*data++ != '-') | ||
267 | return false; | ||
268 | type = tomoyo_parse_ulong(&v, &data); | ||
269 | if (!type || *data) | ||
270 | return false; | ||
271 | num->values[1] = v; | ||
272 | num->max_type = type; | ||
273 | return true; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. | ||
278 | * | ||
279 | * @str: Pointer to the string. | ||
280 | * | ||
281 | * Returns true if @str is a \ooo style octal value, false otherwise. | ||
282 | * | ||
283 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. | ||
284 | * This function verifies that \ooo is in valid range. | ||
285 | */ | ||
286 | static inline bool tomoyo_is_byte_range(const char *str) | ||
287 | { | ||
288 | return *str >= '0' && *str++ <= '3' && | ||
289 | *str >= '0' && *str++ <= '7' && | ||
290 | *str >= '0' && *str <= '7'; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * tomoyo_is_alphabet_char - Check whether the character is an alphabet. | ||
295 | * | ||
296 | * @c: The character to check. | ||
297 | * | ||
298 | * Returns true if @c is an alphabet character, false otherwise. | ||
299 | */ | ||
300 | static inline bool tomoyo_is_alphabet_char(const char c) | ||
301 | { | ||
302 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * tomoyo_make_byte - Make byte value from three octal characters. | ||
307 | * | ||
308 | * @c1: The first character. | ||
309 | * @c2: The second character. | ||
310 | * @c3: The third character. | ||
311 | * | ||
312 | * Returns byte value. | ||
313 | */ | ||
314 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) | ||
315 | { | ||
316 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. | ||
321 | * | ||
322 | * @src: Pointer to pointer to the string. | ||
323 | * @find: Pointer to the keyword. | ||
324 | * | ||
325 | * Returns true if @src starts with @find, false otherwise. | ||
326 | * | ||
327 | * The @src is updated to point the first character after the @find | ||
328 | * if @src starts with @find. | ||
329 | */ | ||
330 | static bool tomoyo_str_starts(char **src, const char *find) | ||
331 | { | ||
332 | const int len = strlen(find); | ||
333 | char *tmp = *src; | ||
334 | |||
335 | if (strncmp(tmp, find, len)) | ||
336 | return false; | ||
337 | tmp += len; | ||
338 | *src = tmp; | ||
339 | return true; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * tomoyo_normalize_line - Format string. | ||
344 | * | ||
345 | * @buffer: The line to normalize. | ||
346 | * | ||
347 | * Leading and trailing whitespaces are removed. | ||
348 | * Multiple whitespaces are packed into single space. | ||
349 | * | ||
350 | * Returns nothing. | ||
351 | */ | ||
352 | static void tomoyo_normalize_line(unsigned char *buffer) | ||
353 | { | ||
354 | unsigned char *sp = buffer; | ||
355 | unsigned char *dp = buffer; | ||
356 | bool first = true; | ||
357 | |||
358 | while (tomoyo_is_invalid(*sp)) | ||
359 | sp++; | ||
360 | while (*sp) { | ||
361 | if (!first) | ||
362 | *dp++ = ' '; | ||
363 | first = false; | ||
364 | while (tomoyo_is_valid(*sp)) | ||
365 | *dp++ = *sp++; | ||
366 | while (tomoyo_is_invalid(*sp)) | ||
367 | sp++; | ||
368 | } | ||
369 | *dp = '\0'; | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * tomoyo_tokenize - Tokenize string. | ||
374 | * | ||
375 | * @buffer: The line to tokenize. | ||
376 | * @w: Pointer to "char *". | ||
377 | * @size: Sizeof @w . | ||
378 | * | ||
379 | * Returns true on success, false otherwise. | ||
380 | */ | ||
381 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size) | ||
382 | { | ||
383 | int count = size / sizeof(char *); | ||
384 | int i; | ||
385 | for (i = 0; i < count; i++) | ||
386 | w[i] = ""; | ||
387 | for (i = 0; i < count; i++) { | ||
388 | char *cp = strchr(buffer, ' '); | ||
389 | if (cp) | ||
390 | *cp = '\0'; | ||
391 | w[i] = buffer; | ||
392 | if (!cp) | ||
393 | break; | ||
394 | buffer = cp + 1; | ||
395 | } | ||
396 | return i < count || !*buffer; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * tomoyo_is_correct_path - Validate a pathname. | ||
401 | * @filename: The pathname to check. | ||
402 | * @start_type: Should the pathname start with '/'? | ||
403 | * 1 = must / -1 = must not / 0 = don't care | ||
404 | * @pattern_type: Can the pathname contain a wildcard? | ||
405 | * 1 = must / -1 = must not / 0 = don't care | ||
406 | * @end_type: Should the pathname end with '/'? | ||
407 | * 1 = must / -1 = must not / 0 = don't care | ||
408 | * | ||
409 | * Check whether the given filename follows the naming rules. | ||
410 | * Returns true if @filename follows the naming rules, false otherwise. | ||
411 | */ | ||
412 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | ||
413 | const s8 pattern_type, const s8 end_type) | ||
414 | { | ||
415 | const char *const start = filename; | ||
416 | bool in_repetition = false; | ||
417 | bool contains_pattern = false; | ||
418 | unsigned char c; | ||
419 | unsigned char d; | ||
420 | unsigned char e; | ||
421 | |||
422 | if (!filename) | ||
423 | goto out; | ||
424 | c = *filename; | ||
425 | if (start_type == 1) { /* Must start with '/' */ | ||
426 | if (c != '/') | ||
427 | goto out; | ||
428 | } else if (start_type == -1) { /* Must not start with '/' */ | ||
429 | if (c == '/') | ||
430 | goto out; | ||
431 | } | ||
432 | if (c) | ||
433 | c = *(filename + strlen(filename) - 1); | ||
434 | if (end_type == 1) { /* Must end with '/' */ | ||
435 | if (c != '/') | ||
436 | goto out; | ||
437 | } else if (end_type == -1) { /* Must not end with '/' */ | ||
438 | if (c == '/') | ||
439 | goto out; | ||
440 | } | ||
441 | while (1) { | ||
442 | c = *filename++; | ||
443 | if (!c) | ||
444 | break; | ||
445 | if (c == '\\') { | ||
446 | c = *filename++; | ||
447 | switch (c) { | ||
448 | case '\\': /* "\\" */ | ||
449 | continue; | ||
450 | case '$': /* "\$" */ | ||
451 | case '+': /* "\+" */ | ||
452 | case '?': /* "\?" */ | ||
453 | case '*': /* "\*" */ | ||
454 | case '@': /* "\@" */ | ||
455 | case 'x': /* "\x" */ | ||
456 | case 'X': /* "\X" */ | ||
457 | case 'a': /* "\a" */ | ||
458 | case 'A': /* "\A" */ | ||
459 | case '-': /* "\-" */ | ||
460 | if (pattern_type == -1) | ||
461 | break; /* Must not contain pattern */ | ||
462 | contains_pattern = true; | ||
463 | continue; | ||
464 | case '{': /* "/\{" */ | ||
465 | if (filename - 3 < start || | ||
466 | *(filename - 3) != '/') | ||
467 | break; | ||
468 | if (pattern_type == -1) | ||
469 | break; /* Must not contain pattern */ | ||
470 | contains_pattern = true; | ||
471 | in_repetition = true; | ||
472 | continue; | ||
473 | case '}': /* "\}/" */ | ||
474 | if (*filename != '/') | ||
475 | break; | ||
476 | if (!in_repetition) | ||
477 | break; | ||
478 | in_repetition = false; | ||
479 | continue; | ||
480 | case '0': /* "\ooo" */ | ||
481 | case '1': | ||
482 | case '2': | ||
483 | case '3': | ||
484 | d = *filename++; | ||
485 | if (d < '0' || d > '7') | ||
486 | break; | ||
487 | e = *filename++; | ||
488 | if (e < '0' || e > '7') | ||
489 | break; | ||
490 | c = tomoyo_make_byte(c, d, e); | ||
491 | if (tomoyo_is_invalid(c)) | ||
492 | continue; /* pattern is not \000 */ | ||
493 | } | ||
494 | goto out; | ||
495 | } else if (in_repetition && c == '/') { | ||
496 | goto out; | ||
497 | } else if (tomoyo_is_invalid(c)) { | ||
498 | goto out; | ||
499 | } | ||
500 | } | ||
501 | if (pattern_type == 1) { /* Must contain pattern */ | ||
502 | if (!contains_pattern) | ||
503 | goto out; | ||
504 | } | ||
505 | if (in_repetition) | ||
506 | goto out; | ||
507 | return true; | ||
508 | out: | ||
509 | return false; | ||
510 | } | ||
511 | |||
512 | /** | ||
513 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. | ||
514 | * @domainname: The domainname to check. | ||
515 | * | ||
516 | * Returns true if @domainname follows the naming rules, false otherwise. | ||
517 | */ | ||
518 | bool tomoyo_is_correct_domain(const unsigned char *domainname) | ||
519 | { | ||
520 | unsigned char c; | ||
521 | unsigned char d; | ||
522 | unsigned char e; | ||
523 | |||
524 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | ||
525 | TOMOYO_ROOT_NAME_LEN)) | ||
526 | goto out; | ||
527 | domainname += TOMOYO_ROOT_NAME_LEN; | ||
528 | if (!*domainname) | ||
529 | return true; | ||
530 | do { | ||
531 | if (*domainname++ != ' ') | ||
532 | goto out; | ||
533 | if (*domainname++ != '/') | ||
534 | goto out; | ||
535 | while ((c = *domainname) != '\0' && c != ' ') { | ||
536 | domainname++; | ||
537 | if (c == '\\') { | ||
538 | c = *domainname++; | ||
539 | switch ((c)) { | ||
540 | case '\\': /* "\\" */ | ||
541 | continue; | ||
542 | case '0': /* "\ooo" */ | ||
543 | case '1': | ||
544 | case '2': | ||
545 | case '3': | ||
546 | d = *domainname++; | ||
547 | if (d < '0' || d > '7') | ||
548 | break; | ||
549 | e = *domainname++; | ||
550 | if (e < '0' || e > '7') | ||
551 | break; | ||
552 | c = tomoyo_make_byte(c, d, e); | ||
553 | if (tomoyo_is_invalid(c)) | ||
554 | /* pattern is not \000 */ | ||
555 | continue; | ||
556 | } | ||
557 | goto out; | ||
558 | } else if (tomoyo_is_invalid(c)) { | ||
559 | goto out; | ||
560 | } | ||
561 | } | ||
562 | } while (*domainname); | ||
563 | return true; | ||
564 | out: | ||
565 | return false; | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * tomoyo_is_domain_def - Check whether the given token can be a domainname. | ||
570 | * | ||
571 | * @buffer: The token to check. | ||
572 | * | ||
573 | * Returns true if @buffer possibly be a domainname, false otherwise. | ||
574 | */ | ||
575 | bool tomoyo_is_domain_def(const unsigned char *buffer) | ||
576 | { | ||
577 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * tomoyo_find_domain - Find a domain by the given name. | ||
582 | * | ||
583 | * @domainname: The domainname to find. | ||
584 | * | ||
585 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | ||
586 | * | ||
587 | * Caller holds tomoyo_read_lock(). | ||
588 | */ | ||
589 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | ||
590 | { | ||
591 | struct tomoyo_domain_info *domain; | ||
592 | struct tomoyo_path_info name; | ||
593 | |||
594 | name.name = domainname; | ||
595 | tomoyo_fill_path_info(&name); | ||
596 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
597 | if (!domain->is_deleted && | ||
598 | !tomoyo_pathcmp(&name, domain->domainname)) | ||
599 | return domain; | ||
600 | } | ||
601 | return NULL; | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. | ||
606 | * | ||
607 | * @filename: The string to evaluate. | ||
608 | * | ||
609 | * Returns the initial length without a pattern in @filename. | ||
610 | */ | ||
611 | static int tomoyo_const_part_length(const char *filename) | ||
612 | { | ||
613 | char c; | ||
614 | int len = 0; | ||
615 | |||
616 | if (!filename) | ||
617 | return 0; | ||
618 | while ((c = *filename++) != '\0') { | ||
619 | if (c != '\\') { | ||
620 | len++; | ||
621 | continue; | ||
622 | } | ||
623 | c = *filename++; | ||
624 | switch (c) { | ||
625 | case '\\': /* "\\" */ | ||
626 | len += 2; | ||
627 | continue; | ||
628 | case '0': /* "\ooo" */ | ||
629 | case '1': | ||
630 | case '2': | ||
631 | case '3': | ||
632 | c = *filename++; | ||
633 | if (c < '0' || c > '7') | ||
634 | break; | ||
635 | c = *filename++; | ||
636 | if (c < '0' || c > '7') | ||
637 | break; | ||
638 | len += 4; | ||
639 | continue; | ||
640 | } | ||
641 | break; | ||
642 | } | ||
643 | return len; | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. | ||
648 | * | ||
649 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. | ||
650 | * | ||
651 | * The caller sets "struct tomoyo_path_info"->name. | ||
652 | */ | ||
653 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | ||
654 | { | ||
655 | const char *name = ptr->name; | ||
656 | const int len = strlen(name); | ||
657 | |||
658 | ptr->const_len = tomoyo_const_part_length(name); | ||
659 | ptr->is_dir = len && (name[len - 1] == '/'); | ||
660 | ptr->is_patterned = (ptr->const_len < len); | ||
661 | ptr->hash = full_name_hash(name, len); | ||
662 | } | ||
663 | |||
664 | /** | ||
665 | * tomoyo_file_matches_pattern2 - Pattern matching without '/' character | ||
666 | * and "\-" pattern. | ||
667 | * | ||
668 | * @filename: The start of string to check. | ||
669 | * @filename_end: The end of string to check. | ||
670 | * @pattern: The start of pattern to compare. | ||
671 | * @pattern_end: The end of pattern to compare. | ||
672 | * | ||
673 | * Returns true if @filename matches @pattern, false otherwise. | ||
674 | */ | ||
675 | static bool tomoyo_file_matches_pattern2(const char *filename, | ||
676 | const char *filename_end, | ||
677 | const char *pattern, | ||
678 | const char *pattern_end) | ||
679 | { | ||
680 | while (filename < filename_end && pattern < pattern_end) { | ||
681 | char c; | ||
682 | if (*pattern != '\\') { | ||
683 | if (*filename++ != *pattern++) | ||
684 | return false; | ||
685 | continue; | ||
686 | } | ||
687 | c = *filename; | ||
688 | pattern++; | ||
689 | switch (*pattern) { | ||
690 | int i; | ||
691 | int j; | ||
692 | case '?': | ||
693 | if (c == '/') { | ||
694 | return false; | ||
695 | } else if (c == '\\') { | ||
696 | if (filename[1] == '\\') | ||
697 | filename++; | ||
698 | else if (tomoyo_is_byte_range(filename + 1)) | ||
699 | filename += 3; | ||
700 | else | ||
701 | return false; | ||
702 | } | ||
703 | break; | ||
704 | case '\\': | ||
705 | if (c != '\\') | ||
706 | return false; | ||
707 | if (*++filename != '\\') | ||
708 | return false; | ||
709 | break; | ||
710 | case '+': | ||
711 | if (!isdigit(c)) | ||
712 | return false; | ||
713 | break; | ||
714 | case 'x': | ||
715 | if (!isxdigit(c)) | ||
716 | return false; | ||
717 | break; | ||
718 | case 'a': | ||
719 | if (!tomoyo_is_alphabet_char(c)) | ||
720 | return false; | ||
721 | break; | ||
722 | case '0': | ||
723 | case '1': | ||
724 | case '2': | ||
725 | case '3': | ||
726 | if (c == '\\' && tomoyo_is_byte_range(filename + 1) | ||
727 | && strncmp(filename + 1, pattern, 3) == 0) { | ||
728 | filename += 3; | ||
729 | pattern += 2; | ||
730 | break; | ||
731 | } | ||
732 | return false; /* Not matched. */ | ||
733 | case '*': | ||
734 | case '@': | ||
735 | for (i = 0; i <= filename_end - filename; i++) { | ||
736 | if (tomoyo_file_matches_pattern2( | ||
737 | filename + i, filename_end, | ||
738 | pattern + 1, pattern_end)) | ||
739 | return true; | ||
740 | c = filename[i]; | ||
741 | if (c == '.' && *pattern == '@') | ||
742 | break; | ||
743 | if (c != '\\') | ||
744 | continue; | ||
745 | if (filename[i + 1] == '\\') | ||
746 | i++; | ||
747 | else if (tomoyo_is_byte_range(filename + i + 1)) | ||
748 | i += 3; | ||
749 | else | ||
750 | break; /* Bad pattern. */ | ||
751 | } | ||
752 | return false; /* Not matched. */ | ||
753 | default: | ||
754 | j = 0; | ||
755 | c = *pattern; | ||
756 | if (c == '$') { | ||
757 | while (isdigit(filename[j])) | ||
758 | j++; | ||
759 | } else if (c == 'X') { | ||
760 | while (isxdigit(filename[j])) | ||
761 | j++; | ||
762 | } else if (c == 'A') { | ||
763 | while (tomoyo_is_alphabet_char(filename[j])) | ||
764 | j++; | ||
765 | } | ||
766 | for (i = 1; i <= j; i++) { | ||
767 | if (tomoyo_file_matches_pattern2( | ||
768 | filename + i, filename_end, | ||
769 | pattern + 1, pattern_end)) | ||
770 | return true; | ||
771 | } | ||
772 | return false; /* Not matched or bad pattern. */ | ||
773 | } | ||
774 | filename++; | ||
775 | pattern++; | ||
776 | } | ||
777 | while (*pattern == '\\' && | ||
778 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) | ||
779 | pattern += 2; | ||
780 | return filename == filename_end && pattern == pattern_end; | ||
781 | } | ||
782 | |||
783 | /** | ||
784 | * tomoyo_file_matches_pattern - Pattern matching without without '/' character. | ||
785 | * | ||
786 | * @filename: The start of string to check. | ||
787 | * @filename_end: The end of string to check. | ||
788 | * @pattern: The start of pattern to compare. | ||
789 | * @pattern_end: The end of pattern to compare. | ||
790 | * | ||
791 | * Returns true if @filename matches @pattern, false otherwise. | ||
792 | */ | ||
793 | static bool tomoyo_file_matches_pattern(const char *filename, | ||
794 | const char *filename_end, | ||
795 | const char *pattern, | ||
796 | const char *pattern_end) | ||
797 | { | ||
798 | const char *pattern_start = pattern; | ||
799 | bool first = true; | ||
800 | bool result; | ||
801 | |||
802 | while (pattern < pattern_end - 1) { | ||
803 | /* Split at "\-" pattern. */ | ||
804 | if (*pattern++ != '\\' || *pattern++ != '-') | ||
805 | continue; | ||
806 | result = tomoyo_file_matches_pattern2(filename, | ||
807 | filename_end, | ||
808 | pattern_start, | ||
809 | pattern - 2); | ||
810 | if (first) | ||
811 | result = !result; | ||
812 | if (result) | ||
813 | return false; | ||
814 | first = false; | ||
815 | pattern_start = pattern; | ||
816 | } | ||
817 | result = tomoyo_file_matches_pattern2(filename, filename_end, | ||
818 | pattern_start, pattern_end); | ||
819 | return first ? result : !result; | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * tomoyo_path_matches_pattern2 - Do pathname pattern matching. | ||
824 | * | ||
825 | * @f: The start of string to check. | ||
826 | * @p: The start of pattern to compare. | ||
827 | * | ||
828 | * Returns true if @f matches @p, false otherwise. | ||
829 | */ | ||
830 | static bool tomoyo_path_matches_pattern2(const char *f, const char *p) | ||
831 | { | ||
832 | const char *f_delimiter; | ||
833 | const char *p_delimiter; | ||
834 | |||
835 | while (*f && *p) { | ||
836 | f_delimiter = strchr(f, '/'); | ||
837 | if (!f_delimiter) | ||
838 | f_delimiter = f + strlen(f); | ||
839 | p_delimiter = strchr(p, '/'); | ||
840 | if (!p_delimiter) | ||
841 | p_delimiter = p + strlen(p); | ||
842 | if (*p == '\\' && *(p + 1) == '{') | ||
843 | goto recursive; | ||
844 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p, | ||
845 | p_delimiter)) | ||
846 | return false; | ||
847 | f = f_delimiter; | ||
848 | if (*f) | ||
849 | f++; | ||
850 | p = p_delimiter; | ||
851 | if (*p) | ||
852 | p++; | ||
853 | } | ||
854 | /* Ignore trailing "\*" and "\@" in @pattern. */ | ||
855 | while (*p == '\\' && | ||
856 | (*(p + 1) == '*' || *(p + 1) == '@')) | ||
857 | p += 2; | ||
858 | return !*f && !*p; | ||
859 | recursive: | ||
860 | /* | ||
861 | * The "\{" pattern is permitted only after '/' character. | ||
862 | * This guarantees that below "*(p - 1)" is safe. | ||
863 | * Also, the "\}" pattern is permitted only before '/' character | ||
864 | * so that "\{" + "\}" pair will not break the "\-" operator. | ||
865 | */ | ||
866 | if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || | ||
867 | *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') | ||
868 | return false; /* Bad pattern. */ | ||
869 | do { | ||
870 | /* Compare current component with pattern. */ | ||
871 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, | ||
872 | p_delimiter - 2)) | ||
873 | break; | ||
874 | /* Proceed to next component. */ | ||
875 | f = f_delimiter; | ||
876 | if (!*f) | ||
877 | break; | ||
878 | f++; | ||
879 | /* Continue comparison. */ | ||
880 | if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) | ||
881 | return true; | ||
882 | f_delimiter = strchr(f, '/'); | ||
883 | } while (f_delimiter); | ||
884 | return false; /* Not matched. */ | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. | ||
889 | * | ||
890 | * @filename: The filename to check. | ||
891 | * @pattern: The pattern to compare. | ||
892 | * | ||
893 | * Returns true if matches, false otherwise. | ||
894 | * | ||
895 | * The following patterns are available. | ||
896 | * \\ \ itself. | ||
897 | * \ooo Octal representation of a byte. | ||
898 | * \* Zero or more repetitions of characters other than '/'. | ||
899 | * \@ Zero or more repetitions of characters other than '/' or '.'. | ||
900 | * \? 1 byte character other than '/'. | ||
901 | * \$ One or more repetitions of decimal digits. | ||
902 | * \+ 1 decimal digit. | ||
903 | * \X One or more repetitions of hexadecimal digits. | ||
904 | * \x 1 hexadecimal digit. | ||
905 | * \A One or more repetitions of alphabet characters. | ||
906 | * \a 1 alphabet character. | ||
907 | * | ||
908 | * \- Subtraction operator. | ||
909 | * | ||
910 | * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ | ||
911 | * /dir/dir/dir/ ). | ||
912 | */ | ||
913 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | ||
914 | const struct tomoyo_path_info *pattern) | ||
915 | { | ||
916 | const char *f = filename->name; | ||
917 | const char *p = pattern->name; | ||
918 | const int len = pattern->const_len; | ||
919 | |||
920 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ | ||
921 | if (!pattern->is_patterned) | ||
922 | return !tomoyo_pathcmp(filename, pattern); | ||
923 | /* Don't compare directory and non-directory. */ | ||
924 | if (filename->is_dir != pattern->is_dir) | ||
925 | return false; | ||
926 | /* Compare the initial length without patterns. */ | ||
927 | if (strncmp(f, p, len)) | ||
928 | return false; | ||
929 | f += len; | ||
930 | p += len; | ||
931 | return tomoyo_path_matches_pattern2(f, p); | ||
932 | } | ||
933 | |||
934 | /** | ||
935 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. | 129 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. |
936 | * | 130 | * |
937 | * @head: Pointer to "struct tomoyo_io_buffer". | 131 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -960,33 +154,6 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | |||
960 | } | 154 | } |
961 | 155 | ||
962 | /** | 156 | /** |
963 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. | ||
964 | * | ||
965 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | ||
966 | * | ||
967 | * This function uses kzalloc(), so the caller must call kfree() | ||
968 | * if this function didn't return NULL. | ||
969 | */ | ||
970 | static const char *tomoyo_get_exe(void) | ||
971 | { | ||
972 | struct mm_struct *mm = current->mm; | ||
973 | struct vm_area_struct *vma; | ||
974 | const char *cp = NULL; | ||
975 | |||
976 | if (!mm) | ||
977 | return NULL; | ||
978 | down_read(&mm->mmap_sem); | ||
979 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
980 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { | ||
981 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); | ||
982 | break; | ||
983 | } | ||
984 | } | ||
985 | up_read(&mm->mmap_sem); | ||
986 | return cp; | ||
987 | } | ||
988 | |||
989 | /** | ||
990 | * tomoyo_check_flags - Check mode for specified functionality. | 157 | * tomoyo_check_flags - Check mode for specified functionality. |
991 | * | 158 | * |
992 | * @domain: Pointer to "struct tomoyo_domain_info". | 159 | * @domain: Pointer to "struct tomoyo_domain_info". |
@@ -1025,76 +192,6 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) | |||
1025 | } | 192 | } |
1026 | 193 | ||
1027 | /** | 194 | /** |
1028 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | ||
1029 | * | ||
1030 | * @r: Pointer to "struct tomoyo_request_info". | ||
1031 | * | ||
1032 | * Returns true if the domain is not exceeded quota, false otherwise. | ||
1033 | * | ||
1034 | * Caller holds tomoyo_read_lock(). | ||
1035 | */ | ||
1036 | static bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | ||
1037 | { | ||
1038 | unsigned int count = 0; | ||
1039 | struct tomoyo_domain_info *domain = r->domain; | ||
1040 | struct tomoyo_acl_info *ptr; | ||
1041 | |||
1042 | if (r->mode != TOMOYO_CONFIG_LEARNING) | ||
1043 | return false; | ||
1044 | if (!domain) | ||
1045 | return true; | ||
1046 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
1047 | switch (ptr->type) { | ||
1048 | u16 perm; | ||
1049 | u8 i; | ||
1050 | case TOMOYO_TYPE_PATH_ACL: | ||
1051 | perm = container_of(ptr, struct tomoyo_path_acl, head) | ||
1052 | ->perm; | ||
1053 | for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) | ||
1054 | if (perm & (1 << i)) | ||
1055 | count++; | ||
1056 | if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
1057 | count -= 2; | ||
1058 | break; | ||
1059 | case TOMOYO_TYPE_PATH2_ACL: | ||
1060 | perm = container_of(ptr, struct tomoyo_path2_acl, head) | ||
1061 | ->perm; | ||
1062 | for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) | ||
1063 | if (perm & (1 << i)) | ||
1064 | count++; | ||
1065 | break; | ||
1066 | case TOMOYO_TYPE_PATH_NUMBER_ACL: | ||
1067 | perm = container_of(ptr, struct tomoyo_path_number_acl, | ||
1068 | head)->perm; | ||
1069 | for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++) | ||
1070 | if (perm & (1 << i)) | ||
1071 | count++; | ||
1072 | break; | ||
1073 | case TOMOYO_TYPE_PATH_NUMBER3_ACL: | ||
1074 | perm = container_of(ptr, struct tomoyo_path_number3_acl, | ||
1075 | head)->perm; | ||
1076 | for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++) | ||
1077 | if (perm & (1 << i)) | ||
1078 | count++; | ||
1079 | break; | ||
1080 | case TOMOYO_TYPE_MOUNT_ACL: | ||
1081 | if (!container_of(ptr, struct tomoyo_mount_acl, head)-> | ||
1082 | is_deleted) | ||
1083 | count++; | ||
1084 | } | ||
1085 | } | ||
1086 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | ||
1087 | return true; | ||
1088 | if (!domain->quota_warned) { | ||
1089 | domain->quota_warned = true; | ||
1090 | printk(KERN_WARNING "TOMOYO-WARNING: " | ||
1091 | "Domain '%s' has so many ACLs to hold. " | ||
1092 | "Stopped learning mode.\n", domain->domainname->name); | ||
1093 | } | ||
1094 | return false; | ||
1095 | } | ||
1096 | |||
1097 | /** | ||
1098 | * tomoyo_find_or_assign_new_profile - Create a new profile. | 195 | * tomoyo_find_or_assign_new_profile - Create a new profile. |
1099 | * | 196 | * |
1100 | * @profile: Profile number to create. | 197 | * @profile: Profile number to create. |
@@ -2118,91 +1215,6 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | |||
2118 | return 0; | 1215 | return 0; |
2119 | } | 1216 | } |
2120 | 1217 | ||
2121 | /* path to policy loader */ | ||
2122 | static const char *tomoyo_loader = "/sbin/tomoyo-init"; | ||
2123 | |||
2124 | /** | ||
2125 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. | ||
2126 | * | ||
2127 | * Returns true if /sbin/tomoyo-init exists, false otherwise. | ||
2128 | */ | ||
2129 | static bool tomoyo_policy_loader_exists(void) | ||
2130 | { | ||
2131 | /* | ||
2132 | * Don't activate MAC if the policy loader doesn't exist. | ||
2133 | * If the initrd includes /sbin/init but real-root-dev has not | ||
2134 | * mounted on / yet, activating MAC will block the system since | ||
2135 | * policies are not loaded yet. | ||
2136 | * Thus, let do_execve() call this function everytime. | ||
2137 | */ | ||
2138 | struct path path; | ||
2139 | |||
2140 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | ||
2141 | printk(KERN_INFO "Not activating Mandatory Access Control now " | ||
2142 | "since %s doesn't exist.\n", tomoyo_loader); | ||
2143 | return false; | ||
2144 | } | ||
2145 | path_put(&path); | ||
2146 | return true; | ||
2147 | } | ||
2148 | |||
2149 | /** | ||
2150 | * tomoyo_load_policy - Run external policy loader to load policy. | ||
2151 | * | ||
2152 | * @filename: The program about to start. | ||
2153 | * | ||
2154 | * This function checks whether @filename is /sbin/init , and if so | ||
2155 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init | ||
2156 | * and then continues invocation of /sbin/init. | ||
2157 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and | ||
2158 | * writes to /sys/kernel/security/tomoyo/ interfaces. | ||
2159 | * | ||
2160 | * Returns nothing. | ||
2161 | */ | ||
2162 | void tomoyo_load_policy(const char *filename) | ||
2163 | { | ||
2164 | char *argv[2]; | ||
2165 | char *envp[3]; | ||
2166 | |||
2167 | if (tomoyo_policy_loaded) | ||
2168 | return; | ||
2169 | /* | ||
2170 | * Check filename is /sbin/init or /sbin/tomoyo-start. | ||
2171 | * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't | ||
2172 | * be passed. | ||
2173 | * You can create /sbin/tomoyo-start by | ||
2174 | * "ln -s /bin/true /sbin/tomoyo-start". | ||
2175 | */ | ||
2176 | if (strcmp(filename, "/sbin/init") && | ||
2177 | strcmp(filename, "/sbin/tomoyo-start")) | ||
2178 | return; | ||
2179 | if (!tomoyo_policy_loader_exists()) | ||
2180 | return; | ||
2181 | |||
2182 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | ||
2183 | tomoyo_loader); | ||
2184 | argv[0] = (char *) tomoyo_loader; | ||
2185 | argv[1] = NULL; | ||
2186 | envp[0] = "HOME=/"; | ||
2187 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | ||
2188 | envp[2] = NULL; | ||
2189 | call_usermodehelper(argv[0], argv, envp, 1); | ||
2190 | |||
2191 | printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n"); | ||
2192 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | ||
2193 | tomoyo_policy_loaded = true; | ||
2194 | { /* Check all profiles currently assigned to domains are defined. */ | ||
2195 | struct tomoyo_domain_info *domain; | ||
2196 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
2197 | const u8 profile = domain->profile; | ||
2198 | if (tomoyo_profile_ptr[profile]) | ||
2199 | continue; | ||
2200 | panic("Profile %u (used by '%s') not defined.\n", | ||
2201 | profile, domain->domainname->name); | ||
2202 | } | ||
2203 | } | ||
2204 | } | ||
2205 | |||
2206 | /** | 1218 | /** |
2207 | * tomoyo_print_header - Get header line of audit log. | 1219 | * tomoyo_print_header - Get header line of audit log. |
2208 | * | 1220 | * |
@@ -2601,7 +1613,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
2601 | * | 1613 | * |
2602 | * Caller acquires tomoyo_read_lock(). | 1614 | * Caller acquires tomoyo_read_lock(). |
2603 | */ | 1615 | */ |
2604 | static int tomoyo_open_control(const u8 type, struct file *file) | 1616 | int tomoyo_open_control(const u8 type, struct file *file) |
2605 | { | 1617 | { |
2606 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); | 1618 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); |
2607 | 1619 | ||
@@ -2744,8 +1756,8 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) | |||
2744 | * | 1756 | * |
2745 | * Caller holds tomoyo_read_lock(). | 1757 | * Caller holds tomoyo_read_lock(). |
2746 | */ | 1758 | */ |
2747 | static int tomoyo_read_control(struct file *file, char __user *buffer, | 1759 | int tomoyo_read_control(struct file *file, char __user *buffer, |
2748 | const int buffer_len) | 1760 | const int buffer_len) |
2749 | { | 1761 | { |
2750 | int len = 0; | 1762 | int len = 0; |
2751 | struct tomoyo_io_buffer *head = file->private_data; | 1763 | struct tomoyo_io_buffer *head = file->private_data; |
@@ -2789,8 +1801,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, | |||
2789 | * | 1801 | * |
2790 | * Caller holds tomoyo_read_lock(). | 1802 | * Caller holds tomoyo_read_lock(). |
2791 | */ | 1803 | */ |
2792 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 1804 | int tomoyo_write_control(struct file *file, const char __user *buffer, |
2793 | const int buffer_len) | 1805 | const int buffer_len) |
2794 | { | 1806 | { |
2795 | struct tomoyo_io_buffer *head = file->private_data; | 1807 | struct tomoyo_io_buffer *head = file->private_data; |
2796 | int error = buffer_len; | 1808 | int error = buffer_len; |
@@ -2841,7 +1853,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2841 | * | 1853 | * |
2842 | * Caller looses tomoyo_read_lock(). | 1854 | * Caller looses tomoyo_read_lock(). |
2843 | */ | 1855 | */ |
2844 | static int tomoyo_close_control(struct file *file) | 1856 | int tomoyo_close_control(struct file *file) |
2845 | { | 1857 | { |
2846 | struct tomoyo_io_buffer *head = file->private_data; | 1858 | struct tomoyo_io_buffer *head = file->private_data; |
2847 | const bool is_write = !!head->write_buf; | 1859 | const bool is_write = !!head->write_buf; |
@@ -2868,131 +1880,22 @@ static int tomoyo_close_control(struct file *file) | |||
2868 | } | 1880 | } |
2869 | 1881 | ||
2870 | /** | 1882 | /** |
2871 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 1883 | * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. |
2872 | * | ||
2873 | * @inode: Pointer to "struct inode". | ||
2874 | * @file: Pointer to "struct file". | ||
2875 | * | ||
2876 | * Returns 0 on success, negative value otherwise. | ||
2877 | */ | 1884 | */ |
2878 | static int tomoyo_open(struct inode *inode, struct file *file) | 1885 | void tomoyo_check_profile(void) |
2879 | { | 1886 | { |
2880 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) | 1887 | struct tomoyo_domain_info *domain; |
2881 | - ((u8 *) NULL); | 1888 | const int idx = tomoyo_read_lock(); |
2882 | return tomoyo_open_control(key, file); | 1889 | tomoyo_policy_loaded = true; |
2883 | } | 1890 | /* Check all profiles currently assigned to domains are defined. */ |
2884 | 1891 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | |
2885 | /** | 1892 | const u8 profile = domain->profile; |
2886 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. | 1893 | if (tomoyo_profile_ptr[profile]) |
2887 | * | 1894 | continue; |
2888 | * @inode: Pointer to "struct inode". | 1895 | panic("Profile %u (used by '%s') not defined.\n", |
2889 | * @file: Pointer to "struct file". | 1896 | profile, domain->domainname->name); |
2890 | * | 1897 | } |
2891 | * Returns 0 on success, negative value otherwise. | 1898 | tomoyo_read_unlock(idx); |
2892 | */ | 1899 | printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n"); |
2893 | static int tomoyo_release(struct inode *inode, struct file *file) | 1900 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2894 | { | ||
2895 | return tomoyo_close_control(file); | ||
2896 | } | ||
2897 | |||
2898 | /** | ||
2899 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. | ||
2900 | * | ||
2901 | * @file: Pointer to "struct file". | ||
2902 | * @buf: Pointer to buffer. | ||
2903 | * @count: Size of @buf. | ||
2904 | * @ppos: Unused. | ||
2905 | * | ||
2906 | * Returns bytes read on success, negative value otherwise. | ||
2907 | */ | ||
2908 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | ||
2909 | loff_t *ppos) | ||
2910 | { | ||
2911 | return tomoyo_read_control(file, buf, count); | ||
2912 | } | ||
2913 | |||
2914 | /** | ||
2915 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. | ||
2916 | * | ||
2917 | * @file: Pointer to "struct file". | ||
2918 | * @buf: Pointer to buffer. | ||
2919 | * @count: Size of @buf. | ||
2920 | * @ppos: Unused. | ||
2921 | * | ||
2922 | * Returns @count on success, negative value otherwise. | ||
2923 | */ | ||
2924 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, | ||
2925 | size_t count, loff_t *ppos) | ||
2926 | { | ||
2927 | return tomoyo_write_control(file, buf, count); | ||
2928 | } | ||
2929 | |||
2930 | /* | ||
2931 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
2932 | * /sys/kernel/security/tomoyo/ interface. | ||
2933 | * | ||
2934 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
2935 | * See tomoyo_io_buffer for internals. | ||
2936 | */ | ||
2937 | static const struct file_operations tomoyo_operations = { | ||
2938 | .open = tomoyo_open, | ||
2939 | .release = tomoyo_release, | ||
2940 | .read = tomoyo_read, | ||
2941 | .write = tomoyo_write, | ||
2942 | }; | ||
2943 | |||
2944 | /** | ||
2945 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. | ||
2946 | * | ||
2947 | * @name: The name of the interface file. | ||
2948 | * @mode: The permission of the interface file. | ||
2949 | * @parent: The parent directory. | ||
2950 | * @key: Type of interface. | ||
2951 | * | ||
2952 | * Returns nothing. | ||
2953 | */ | ||
2954 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, | ||
2955 | struct dentry *parent, const u8 key) | ||
2956 | { | ||
2957 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, | ||
2958 | &tomoyo_operations); | ||
2959 | } | ||
2960 | |||
2961 | /** | ||
2962 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. | ||
2963 | * | ||
2964 | * Returns 0. | ||
2965 | */ | ||
2966 | static int __init tomoyo_initerface_init(void) | ||
2967 | { | ||
2968 | struct dentry *tomoyo_dir; | ||
2969 | |||
2970 | /* Don't create securityfs entries unless registered. */ | ||
2971 | if (current_cred()->security != &tomoyo_kernel_domain) | ||
2972 | return 0; | ||
2973 | |||
2974 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | ||
2975 | tomoyo_create_entry("query", 0600, tomoyo_dir, | ||
2976 | TOMOYO_QUERY); | ||
2977 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, | ||
2978 | TOMOYO_DOMAINPOLICY); | ||
2979 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | ||
2980 | TOMOYO_EXCEPTIONPOLICY); | ||
2981 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | ||
2982 | TOMOYO_SELFDOMAIN); | ||
2983 | tomoyo_create_entry(".domain_status", 0600, tomoyo_dir, | ||
2984 | TOMOYO_DOMAIN_STATUS); | ||
2985 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | ||
2986 | TOMOYO_PROCESS_STATUS); | ||
2987 | tomoyo_create_entry("meminfo", 0600, tomoyo_dir, | ||
2988 | TOMOYO_MEMINFO); | ||
2989 | tomoyo_create_entry("profile", 0600, tomoyo_dir, | ||
2990 | TOMOYO_PROFILE); | ||
2991 | tomoyo_create_entry("manager", 0600, tomoyo_dir, | ||
2992 | TOMOYO_MANAGER); | ||
2993 | tomoyo_create_entry("version", 0400, tomoyo_dir, | ||
2994 | TOMOYO_VERSION); | ||
2995 | return 0; | ||
2996 | } | 1901 | } |
2997 | |||
2998 | fs_initcall(tomoyo_initerface_init); | ||