diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 1143 | ||||
-rw-r--r-- | security/tomoyo/common.h | 29 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 20 | ||||
-rw-r--r-- | security/tomoyo/file.c | 62 | ||||
-rw-r--r-- | security/tomoyo/load_policy.c | 81 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 236 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 214 | ||||
-rw-r--r-- | security/tomoyo/securityfs_if.c | 140 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 7 | ||||
-rw-r--r-- | security/tomoyo/util.c | 951 |
11 files changed, 1469 insertions, 1416 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index d7befab40eff..3aa6f076948e 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1 @@ | |||
obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o number_group.o mount.o | obj-y = common.o domain.o file.o gc.o load_policy.o memory.o mount.o number_group.o path_group.o realpath.o securityfs_if.o tomoyo.o util.o | ||
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); | ||
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index dc5f98f52f61..be03e4a21db0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -673,6 +673,31 @@ struct tomoyo_policy_manager_entry { | |||
673 | extern asmlinkage long sys_getpid(void); | 673 | extern asmlinkage long sys_getpid(void); |
674 | extern asmlinkage long sys_getppid(void); | 674 | extern asmlinkage long sys_getppid(void); |
675 | 675 | ||
676 | /* Check whether the given string starts with the given keyword. */ | ||
677 | bool tomoyo_str_starts(char **src, const char *find); | ||
678 | /* Get tomoyo_realpath() of current process. */ | ||
679 | const char *tomoyo_get_exe(void); | ||
680 | /* Format string. */ | ||
681 | void tomoyo_normalize_line(unsigned char *buffer); | ||
682 | /* Print warning or error message on console. */ | ||
683 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
684 | __attribute__ ((format(printf, 2, 3))); | ||
685 | /* Check all profiles currently assigned to domains are defined. */ | ||
686 | void tomoyo_check_profile(void); | ||
687 | /* Open operation for /sys/kernel/security/tomoyo/ interface. */ | ||
688 | int tomoyo_open_control(const u8 type, struct file *file); | ||
689 | /* Close /sys/kernel/security/tomoyo/ interface. */ | ||
690 | int tomoyo_close_control(struct file *file); | ||
691 | /* Read operation for /sys/kernel/security/tomoyo/ interface. */ | ||
692 | int tomoyo_read_control(struct file *file, char __user *buffer, | ||
693 | const int buffer_len); | ||
694 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ | ||
695 | int tomoyo_write_control(struct file *file, const char __user *buffer, | ||
696 | const int buffer_len); | ||
697 | /* Check whether the domain has too many ACL entries to hold. */ | ||
698 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); | ||
699 | /* Print out of memory warning message. */ | ||
700 | void tomoyo_warn_oom(const char *function); | ||
676 | /* Check whether the given name matches the given name_union. */ | 701 | /* Check whether the given name matches the given name_union. */ |
677 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 702 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
678 | const struct tomoyo_name_union *ptr); | 703 | const struct tomoyo_name_union *ptr); |
@@ -837,8 +862,8 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | |||
837 | /* Set memory quota. */ | 862 | /* Set memory quota. */ |
838 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | 863 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); |
839 | 864 | ||
840 | /* Initialize realpath related code. */ | 865 | /* Initialize mm related code. */ |
841 | void __init tomoyo_realpath_init(void); | 866 | void __init tomoyo_mm_init(void); |
842 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 867 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
843 | const struct tomoyo_path_info *filename); | 868 | const struct tomoyo_path_info *filename); |
844 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 869 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 7e242d27da5a..08428bc082df 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -1,12 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/domain.c | 2 | * security/tomoyo/domain.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Domain transition functions for TOMOYO. |
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #include "common.h" | 9 | #include "common.h" |
@@ -697,24 +694,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
697 | struct tomoyo_path_info rn; /* real name */ | 694 | struct tomoyo_path_info rn; /* real name */ |
698 | struct tomoyo_path_info sn; /* symlink name */ | 695 | struct tomoyo_path_info sn; /* symlink name */ |
699 | struct tomoyo_path_info ln; /* last name */ | 696 | struct tomoyo_path_info ln; /* last name */ |
700 | static bool initialized; | ||
701 | 697 | ||
702 | tomoyo_init_request_info(&r, NULL); | 698 | tomoyo_init_request_info(&r, NULL); |
703 | if (!tmp) | 699 | if (!tmp) |
704 | goto out; | 700 | goto out; |
705 | 701 | ||
706 | if (!initialized) { | ||
707 | /* | ||
708 | * Built-in initializers. This is needed because policies are | ||
709 | * not loaded until starting /sbin/init. | ||
710 | */ | ||
711 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug", | ||
712 | false, false); | ||
713 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe", | ||
714 | false, false); | ||
715 | initialized = true; | ||
716 | } | ||
717 | |||
718 | retry: | 702 | retry: |
719 | /* Get tomoyo_realpath of program. */ | 703 | /* Get tomoyo_realpath of program. */ |
720 | retval = -ENOENT; | 704 | retval = -ENOENT; |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c629cb4e2c66..c13806937dc6 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -1,12 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/file.c | 2 | * security/tomoyo/file.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Pathname restriction functions. |
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #include "common.h" | 9 | #include "common.h" |
@@ -100,61 +97,6 @@ bool tomoyo_compare_number_union(const unsigned long value, | |||
100 | } | 97 | } |
101 | 98 | ||
102 | /** | 99 | /** |
103 | * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. | ||
104 | * | ||
105 | * @r: Pointer to "struct tomoyo_request_info" to initialize. | ||
106 | * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). | ||
107 | * | ||
108 | * Returns mode. | ||
109 | */ | ||
110 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | ||
111 | struct tomoyo_domain_info *domain) | ||
112 | { | ||
113 | memset(r, 0, sizeof(*r)); | ||
114 | if (!domain) | ||
115 | domain = tomoyo_domain(); | ||
116 | r->domain = domain; | ||
117 | r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | ||
118 | return r->mode; | ||
119 | } | ||
120 | |||
121 | static void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
122 | __attribute__ ((format(printf, 2, 3))); | ||
123 | /** | ||
124 | * tomoyo_warn_log - Print warning or error message on console. | ||
125 | * | ||
126 | * @r: Pointer to "struct tomoyo_request_info". | ||
127 | * @fmt: The printf()'s format string, followed by parameters. | ||
128 | */ | ||
129 | static void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
130 | { | ||
131 | int len = PAGE_SIZE; | ||
132 | va_list args; | ||
133 | char *buffer; | ||
134 | if (!tomoyo_verbose_mode(r->domain)) | ||
135 | return; | ||
136 | while (1) { | ||
137 | int len2; | ||
138 | buffer = kmalloc(len, GFP_NOFS); | ||
139 | if (!buffer) | ||
140 | return; | ||
141 | va_start(args, fmt); | ||
142 | len2 = vsnprintf(buffer, len - 1, fmt, args); | ||
143 | va_end(args); | ||
144 | if (len2 <= len - 1) { | ||
145 | buffer[len2] = '\0'; | ||
146 | break; | ||
147 | } | ||
148 | len = len2 + 1; | ||
149 | kfree(buffer); | ||
150 | } | ||
151 | printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n", | ||
152 | r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", | ||
153 | buffer, tomoyo_get_last_name(r->domain)); | ||
154 | kfree(buffer); | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * tomoyo_path2keyword - Get the name of single path operation. | 100 | * tomoyo_path2keyword - Get the name of single path operation. |
159 | * | 101 | * |
160 | * @operation: Type of operation. | 102 | * @operation: Type of operation. |
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c new file mode 100644 index 000000000000..bbada7ca1b91 --- /dev/null +++ b/security/tomoyo/load_policy.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * security/tomoyo/load_policy.c | ||
3 | * | ||
4 | * Policy loader launcher for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | ||
8 | |||
9 | #include "common.h" | ||
10 | |||
11 | /* path to policy loader */ | ||
12 | static const char *tomoyo_loader = "/sbin/tomoyo-init"; | ||
13 | |||
14 | /** | ||
15 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. | ||
16 | * | ||
17 | * Returns true if /sbin/tomoyo-init exists, false otherwise. | ||
18 | */ | ||
19 | static bool tomoyo_policy_loader_exists(void) | ||
20 | { | ||
21 | /* | ||
22 | * Don't activate MAC if the policy loader doesn't exist. | ||
23 | * If the initrd includes /sbin/init but real-root-dev has not | ||
24 | * mounted on / yet, activating MAC will block the system since | ||
25 | * policies are not loaded yet. | ||
26 | * Thus, let do_execve() call this function everytime. | ||
27 | */ | ||
28 | struct path path; | ||
29 | |||
30 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | ||
31 | printk(KERN_INFO "Not activating Mandatory Access Control now " | ||
32 | "since %s doesn't exist.\n", tomoyo_loader); | ||
33 | return false; | ||
34 | } | ||
35 | path_put(&path); | ||
36 | return true; | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * tomoyo_load_policy - Run external policy loader to load policy. | ||
41 | * | ||
42 | * @filename: The program about to start. | ||
43 | * | ||
44 | * This function checks whether @filename is /sbin/init , and if so | ||
45 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init | ||
46 | * and then continues invocation of /sbin/init. | ||
47 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and | ||
48 | * writes to /sys/kernel/security/tomoyo/ interfaces. | ||
49 | * | ||
50 | * Returns nothing. | ||
51 | */ | ||
52 | void tomoyo_load_policy(const char *filename) | ||
53 | { | ||
54 | char *argv[2]; | ||
55 | char *envp[3]; | ||
56 | |||
57 | if (tomoyo_policy_loaded) | ||
58 | return; | ||
59 | /* | ||
60 | * Check filename is /sbin/init or /sbin/tomoyo-start. | ||
61 | * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't | ||
62 | * be passed. | ||
63 | * You can create /sbin/tomoyo-start by | ||
64 | * "ln -s /bin/true /sbin/tomoyo-start". | ||
65 | */ | ||
66 | if (strcmp(filename, "/sbin/init") && | ||
67 | strcmp(filename, "/sbin/tomoyo-start")) | ||
68 | return; | ||
69 | if (!tomoyo_policy_loader_exists()) | ||
70 | return; | ||
71 | |||
72 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | ||
73 | tomoyo_loader); | ||
74 | argv[0] = (char *) tomoyo_loader; | ||
75 | argv[1] = NULL; | ||
76 | envp[0] = "HOME=/"; | ||
77 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | ||
78 | envp[2] = NULL; | ||
79 | call_usermodehelper(argv[0], argv, envp, 1); | ||
80 | tomoyo_check_profile(); | ||
81 | } | ||
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c new file mode 100644 index 000000000000..8fb73ff5cb63 --- /dev/null +++ b/security/tomoyo/memory.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * security/tomoyo/memory.c | ||
3 | * | ||
4 | * Memory management functions for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | ||
8 | |||
9 | #include <linux/hash.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include "common.h" | ||
12 | |||
13 | /** | ||
14 | * tomoyo_warn_oom - Print out of memory warning message. | ||
15 | * | ||
16 | * @function: Function's name. | ||
17 | */ | ||
18 | void tomoyo_warn_oom(const char *function) | ||
19 | { | ||
20 | /* Reduce error messages. */ | ||
21 | static pid_t tomoyo_last_pid; | ||
22 | const pid_t pid = current->pid; | ||
23 | if (tomoyo_last_pid != pid) { | ||
24 | printk(KERN_WARNING "ERROR: Out of memory at %s.\n", | ||
25 | function); | ||
26 | tomoyo_last_pid = pid; | ||
27 | } | ||
28 | if (!tomoyo_policy_loaded) | ||
29 | panic("MAC Initialization failed.\n"); | ||
30 | } | ||
31 | |||
32 | /* Memory allocated for policy. */ | ||
33 | static atomic_t tomoyo_policy_memory_size; | ||
34 | /* Quota for holding policy. */ | ||
35 | static unsigned int tomoyo_quota_for_policy; | ||
36 | |||
37 | /** | ||
38 | * tomoyo_memory_ok - Check memory quota. | ||
39 | * | ||
40 | * @ptr: Pointer to allocated memory. | ||
41 | * | ||
42 | * Returns true on success, false otherwise. | ||
43 | * | ||
44 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. | ||
45 | */ | ||
46 | bool tomoyo_memory_ok(void *ptr) | ||
47 | { | ||
48 | size_t s = ptr ? ksize(ptr) : 0; | ||
49 | atomic_add(s, &tomoyo_policy_memory_size); | ||
50 | if (ptr && (!tomoyo_quota_for_policy || | ||
51 | atomic_read(&tomoyo_policy_memory_size) | ||
52 | <= tomoyo_quota_for_policy)) { | ||
53 | memset(ptr, 0, s); | ||
54 | return true; | ||
55 | } | ||
56 | atomic_sub(s, &tomoyo_policy_memory_size); | ||
57 | tomoyo_warn_oom(__func__); | ||
58 | return false; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * tomoyo_commit_ok - Check memory quota. | ||
63 | * | ||
64 | * @data: Data to copy from. | ||
65 | * @size: Size in byte. | ||
66 | * | ||
67 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
68 | * @data is zero-cleared on success. | ||
69 | */ | ||
70 | void *tomoyo_commit_ok(void *data, const unsigned int size) | ||
71 | { | ||
72 | void *ptr = kzalloc(size, GFP_NOFS); | ||
73 | if (tomoyo_memory_ok(ptr)) { | ||
74 | memmove(ptr, data, size); | ||
75 | memset(data, 0, size); | ||
76 | return ptr; | ||
77 | } | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * tomoyo_memory_free - Free memory for elements. | ||
83 | * | ||
84 | * @ptr: Pointer to allocated memory. | ||
85 | */ | ||
86 | void tomoyo_memory_free(void *ptr) | ||
87 | { | ||
88 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); | ||
89 | kfree(ptr); | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * tomoyo_name_list is used for holding string data used by TOMOYO. | ||
94 | * Since same string data is likely used for multiple times (e.g. | ||
95 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | ||
96 | * "const struct tomoyo_path_info *". | ||
97 | */ | ||
98 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
99 | |||
100 | /** | ||
101 | * tomoyo_get_name - Allocate permanent memory for string data. | ||
102 | * | ||
103 | * @name: The string to store into the permernent memory. | ||
104 | * | ||
105 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | ||
106 | */ | ||
107 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | ||
108 | { | ||
109 | struct tomoyo_name_entry *ptr; | ||
110 | unsigned int hash; | ||
111 | int len; | ||
112 | int allocated_len; | ||
113 | struct list_head *head; | ||
114 | |||
115 | if (!name) | ||
116 | return NULL; | ||
117 | len = strlen(name) + 1; | ||
118 | hash = full_name_hash((const unsigned char *) name, len - 1); | ||
119 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | ||
120 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
121 | return NULL; | ||
122 | list_for_each_entry(ptr, head, list) { | ||
123 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | ||
124 | continue; | ||
125 | atomic_inc(&ptr->users); | ||
126 | goto out; | ||
127 | } | ||
128 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); | ||
129 | allocated_len = ptr ? ksize(ptr) : 0; | ||
130 | if (!ptr || (tomoyo_quota_for_policy && | ||
131 | atomic_read(&tomoyo_policy_memory_size) + allocated_len | ||
132 | > tomoyo_quota_for_policy)) { | ||
133 | kfree(ptr); | ||
134 | ptr = NULL; | ||
135 | tomoyo_warn_oom(__func__); | ||
136 | goto out; | ||
137 | } | ||
138 | atomic_add(allocated_len, &tomoyo_policy_memory_size); | ||
139 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | ||
140 | memmove((char *) ptr->entry.name, name, len); | ||
141 | atomic_set(&ptr->users, 1); | ||
142 | tomoyo_fill_path_info(&ptr->entry); | ||
143 | list_add_tail(&ptr->list, head); | ||
144 | out: | ||
145 | mutex_unlock(&tomoyo_policy_lock); | ||
146 | return ptr ? &ptr->entry : NULL; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * tomoyo_mm_init - Initialize mm related code. | ||
151 | */ | ||
152 | void __init tomoyo_mm_init(void) | ||
153 | { | ||
154 | int idx; | ||
155 | |||
156 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | ||
157 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | ||
158 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | ||
159 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | ||
160 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); | ||
161 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | ||
162 | idx = tomoyo_read_lock(); | ||
163 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | ||
164 | panic("Can't register tomoyo_kernel_domain"); | ||
165 | { | ||
166 | /* Load built-in policy. */ | ||
167 | tomoyo_write_domain_initializer_policy("/sbin/hotplug", | ||
168 | false, false); | ||
169 | tomoyo_write_domain_initializer_policy("/sbin/modprobe", | ||
170 | false, false); | ||
171 | } | ||
172 | tomoyo_read_unlock(idx); | ||
173 | } | ||
174 | |||
175 | |||
176 | /* Memory allocated for query lists. */ | ||
177 | unsigned int tomoyo_query_memory_size; | ||
178 | /* Quota for holding query lists. */ | ||
179 | unsigned int tomoyo_quota_for_query; | ||
180 | |||
181 | /** | ||
182 | * tomoyo_read_memory_counter - Check for memory usage in bytes. | ||
183 | * | ||
184 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
185 | * | ||
186 | * Returns memory usage. | ||
187 | */ | ||
188 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | ||
189 | { | ||
190 | if (!head->read_eof) { | ||
191 | const unsigned int policy | ||
192 | = atomic_read(&tomoyo_policy_memory_size); | ||
193 | const unsigned int query = tomoyo_query_memory_size; | ||
194 | char buffer[64]; | ||
195 | |||
196 | memset(buffer, 0, sizeof(buffer)); | ||
197 | if (tomoyo_quota_for_policy) | ||
198 | snprintf(buffer, sizeof(buffer) - 1, | ||
199 | " (Quota: %10u)", | ||
200 | tomoyo_quota_for_policy); | ||
201 | else | ||
202 | buffer[0] = '\0'; | ||
203 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, | ||
204 | buffer); | ||
205 | if (tomoyo_quota_for_query) | ||
206 | snprintf(buffer, sizeof(buffer) - 1, | ||
207 | " (Quota: %10u)", | ||
208 | tomoyo_quota_for_query); | ||
209 | else | ||
210 | buffer[0] = '\0'; | ||
211 | tomoyo_io_printf(head, "Query lists: %10u%s\n", query, | ||
212 | buffer); | ||
213 | tomoyo_io_printf(head, "Total: %10u\n", policy + query); | ||
214 | head->read_eof = true; | ||
215 | } | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * tomoyo_write_memory_quota - Set memory quota. | ||
221 | * | ||
222 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
223 | * | ||
224 | * Returns 0. | ||
225 | */ | ||
226 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | ||
227 | { | ||
228 | char *data = head->write_buf; | ||
229 | unsigned int size; | ||
230 | |||
231 | if (sscanf(data, "Policy: %u", &size) == 1) | ||
232 | tomoyo_quota_for_policy = size; | ||
233 | else if (sscanf(data, "Query lists: %u", &size) == 1) | ||
234 | tomoyo_quota_for_query = size; | ||
235 | return 0; | ||
236 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 3ceb1724c92d..1fd685a94ad1 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -1,19 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/realpath.c | 2 | * security/tomoyo/realpath.c |
3 | * | 3 | * |
4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. | 4 | * Pathname calculation functions for TOMOYO. |
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #include <linux/types.h> | 9 | #include <linux/types.h> |
13 | #include <linux/mount.h> | 10 | #include <linux/mount.h> |
14 | #include <linux/mnt_namespace.h> | 11 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> | ||
17 | #include <linux/magic.h> | 13 | #include <linux/magic.h> |
18 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
19 | #include "common.h" | 15 | #include "common.h" |
@@ -123,7 +119,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
123 | } | 119 | } |
124 | } | 120 | } |
125 | if (error) | 121 | if (error) |
126 | printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); | 122 | tomoyo_warn_oom(__func__); |
127 | return error; | 123 | return error; |
128 | } | 124 | } |
129 | 125 | ||
@@ -141,6 +137,7 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
141 | { | 137 | { |
142 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); | 138 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); |
143 | 139 | ||
140 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | ||
144 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 141 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
145 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 142 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
146 | if (!buf) | 143 | if (!buf) |
@@ -189,206 +186,3 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
189 | } | 186 | } |
190 | return NULL; | 187 | return NULL; |
191 | } | 188 | } |
192 | |||
193 | /* Memory allocated for non-string data. */ | ||
194 | static atomic_t tomoyo_policy_memory_size; | ||
195 | /* Quota for holding policy. */ | ||
196 | static unsigned int tomoyo_quota_for_policy; | ||
197 | |||
198 | /** | ||
199 | * tomoyo_memory_ok - Check memory quota. | ||
200 | * | ||
201 | * @ptr: Pointer to allocated memory. | ||
202 | * | ||
203 | * Returns true on success, false otherwise. | ||
204 | * | ||
205 | * Caller holds tomoyo_policy_lock. | ||
206 | * Memory pointed by @ptr will be zeroed on success. | ||
207 | */ | ||
208 | bool tomoyo_memory_ok(void *ptr) | ||
209 | { | ||
210 | int allocated_len = ptr ? ksize(ptr) : 0; | ||
211 | atomic_add(allocated_len, &tomoyo_policy_memory_size); | ||
212 | if (ptr && (!tomoyo_quota_for_policy || | ||
213 | atomic_read(&tomoyo_policy_memory_size) | ||
214 | <= tomoyo_quota_for_policy)) { | ||
215 | memset(ptr, 0, allocated_len); | ||
216 | return true; | ||
217 | } | ||
218 | printk(KERN_WARNING "ERROR: Out of memory " | ||
219 | "for tomoyo_alloc_element().\n"); | ||
220 | if (!tomoyo_policy_loaded) | ||
221 | panic("MAC Initialization failed.\n"); | ||
222 | return false; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * tomoyo_commit_ok - Check memory quota. | ||
227 | * | ||
228 | * @data: Data to copy from. | ||
229 | * @size: Size in byte. | ||
230 | * | ||
231 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
232 | */ | ||
233 | void *tomoyo_commit_ok(void *data, const unsigned int size) | ||
234 | { | ||
235 | void *ptr = kzalloc(size, GFP_NOFS); | ||
236 | if (tomoyo_memory_ok(ptr)) { | ||
237 | memmove(ptr, data, size); | ||
238 | memset(data, 0, size); | ||
239 | return ptr; | ||
240 | } | ||
241 | return NULL; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * tomoyo_memory_free - Free memory for elements. | ||
246 | * | ||
247 | * @ptr: Pointer to allocated memory. | ||
248 | */ | ||
249 | void tomoyo_memory_free(void *ptr) | ||
250 | { | ||
251 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); | ||
252 | kfree(ptr); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * tomoyo_name_list is used for holding string data used by TOMOYO. | ||
257 | * Since same string data is likely used for multiple times (e.g. | ||
258 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | ||
259 | * "const struct tomoyo_path_info *". | ||
260 | */ | ||
261 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
262 | |||
263 | /** | ||
264 | * tomoyo_get_name - Allocate permanent memory for string data. | ||
265 | * | ||
266 | * @name: The string to store into the permernent memory. | ||
267 | * | ||
268 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | ||
269 | */ | ||
270 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | ||
271 | { | ||
272 | struct tomoyo_name_entry *ptr; | ||
273 | unsigned int hash; | ||
274 | int len; | ||
275 | int allocated_len; | ||
276 | struct list_head *head; | ||
277 | |||
278 | if (!name) | ||
279 | return NULL; | ||
280 | len = strlen(name) + 1; | ||
281 | hash = full_name_hash((const unsigned char *) name, len - 1); | ||
282 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | ||
283 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
284 | return NULL; | ||
285 | list_for_each_entry(ptr, head, list) { | ||
286 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | ||
287 | continue; | ||
288 | atomic_inc(&ptr->users); | ||
289 | goto out; | ||
290 | } | ||
291 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); | ||
292 | allocated_len = ptr ? ksize(ptr) : 0; | ||
293 | if (!ptr || (tomoyo_quota_for_policy && | ||
294 | atomic_read(&tomoyo_policy_memory_size) + allocated_len | ||
295 | > tomoyo_quota_for_policy)) { | ||
296 | kfree(ptr); | ||
297 | printk(KERN_WARNING "ERROR: Out of memory " | ||
298 | "for tomoyo_get_name().\n"); | ||
299 | if (!tomoyo_policy_loaded) | ||
300 | panic("MAC Initialization failed.\n"); | ||
301 | ptr = NULL; | ||
302 | goto out; | ||
303 | } | ||
304 | atomic_add(allocated_len, &tomoyo_policy_memory_size); | ||
305 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | ||
306 | memmove((char *) ptr->entry.name, name, len); | ||
307 | atomic_set(&ptr->users, 1); | ||
308 | tomoyo_fill_path_info(&ptr->entry); | ||
309 | list_add_tail(&ptr->list, head); | ||
310 | out: | ||
311 | mutex_unlock(&tomoyo_policy_lock); | ||
312 | return ptr ? &ptr->entry : NULL; | ||
313 | } | ||
314 | |||
315 | /** | ||
316 | * tomoyo_realpath_init - Initialize realpath related code. | ||
317 | */ | ||
318 | void __init tomoyo_realpath_init(void) | ||
319 | { | ||
320 | int i; | ||
321 | |||
322 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | ||
323 | for (i = 0; i < TOMOYO_MAX_HASH; i++) | ||
324 | INIT_LIST_HEAD(&tomoyo_name_list[i]); | ||
325 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | ||
326 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); | ||
327 | /* | ||
328 | * tomoyo_read_lock() is not needed because this function is | ||
329 | * called before the first "delete" request. | ||
330 | */ | ||
331 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | ||
332 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | ||
333 | panic("Can't register tomoyo_kernel_domain"); | ||
334 | } | ||
335 | |||
336 | unsigned int tomoyo_quota_for_query; | ||
337 | unsigned int tomoyo_query_memory_size; | ||
338 | |||
339 | /** | ||
340 | * tomoyo_read_memory_counter - Check for memory usage in bytes. | ||
341 | * | ||
342 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
343 | * | ||
344 | * Returns memory usage. | ||
345 | */ | ||
346 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | ||
347 | { | ||
348 | if (!head->read_eof) { | ||
349 | const unsigned int policy | ||
350 | = atomic_read(&tomoyo_policy_memory_size); | ||
351 | const unsigned int query = tomoyo_query_memory_size; | ||
352 | char buffer[64]; | ||
353 | |||
354 | memset(buffer, 0, sizeof(buffer)); | ||
355 | if (tomoyo_quota_for_policy) | ||
356 | snprintf(buffer, sizeof(buffer) - 1, | ||
357 | " (Quota: %10u)", | ||
358 | tomoyo_quota_for_policy); | ||
359 | else | ||
360 | buffer[0] = '\0'; | ||
361 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, | ||
362 | buffer); | ||
363 | if (tomoyo_quota_for_query) | ||
364 | snprintf(buffer, sizeof(buffer) - 1, | ||
365 | " (Quota: %10u)", | ||
366 | tomoyo_quota_for_query); | ||
367 | else | ||
368 | buffer[0] = '\0'; | ||
369 | tomoyo_io_printf(head, "Query lists: %10u%s\n", query, | ||
370 | buffer); | ||
371 | tomoyo_io_printf(head, "Total: %10u\n", policy + query); | ||
372 | head->read_eof = true; | ||
373 | } | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * tomoyo_write_memory_quota - Set memory quota. | ||
379 | * | ||
380 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
381 | * | ||
382 | * Returns 0. | ||
383 | */ | ||
384 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | ||
385 | { | ||
386 | char *data = head->write_buf; | ||
387 | unsigned int size; | ||
388 | |||
389 | if (sscanf(data, "Policy: %u", &size) == 1) | ||
390 | tomoyo_quota_for_policy = size; | ||
391 | else if (sscanf(data, "Query lists: %u", &size) == 1) | ||
392 | tomoyo_quota_for_query = size; | ||
393 | return 0; | ||
394 | } | ||
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c new file mode 100644 index 000000000000..5eb53510c4a7 --- /dev/null +++ b/security/tomoyo/securityfs_if.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * security/tomoyo/common.c | ||
3 | * | ||
4 | * Securityfs interface for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | ||
8 | |||
9 | #include <linux/security.h> | ||
10 | #include "common.h" | ||
11 | |||
12 | /** | ||
13 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | ||
14 | * | ||
15 | * @inode: Pointer to "struct inode". | ||
16 | * @file: Pointer to "struct file". | ||
17 | * | ||
18 | * Returns 0 on success, negative value otherwise. | ||
19 | */ | ||
20 | static int tomoyo_open(struct inode *inode, struct file *file) | ||
21 | { | ||
22 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) | ||
23 | - ((u8 *) NULL); | ||
24 | return tomoyo_open_control(key, file); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. | ||
29 | * | ||
30 | * @inode: Pointer to "struct inode". | ||
31 | * @file: Pointer to "struct file". | ||
32 | * | ||
33 | * Returns 0 on success, negative value otherwise. | ||
34 | */ | ||
35 | static int tomoyo_release(struct inode *inode, struct file *file) | ||
36 | { | ||
37 | return tomoyo_close_control(file); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. | ||
42 | * | ||
43 | * @file: Pointer to "struct file". | ||
44 | * @buf: Pointer to buffer. | ||
45 | * @count: Size of @buf. | ||
46 | * @ppos: Unused. | ||
47 | * | ||
48 | * Returns bytes read on success, negative value otherwise. | ||
49 | */ | ||
50 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | ||
51 | loff_t *ppos) | ||
52 | { | ||
53 | return tomoyo_read_control(file, buf, count); | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. | ||
58 | * | ||
59 | * @file: Pointer to "struct file". | ||
60 | * @buf: Pointer to buffer. | ||
61 | * @count: Size of @buf. | ||
62 | * @ppos: Unused. | ||
63 | * | ||
64 | * Returns @count on success, negative value otherwise. | ||
65 | */ | ||
66 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, | ||
67 | size_t count, loff_t *ppos) | ||
68 | { | ||
69 | return tomoyo_write_control(file, buf, count); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
74 | * /sys/kernel/security/tomoyo/ interface. | ||
75 | * | ||
76 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
77 | * See tomoyo_io_buffer for internals. | ||
78 | */ | ||
79 | static const struct file_operations tomoyo_operations = { | ||
80 | .open = tomoyo_open, | ||
81 | .release = tomoyo_release, | ||
82 | .read = tomoyo_read, | ||
83 | .write = tomoyo_write, | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. | ||
88 | * | ||
89 | * @name: The name of the interface file. | ||
90 | * @mode: The permission of the interface file. | ||
91 | * @parent: The parent directory. | ||
92 | * @key: Type of interface. | ||
93 | * | ||
94 | * Returns nothing. | ||
95 | */ | ||
96 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, | ||
97 | struct dentry *parent, const u8 key) | ||
98 | { | ||
99 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, | ||
100 | &tomoyo_operations); | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. | ||
105 | * | ||
106 | * Returns 0. | ||
107 | */ | ||
108 | static int __init tomoyo_initerface_init(void) | ||
109 | { | ||
110 | struct dentry *tomoyo_dir; | ||
111 | |||
112 | /* Don't create securityfs entries unless registered. */ | ||
113 | if (current_cred()->security != &tomoyo_kernel_domain) | ||
114 | return 0; | ||
115 | |||
116 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | ||
117 | tomoyo_create_entry("query", 0600, tomoyo_dir, | ||
118 | TOMOYO_QUERY); | ||
119 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, | ||
120 | TOMOYO_DOMAINPOLICY); | ||
121 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | ||
122 | TOMOYO_EXCEPTIONPOLICY); | ||
123 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | ||
124 | TOMOYO_SELFDOMAIN); | ||
125 | tomoyo_create_entry(".domain_status", 0600, tomoyo_dir, | ||
126 | TOMOYO_DOMAIN_STATUS); | ||
127 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | ||
128 | TOMOYO_PROCESS_STATUS); | ||
129 | tomoyo_create_entry("meminfo", 0600, tomoyo_dir, | ||
130 | TOMOYO_MEMINFO); | ||
131 | tomoyo_create_entry("profile", 0600, tomoyo_dir, | ||
132 | TOMOYO_PROFILE); | ||
133 | tomoyo_create_entry("manager", 0600, tomoyo_dir, | ||
134 | TOMOYO_MANAGER); | ||
135 | tomoyo_create_entry("version", 0400, tomoyo_dir, | ||
136 | TOMOYO_VERSION); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | fs_initcall(tomoyo_initerface_init); | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 5d64d409b112..57d442e7339b 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -3,10 +3,7 @@ | |||
3 | * | 3 | * |
4 | * LSM hooks for TOMOYO Linux. | 4 | * LSM hooks for TOMOYO Linux. |
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/security.h> | 9 | #include <linux/security.h> |
@@ -286,7 +283,7 @@ static int __init tomoyo_init(void) | |||
286 | panic("Failure registering TOMOYO Linux"); | 283 | panic("Failure registering TOMOYO Linux"); |
287 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 284 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
288 | cred->security = &tomoyo_kernel_domain; | 285 | cred->security = &tomoyo_kernel_domain; |
289 | tomoyo_realpath_init(); | 286 | tomoyo_mm_init(); |
290 | return 0; | 287 | return 0; |
291 | } | 288 | } |
292 | 289 | ||
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c new file mode 100644 index 000000000000..7b023f5e1314 --- /dev/null +++ b/security/tomoyo/util.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * security/tomoyo/util.c | ||
3 | * | ||
4 | * Utility functions for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | ||
8 | |||
9 | #include <linux/slab.h> | ||
10 | #include "common.h" | ||
11 | |||
12 | /* Lock for protecting policy. */ | ||
13 | DEFINE_MUTEX(tomoyo_policy_lock); | ||
14 | |||
15 | /* Has /sbin/init started? */ | ||
16 | bool tomoyo_policy_loaded; | ||
17 | |||
18 | /** | ||
19 | * tomoyo_parse_ulong - Parse an "unsigned long" value. | ||
20 | * | ||
21 | * @result: Pointer to "unsigned long". | ||
22 | * @str: Pointer to string to parse. | ||
23 | * | ||
24 | * Returns value type on success, 0 otherwise. | ||
25 | * | ||
26 | * The @src is updated to point the first character after the value | ||
27 | * on success. | ||
28 | */ | ||
29 | u8 tomoyo_parse_ulong(unsigned long *result, char **str) | ||
30 | { | ||
31 | const char *cp = *str; | ||
32 | char *ep; | ||
33 | int base = 10; | ||
34 | if (*cp == '0') { | ||
35 | char c = *(cp + 1); | ||
36 | if (c == 'x' || c == 'X') { | ||
37 | base = 16; | ||
38 | cp += 2; | ||
39 | } else if (c >= '0' && c <= '7') { | ||
40 | base = 8; | ||
41 | cp++; | ||
42 | } | ||
43 | } | ||
44 | *result = simple_strtoul(cp, &ep, base); | ||
45 | if (cp == ep) | ||
46 | return 0; | ||
47 | *str = ep; | ||
48 | switch (base) { | ||
49 | case 16: | ||
50 | return TOMOYO_VALUE_TYPE_HEXADECIMAL; | ||
51 | case 8: | ||
52 | return TOMOYO_VALUE_TYPE_OCTAL; | ||
53 | default: | ||
54 | return TOMOYO_VALUE_TYPE_DECIMAL; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * tomoyo_print_ulong - Print an "unsigned long" value. | ||
60 | * | ||
61 | * @buffer: Pointer to buffer. | ||
62 | * @buffer_len: Size of @buffer. | ||
63 | * @value: An "unsigned long" value. | ||
64 | * @type: Type of @value. | ||
65 | * | ||
66 | * Returns nothing. | ||
67 | */ | ||
68 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | ||
69 | const unsigned long value, const u8 type) | ||
70 | { | ||
71 | if (type == TOMOYO_VALUE_TYPE_DECIMAL) | ||
72 | snprintf(buffer, buffer_len, "%lu", value); | ||
73 | else if (type == TOMOYO_VALUE_TYPE_OCTAL) | ||
74 | snprintf(buffer, buffer_len, "0%lo", value); | ||
75 | else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) | ||
76 | snprintf(buffer, buffer_len, "0x%lX", value); | ||
77 | else | ||
78 | snprintf(buffer, buffer_len, "type(%u)", type); | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | ||
83 | * | ||
84 | * @filename: Name or name group. | ||
85 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
86 | * | ||
87 | * Returns true on success, false otherwise. | ||
88 | */ | ||
89 | bool tomoyo_parse_name_union(const char *filename, | ||
90 | struct tomoyo_name_union *ptr) | ||
91 | { | ||
92 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) | ||
93 | return false; | ||
94 | if (filename[0] == '@') { | ||
95 | ptr->group = tomoyo_get_path_group(filename + 1); | ||
96 | ptr->is_group = true; | ||
97 | return ptr->group != NULL; | ||
98 | } | ||
99 | ptr->filename = tomoyo_get_name(filename); | ||
100 | ptr->is_group = false; | ||
101 | return ptr->filename != NULL; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. | ||
106 | * | ||
107 | * @data: Number or number range or number group. | ||
108 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
109 | * | ||
110 | * Returns true on success, false otherwise. | ||
111 | */ | ||
112 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) | ||
113 | { | ||
114 | u8 type; | ||
115 | unsigned long v; | ||
116 | memset(num, 0, sizeof(*num)); | ||
117 | if (data[0] == '@') { | ||
118 | if (!tomoyo_is_correct_path(data, 0, 0, 0)) | ||
119 | return false; | ||
120 | num->group = tomoyo_get_number_group(data + 1); | ||
121 | num->is_group = true; | ||
122 | return num->group != NULL; | ||
123 | } | ||
124 | type = tomoyo_parse_ulong(&v, &data); | ||
125 | if (!type) | ||
126 | return false; | ||
127 | num->values[0] = v; | ||
128 | num->min_type = type; | ||
129 | if (!*data) { | ||
130 | num->values[1] = v; | ||
131 | num->max_type = type; | ||
132 | return true; | ||
133 | } | ||
134 | if (*data++ != '-') | ||
135 | return false; | ||
136 | type = tomoyo_parse_ulong(&v, &data); | ||
137 | if (!type || *data) | ||
138 | return false; | ||
139 | num->values[1] = v; | ||
140 | num->max_type = type; | ||
141 | return true; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * tomoyo_is_byte_range - Check whether the string is a \ooo style octal value. | ||
146 | * | ||
147 | * @str: Pointer to the string. | ||
148 | * | ||
149 | * Returns true if @str is a \ooo style octal value, false otherwise. | ||
150 | * | ||
151 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. | ||
152 | * This function verifies that \ooo is in valid range. | ||
153 | */ | ||
154 | static inline bool tomoyo_is_byte_range(const char *str) | ||
155 | { | ||
156 | return *str >= '0' && *str++ <= '3' && | ||
157 | *str >= '0' && *str++ <= '7' && | ||
158 | *str >= '0' && *str <= '7'; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * tomoyo_is_alphabet_char - Check whether the character is an alphabet. | ||
163 | * | ||
164 | * @c: The character to check. | ||
165 | * | ||
166 | * Returns true if @c is an alphabet character, false otherwise. | ||
167 | */ | ||
168 | static inline bool tomoyo_is_alphabet_char(const char c) | ||
169 | { | ||
170 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * tomoyo_make_byte - Make byte value from three octal characters. | ||
175 | * | ||
176 | * @c1: The first character. | ||
177 | * @c2: The second character. | ||
178 | * @c3: The third character. | ||
179 | * | ||
180 | * Returns byte value. | ||
181 | */ | ||
182 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) | ||
183 | { | ||
184 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. | ||
189 | * | ||
190 | * @src: Pointer to pointer to the string. | ||
191 | * @find: Pointer to the keyword. | ||
192 | * | ||
193 | * Returns true if @src starts with @find, false otherwise. | ||
194 | * | ||
195 | * The @src is updated to point the first character after the @find | ||
196 | * if @src starts with @find. | ||
197 | */ | ||
198 | bool tomoyo_str_starts(char **src, const char *find) | ||
199 | { | ||
200 | const int len = strlen(find); | ||
201 | char *tmp = *src; | ||
202 | |||
203 | if (strncmp(tmp, find, len)) | ||
204 | return false; | ||
205 | tmp += len; | ||
206 | *src = tmp; | ||
207 | return true; | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * tomoyo_normalize_line - Format string. | ||
212 | * | ||
213 | * @buffer: The line to normalize. | ||
214 | * | ||
215 | * Leading and trailing whitespaces are removed. | ||
216 | * Multiple whitespaces are packed into single space. | ||
217 | * | ||
218 | * Returns nothing. | ||
219 | */ | ||
220 | void tomoyo_normalize_line(unsigned char *buffer) | ||
221 | { | ||
222 | unsigned char *sp = buffer; | ||
223 | unsigned char *dp = buffer; | ||
224 | bool first = true; | ||
225 | |||
226 | while (tomoyo_is_invalid(*sp)) | ||
227 | sp++; | ||
228 | while (*sp) { | ||
229 | if (!first) | ||
230 | *dp++ = ' '; | ||
231 | first = false; | ||
232 | while (tomoyo_is_valid(*sp)) | ||
233 | *dp++ = *sp++; | ||
234 | while (tomoyo_is_invalid(*sp)) | ||
235 | sp++; | ||
236 | } | ||
237 | *dp = '\0'; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * tomoyo_tokenize - Tokenize string. | ||
242 | * | ||
243 | * @buffer: The line to tokenize. | ||
244 | * @w: Pointer to "char *". | ||
245 | * @size: Sizeof @w . | ||
246 | * | ||
247 | * Returns true on success, false otherwise. | ||
248 | */ | ||
249 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size) | ||
250 | { | ||
251 | int count = size / sizeof(char *); | ||
252 | int i; | ||
253 | for (i = 0; i < count; i++) | ||
254 | w[i] = ""; | ||
255 | for (i = 0; i < count; i++) { | ||
256 | char *cp = strchr(buffer, ' '); | ||
257 | if (cp) | ||
258 | *cp = '\0'; | ||
259 | w[i] = buffer; | ||
260 | if (!cp) | ||
261 | break; | ||
262 | buffer = cp + 1; | ||
263 | } | ||
264 | return i < count || !*buffer; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * tomoyo_is_correct_path - Validate a pathname. | ||
269 | * | ||
270 | * @filename: The pathname to check. | ||
271 | * @start_type: Should the pathname start with '/'? | ||
272 | * 1 = must / -1 = must not / 0 = don't care | ||
273 | * @pattern_type: Can the pathname contain a wildcard? | ||
274 | * 1 = must / -1 = must not / 0 = don't care | ||
275 | * @end_type: Should the pathname end with '/'? | ||
276 | * 1 = must / -1 = must not / 0 = don't care | ||
277 | * | ||
278 | * Check whether the given filename follows the naming rules. | ||
279 | * Returns true if @filename follows the naming rules, false otherwise. | ||
280 | */ | ||
281 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | ||
282 | const s8 pattern_type, const s8 end_type) | ||
283 | { | ||
284 | const char *const start = filename; | ||
285 | bool in_repetition = false; | ||
286 | bool contains_pattern = false; | ||
287 | unsigned char c; | ||
288 | unsigned char d; | ||
289 | unsigned char e; | ||
290 | |||
291 | if (!filename) | ||
292 | goto out; | ||
293 | c = *filename; | ||
294 | if (start_type == 1) { /* Must start with '/' */ | ||
295 | if (c != '/') | ||
296 | goto out; | ||
297 | } else if (start_type == -1) { /* Must not start with '/' */ | ||
298 | if (c == '/') | ||
299 | goto out; | ||
300 | } | ||
301 | if (c) | ||
302 | c = *(filename + strlen(filename) - 1); | ||
303 | if (end_type == 1) { /* Must end with '/' */ | ||
304 | if (c != '/') | ||
305 | goto out; | ||
306 | } else if (end_type == -1) { /* Must not end with '/' */ | ||
307 | if (c == '/') | ||
308 | goto out; | ||
309 | } | ||
310 | while (1) { | ||
311 | c = *filename++; | ||
312 | if (!c) | ||
313 | break; | ||
314 | if (c == '\\') { | ||
315 | c = *filename++; | ||
316 | switch (c) { | ||
317 | case '\\': /* "\\" */ | ||
318 | continue; | ||
319 | case '$': /* "\$" */ | ||
320 | case '+': /* "\+" */ | ||
321 | case '?': /* "\?" */ | ||
322 | case '*': /* "\*" */ | ||
323 | case '@': /* "\@" */ | ||
324 | case 'x': /* "\x" */ | ||
325 | case 'X': /* "\X" */ | ||
326 | case 'a': /* "\a" */ | ||
327 | case 'A': /* "\A" */ | ||
328 | case '-': /* "\-" */ | ||
329 | if (pattern_type == -1) | ||
330 | break; /* Must not contain pattern */ | ||
331 | contains_pattern = true; | ||
332 | continue; | ||
333 | case '{': /* "/\{" */ | ||
334 | if (filename - 3 < start || | ||
335 | *(filename - 3) != '/') | ||
336 | break; | ||
337 | if (pattern_type == -1) | ||
338 | break; /* Must not contain pattern */ | ||
339 | contains_pattern = true; | ||
340 | in_repetition = true; | ||
341 | continue; | ||
342 | case '}': /* "\}/" */ | ||
343 | if (*filename != '/') | ||
344 | break; | ||
345 | if (!in_repetition) | ||
346 | break; | ||
347 | in_repetition = false; | ||
348 | continue; | ||
349 | case '0': /* "\ooo" */ | ||
350 | case '1': | ||
351 | case '2': | ||
352 | case '3': | ||
353 | d = *filename++; | ||
354 | if (d < '0' || d > '7') | ||
355 | break; | ||
356 | e = *filename++; | ||
357 | if (e < '0' || e > '7') | ||
358 | break; | ||
359 | c = tomoyo_make_byte(c, d, e); | ||
360 | if (tomoyo_is_invalid(c)) | ||
361 | continue; /* pattern is not \000 */ | ||
362 | } | ||
363 | goto out; | ||
364 | } else if (in_repetition && c == '/') { | ||
365 | goto out; | ||
366 | } else if (tomoyo_is_invalid(c)) { | ||
367 | goto out; | ||
368 | } | ||
369 | } | ||
370 | if (pattern_type == 1) { /* Must contain pattern */ | ||
371 | if (!contains_pattern) | ||
372 | goto out; | ||
373 | } | ||
374 | if (in_repetition) | ||
375 | goto out; | ||
376 | return true; | ||
377 | out: | ||
378 | return false; | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. | ||
383 | * | ||
384 | * @domainname: The domainname to check. | ||
385 | * | ||
386 | * Returns true if @domainname follows the naming rules, false otherwise. | ||
387 | */ | ||
388 | bool tomoyo_is_correct_domain(const unsigned char *domainname) | ||
389 | { | ||
390 | unsigned char c; | ||
391 | unsigned char d; | ||
392 | unsigned char e; | ||
393 | |||
394 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | ||
395 | TOMOYO_ROOT_NAME_LEN)) | ||
396 | goto out; | ||
397 | domainname += TOMOYO_ROOT_NAME_LEN; | ||
398 | if (!*domainname) | ||
399 | return true; | ||
400 | do { | ||
401 | if (*domainname++ != ' ') | ||
402 | goto out; | ||
403 | if (*domainname++ != '/') | ||
404 | goto out; | ||
405 | while ((c = *domainname) != '\0' && c != ' ') { | ||
406 | domainname++; | ||
407 | if (c == '\\') { | ||
408 | c = *domainname++; | ||
409 | switch ((c)) { | ||
410 | case '\\': /* "\\" */ | ||
411 | continue; | ||
412 | case '0': /* "\ooo" */ | ||
413 | case '1': | ||
414 | case '2': | ||
415 | case '3': | ||
416 | d = *domainname++; | ||
417 | if (d < '0' || d > '7') | ||
418 | break; | ||
419 | e = *domainname++; | ||
420 | if (e < '0' || e > '7') | ||
421 | break; | ||
422 | c = tomoyo_make_byte(c, d, e); | ||
423 | if (tomoyo_is_invalid(c)) | ||
424 | /* pattern is not \000 */ | ||
425 | continue; | ||
426 | } | ||
427 | goto out; | ||
428 | } else if (tomoyo_is_invalid(c)) { | ||
429 | goto out; | ||
430 | } | ||
431 | } | ||
432 | } while (*domainname); | ||
433 | return true; | ||
434 | out: | ||
435 | return false; | ||
436 | } | ||
437 | |||
438 | /** | ||
439 | * tomoyo_is_domain_def - Check whether the given token can be a domainname. | ||
440 | * | ||
441 | * @buffer: The token to check. | ||
442 | * | ||
443 | * Returns true if @buffer possibly be a domainname, false otherwise. | ||
444 | */ | ||
445 | bool tomoyo_is_domain_def(const unsigned char *buffer) | ||
446 | { | ||
447 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * tomoyo_find_domain - Find a domain by the given name. | ||
452 | * | ||
453 | * @domainname: The domainname to find. | ||
454 | * | ||
455 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | ||
456 | * | ||
457 | * Caller holds tomoyo_read_lock(). | ||
458 | */ | ||
459 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | ||
460 | { | ||
461 | struct tomoyo_domain_info *domain; | ||
462 | struct tomoyo_path_info name; | ||
463 | |||
464 | name.name = domainname; | ||
465 | tomoyo_fill_path_info(&name); | ||
466 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
467 | if (!domain->is_deleted && | ||
468 | !tomoyo_pathcmp(&name, domain->domainname)) | ||
469 | return domain; | ||
470 | } | ||
471 | return NULL; | ||
472 | } | ||
473 | |||
474 | /** | ||
475 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. | ||
476 | * | ||
477 | * @filename: The string to evaluate. | ||
478 | * | ||
479 | * Returns the initial length without a pattern in @filename. | ||
480 | */ | ||
481 | static int tomoyo_const_part_length(const char *filename) | ||
482 | { | ||
483 | char c; | ||
484 | int len = 0; | ||
485 | |||
486 | if (!filename) | ||
487 | return 0; | ||
488 | while ((c = *filename++) != '\0') { | ||
489 | if (c != '\\') { | ||
490 | len++; | ||
491 | continue; | ||
492 | } | ||
493 | c = *filename++; | ||
494 | switch (c) { | ||
495 | case '\\': /* "\\" */ | ||
496 | len += 2; | ||
497 | continue; | ||
498 | case '0': /* "\ooo" */ | ||
499 | case '1': | ||
500 | case '2': | ||
501 | case '3': | ||
502 | c = *filename++; | ||
503 | if (c < '0' || c > '7') | ||
504 | break; | ||
505 | c = *filename++; | ||
506 | if (c < '0' || c > '7') | ||
507 | break; | ||
508 | len += 4; | ||
509 | continue; | ||
510 | } | ||
511 | break; | ||
512 | } | ||
513 | return len; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. | ||
518 | * | ||
519 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. | ||
520 | * | ||
521 | * The caller sets "struct tomoyo_path_info"->name. | ||
522 | */ | ||
523 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | ||
524 | { | ||
525 | const char *name = ptr->name; | ||
526 | const int len = strlen(name); | ||
527 | |||
528 | ptr->const_len = tomoyo_const_part_length(name); | ||
529 | ptr->is_dir = len && (name[len - 1] == '/'); | ||
530 | ptr->is_patterned = (ptr->const_len < len); | ||
531 | ptr->hash = full_name_hash(name, len); | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. | ||
536 | * | ||
537 | * @filename: The start of string to check. | ||
538 | * @filename_end: The end of string to check. | ||
539 | * @pattern: The start of pattern to compare. | ||
540 | * @pattern_end: The end of pattern to compare. | ||
541 | * | ||
542 | * Returns true if @filename matches @pattern, false otherwise. | ||
543 | */ | ||
544 | static bool tomoyo_file_matches_pattern2(const char *filename, | ||
545 | const char *filename_end, | ||
546 | const char *pattern, | ||
547 | const char *pattern_end) | ||
548 | { | ||
549 | while (filename < filename_end && pattern < pattern_end) { | ||
550 | char c; | ||
551 | if (*pattern != '\\') { | ||
552 | if (*filename++ != *pattern++) | ||
553 | return false; | ||
554 | continue; | ||
555 | } | ||
556 | c = *filename; | ||
557 | pattern++; | ||
558 | switch (*pattern) { | ||
559 | int i; | ||
560 | int j; | ||
561 | case '?': | ||
562 | if (c == '/') { | ||
563 | return false; | ||
564 | } else if (c == '\\') { | ||
565 | if (filename[1] == '\\') | ||
566 | filename++; | ||
567 | else if (tomoyo_is_byte_range(filename + 1)) | ||
568 | filename += 3; | ||
569 | else | ||
570 | return false; | ||
571 | } | ||
572 | break; | ||
573 | case '\\': | ||
574 | if (c != '\\') | ||
575 | return false; | ||
576 | if (*++filename != '\\') | ||
577 | return false; | ||
578 | break; | ||
579 | case '+': | ||
580 | if (!isdigit(c)) | ||
581 | return false; | ||
582 | break; | ||
583 | case 'x': | ||
584 | if (!isxdigit(c)) | ||
585 | return false; | ||
586 | break; | ||
587 | case 'a': | ||
588 | if (!tomoyo_is_alphabet_char(c)) | ||
589 | return false; | ||
590 | break; | ||
591 | case '0': | ||
592 | case '1': | ||
593 | case '2': | ||
594 | case '3': | ||
595 | if (c == '\\' && tomoyo_is_byte_range(filename + 1) | ||
596 | && strncmp(filename + 1, pattern, 3) == 0) { | ||
597 | filename += 3; | ||
598 | pattern += 2; | ||
599 | break; | ||
600 | } | ||
601 | return false; /* Not matched. */ | ||
602 | case '*': | ||
603 | case '@': | ||
604 | for (i = 0; i <= filename_end - filename; i++) { | ||
605 | if (tomoyo_file_matches_pattern2( | ||
606 | filename + i, filename_end, | ||
607 | pattern + 1, pattern_end)) | ||
608 | return true; | ||
609 | c = filename[i]; | ||
610 | if (c == '.' && *pattern == '@') | ||
611 | break; | ||
612 | if (c != '\\') | ||
613 | continue; | ||
614 | if (filename[i + 1] == '\\') | ||
615 | i++; | ||
616 | else if (tomoyo_is_byte_range(filename + i + 1)) | ||
617 | i += 3; | ||
618 | else | ||
619 | break; /* Bad pattern. */ | ||
620 | } | ||
621 | return false; /* Not matched. */ | ||
622 | default: | ||
623 | j = 0; | ||
624 | c = *pattern; | ||
625 | if (c == '$') { | ||
626 | while (isdigit(filename[j])) | ||
627 | j++; | ||
628 | } else if (c == 'X') { | ||
629 | while (isxdigit(filename[j])) | ||
630 | j++; | ||
631 | } else if (c == 'A') { | ||
632 | while (tomoyo_is_alphabet_char(filename[j])) | ||
633 | j++; | ||
634 | } | ||
635 | for (i = 1; i <= j; i++) { | ||
636 | if (tomoyo_file_matches_pattern2( | ||
637 | filename + i, filename_end, | ||
638 | pattern + 1, pattern_end)) | ||
639 | return true; | ||
640 | } | ||
641 | return false; /* Not matched or bad pattern. */ | ||
642 | } | ||
643 | filename++; | ||
644 | pattern++; | ||
645 | } | ||
646 | while (*pattern == '\\' && | ||
647 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) | ||
648 | pattern += 2; | ||
649 | return filename == filename_end && pattern == pattern_end; | ||
650 | } | ||
651 | |||
652 | /** | ||
653 | * tomoyo_file_matches_pattern - Pattern matching without '/' character. | ||
654 | * | ||
655 | * @filename: The start of string to check. | ||
656 | * @filename_end: The end of string to check. | ||
657 | * @pattern: The start of pattern to compare. | ||
658 | * @pattern_end: The end of pattern to compare. | ||
659 | * | ||
660 | * Returns true if @filename matches @pattern, false otherwise. | ||
661 | */ | ||
662 | static bool tomoyo_file_matches_pattern(const char *filename, | ||
663 | const char *filename_end, | ||
664 | const char *pattern, | ||
665 | const char *pattern_end) | ||
666 | { | ||
667 | const char *pattern_start = pattern; | ||
668 | bool first = true; | ||
669 | bool result; | ||
670 | |||
671 | while (pattern < pattern_end - 1) { | ||
672 | /* Split at "\-" pattern. */ | ||
673 | if (*pattern++ != '\\' || *pattern++ != '-') | ||
674 | continue; | ||
675 | result = tomoyo_file_matches_pattern2(filename, | ||
676 | filename_end, | ||
677 | pattern_start, | ||
678 | pattern - 2); | ||
679 | if (first) | ||
680 | result = !result; | ||
681 | if (result) | ||
682 | return false; | ||
683 | first = false; | ||
684 | pattern_start = pattern; | ||
685 | } | ||
686 | result = tomoyo_file_matches_pattern2(filename, filename_end, | ||
687 | pattern_start, pattern_end); | ||
688 | return first ? result : !result; | ||
689 | } | ||
690 | |||
691 | /** | ||
692 | * tomoyo_path_matches_pattern2 - Do pathname pattern matching. | ||
693 | * | ||
694 | * @f: The start of string to check. | ||
695 | * @p: The start of pattern to compare. | ||
696 | * | ||
697 | * Returns true if @f matches @p, false otherwise. | ||
698 | */ | ||
699 | static bool tomoyo_path_matches_pattern2(const char *f, const char *p) | ||
700 | { | ||
701 | const char *f_delimiter; | ||
702 | const char *p_delimiter; | ||
703 | |||
704 | while (*f && *p) { | ||
705 | f_delimiter = strchr(f, '/'); | ||
706 | if (!f_delimiter) | ||
707 | f_delimiter = f + strlen(f); | ||
708 | p_delimiter = strchr(p, '/'); | ||
709 | if (!p_delimiter) | ||
710 | p_delimiter = p + strlen(p); | ||
711 | if (*p == '\\' && *(p + 1) == '{') | ||
712 | goto recursive; | ||
713 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p, | ||
714 | p_delimiter)) | ||
715 | return false; | ||
716 | f = f_delimiter; | ||
717 | if (*f) | ||
718 | f++; | ||
719 | p = p_delimiter; | ||
720 | if (*p) | ||
721 | p++; | ||
722 | } | ||
723 | /* Ignore trailing "\*" and "\@" in @pattern. */ | ||
724 | while (*p == '\\' && | ||
725 | (*(p + 1) == '*' || *(p + 1) == '@')) | ||
726 | p += 2; | ||
727 | return !*f && !*p; | ||
728 | recursive: | ||
729 | /* | ||
730 | * The "\{" pattern is permitted only after '/' character. | ||
731 | * This guarantees that below "*(p - 1)" is safe. | ||
732 | * Also, the "\}" pattern is permitted only before '/' character | ||
733 | * so that "\{" + "\}" pair will not break the "\-" operator. | ||
734 | */ | ||
735 | if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || | ||
736 | *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') | ||
737 | return false; /* Bad pattern. */ | ||
738 | do { | ||
739 | /* Compare current component with pattern. */ | ||
740 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, | ||
741 | p_delimiter - 2)) | ||
742 | break; | ||
743 | /* Proceed to next component. */ | ||
744 | f = f_delimiter; | ||
745 | if (!*f) | ||
746 | break; | ||
747 | f++; | ||
748 | /* Continue comparison. */ | ||
749 | if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) | ||
750 | return true; | ||
751 | f_delimiter = strchr(f, '/'); | ||
752 | } while (f_delimiter); | ||
753 | return false; /* Not matched. */ | ||
754 | } | ||
755 | |||
756 | /** | ||
757 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. | ||
758 | * | ||
759 | * @filename: The filename to check. | ||
760 | * @pattern: The pattern to compare. | ||
761 | * | ||
762 | * Returns true if matches, false otherwise. | ||
763 | * | ||
764 | * The following patterns are available. | ||
765 | * \\ \ itself. | ||
766 | * \ooo Octal representation of a byte. | ||
767 | * \* Zero or more repetitions of characters other than '/'. | ||
768 | * \@ Zero or more repetitions of characters other than '/' or '.'. | ||
769 | * \? 1 byte character other than '/'. | ||
770 | * \$ One or more repetitions of decimal digits. | ||
771 | * \+ 1 decimal digit. | ||
772 | * \X One or more repetitions of hexadecimal digits. | ||
773 | * \x 1 hexadecimal digit. | ||
774 | * \A One or more repetitions of alphabet characters. | ||
775 | * \a 1 alphabet character. | ||
776 | * | ||
777 | * \- Subtraction operator. | ||
778 | * | ||
779 | * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ | ||
780 | * /dir/dir/dir/ ). | ||
781 | */ | ||
782 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | ||
783 | const struct tomoyo_path_info *pattern) | ||
784 | { | ||
785 | const char *f = filename->name; | ||
786 | const char *p = pattern->name; | ||
787 | const int len = pattern->const_len; | ||
788 | |||
789 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ | ||
790 | if (!pattern->is_patterned) | ||
791 | return !tomoyo_pathcmp(filename, pattern); | ||
792 | /* Don't compare directory and non-directory. */ | ||
793 | if (filename->is_dir != pattern->is_dir) | ||
794 | return false; | ||
795 | /* Compare the initial length without patterns. */ | ||
796 | if (strncmp(f, p, len)) | ||
797 | return false; | ||
798 | f += len; | ||
799 | p += len; | ||
800 | return tomoyo_path_matches_pattern2(f, p); | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. | ||
805 | * | ||
806 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | ||
807 | * | ||
808 | * This function uses kzalloc(), so the caller must call kfree() | ||
809 | * if this function didn't return NULL. | ||
810 | */ | ||
811 | const char *tomoyo_get_exe(void) | ||
812 | { | ||
813 | struct mm_struct *mm = current->mm; | ||
814 | struct vm_area_struct *vma; | ||
815 | const char *cp = NULL; | ||
816 | |||
817 | if (!mm) | ||
818 | return NULL; | ||
819 | down_read(&mm->mmap_sem); | ||
820 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
821 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { | ||
822 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); | ||
823 | break; | ||
824 | } | ||
825 | } | ||
826 | up_read(&mm->mmap_sem); | ||
827 | return cp; | ||
828 | } | ||
829 | |||
830 | /** | ||
831 | * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. | ||
832 | * | ||
833 | * @r: Pointer to "struct tomoyo_request_info" to initialize. | ||
834 | * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). | ||
835 | * | ||
836 | * Returns mode. | ||
837 | */ | ||
838 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | ||
839 | struct tomoyo_domain_info *domain) | ||
840 | { | ||
841 | memset(r, 0, sizeof(*r)); | ||
842 | if (!domain) | ||
843 | domain = tomoyo_domain(); | ||
844 | r->domain = domain; | ||
845 | r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | ||
846 | return r->mode; | ||
847 | } | ||
848 | |||
849 | /** | ||
850 | * tomoyo_warn_log - Print warning or error message on console. | ||
851 | * | ||
852 | * @r: Pointer to "struct tomoyo_request_info". | ||
853 | * @fmt: The printf()'s format string, followed by parameters. | ||
854 | */ | ||
855 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
856 | { | ||
857 | int len = PAGE_SIZE; | ||
858 | va_list args; | ||
859 | char *buffer; | ||
860 | if (!tomoyo_verbose_mode(r->domain)) | ||
861 | return; | ||
862 | while (1) { | ||
863 | int len2; | ||
864 | buffer = kmalloc(len, GFP_NOFS); | ||
865 | if (!buffer) | ||
866 | return; | ||
867 | va_start(args, fmt); | ||
868 | len2 = vsnprintf(buffer, len - 1, fmt, args); | ||
869 | va_end(args); | ||
870 | if (len2 <= len - 1) { | ||
871 | buffer[len2] = '\0'; | ||
872 | break; | ||
873 | } | ||
874 | len = len2 + 1; | ||
875 | kfree(buffer); | ||
876 | } | ||
877 | printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n", | ||
878 | r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", | ||
879 | buffer, tomoyo_get_last_name(r->domain)); | ||
880 | kfree(buffer); | ||
881 | } | ||
882 | |||
883 | /** | ||
884 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | ||
885 | * | ||
886 | * @r: Pointer to "struct tomoyo_request_info". | ||
887 | * | ||
888 | * Returns true if the domain is not exceeded quota, false otherwise. | ||
889 | * | ||
890 | * Caller holds tomoyo_read_lock(). | ||
891 | */ | ||
892 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | ||
893 | { | ||
894 | unsigned int count = 0; | ||
895 | struct tomoyo_domain_info *domain = r->domain; | ||
896 | struct tomoyo_acl_info *ptr; | ||
897 | |||
898 | if (r->mode != TOMOYO_CONFIG_LEARNING) | ||
899 | return false; | ||
900 | if (!domain) | ||
901 | return true; | ||
902 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
903 | switch (ptr->type) { | ||
904 | u16 perm; | ||
905 | u8 i; | ||
906 | case TOMOYO_TYPE_PATH_ACL: | ||
907 | perm = container_of(ptr, struct tomoyo_path_acl, head) | ||
908 | ->perm; | ||
909 | for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) | ||
910 | if (perm & (1 << i)) | ||
911 | count++; | ||
912 | if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
913 | count -= 2; | ||
914 | break; | ||
915 | case TOMOYO_TYPE_PATH2_ACL: | ||
916 | perm = container_of(ptr, struct tomoyo_path2_acl, head) | ||
917 | ->perm; | ||
918 | for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) | ||
919 | if (perm & (1 << i)) | ||
920 | count++; | ||
921 | break; | ||
922 | case TOMOYO_TYPE_PATH_NUMBER_ACL: | ||
923 | perm = container_of(ptr, struct tomoyo_path_number_acl, | ||
924 | head)->perm; | ||
925 | for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++) | ||
926 | if (perm & (1 << i)) | ||
927 | count++; | ||
928 | break; | ||
929 | case TOMOYO_TYPE_PATH_NUMBER3_ACL: | ||
930 | perm = container_of(ptr, struct tomoyo_path_number3_acl, | ||
931 | head)->perm; | ||
932 | for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++) | ||
933 | if (perm & (1 << i)) | ||
934 | count++; | ||
935 | break; | ||
936 | case TOMOYO_TYPE_MOUNT_ACL: | ||
937 | if (!container_of(ptr, struct tomoyo_mount_acl, head)-> | ||
938 | is_deleted) | ||
939 | count++; | ||
940 | } | ||
941 | } | ||
942 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | ||
943 | return true; | ||
944 | if (!domain->quota_warned) { | ||
945 | domain->quota_warned = true; | ||
946 | printk(KERN_WARNING "TOMOYO-WARNING: " | ||
947 | "Domain '%s' has so many ACLs to hold. " | ||
948 | "Stopped learning mode.\n", domain->domainname->name); | ||
949 | } | ||
950 | return false; | ||
951 | } | ||