Commit c3ef1500ec833890275172c7d063333404b64d60
Committed by
James Morris
1 parent
17fcfbd9d4
Exists in
master
and in
39 other branches
TOMOYO: Split files into some pieces.
security/tomoyo/common.c became too large to read. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Showing 11 changed files with 1469 additions and 1416 deletions Side-by-side Diff
security/tomoyo/Makefile
security/tomoyo/common.c
Changes suppressed. Click to show
... | ... | @@ -3,10 +3,7 @@ |
3 | 3 | * |
4 | 4 | * Common functions for TOMOYO. |
5 | 5 | * |
6 | - * Copyright (C) 2005-2009 NTT DATA CORPORATION | |
7 | - * | |
8 | - * Version: 2.2.0 2009/04/01 | |
9 | - * | |
6 | + * Copyright (C) 2005-2010 NTT DATA CORPORATION | |
10 | 7 | */ |
11 | 8 | |
12 | 9 | #include <linux/uaccess.h> |
... | ... | @@ -15,12 +12,6 @@ |
15 | 12 | #include <linux/hardirq.h> |
16 | 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 | 15 | /* String table for functionality that takes 4 modes. */ |
25 | 16 | static const char *tomoyo_mode_4[4] = { |
26 | 17 | "disabled", "learning", "permissive", "enforcing" |
27 | 18 | |
... | ... | @@ -64,43 +55,7 @@ |
64 | 55 | |
65 | 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 | 58 | /** |
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 | -/** | |
104 | 59 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
105 | 60 | * |
106 | 61 | * @head: Pointer to "struct tomoyo_io_buffer". |
... | ... | @@ -121,69 +76,6 @@ |
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 | 79 | * tomoyo_print_number_union - Print a tomoyo_number_union. |
188 | 80 | * |
189 | 81 | * @head: Pointer to "struct tomoyo_io_buffer". |
... | ... | @@ -234,704 +126,6 @@ |
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 | 129 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. |
936 | 130 | * |
937 | 131 | * @head: Pointer to "struct tomoyo_io_buffer". |
... | ... | @@ -960,33 +154,6 @@ |
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 | 157 | * tomoyo_check_flags - Check mode for specified functionality. |
991 | 158 | * |
992 | 159 | * @domain: Pointer to "struct tomoyo_domain_info". |
... | ... | @@ -1025,76 +192,6 @@ |
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 | 195 | * tomoyo_find_or_assign_new_profile - Create a new profile. |
1099 | 196 | * |
1100 | 197 | * @profile: Profile number to create. |
1101 | 198 | |
... | ... | @@ -2118,92 +1215,7 @@ |
2118 | 1215 | return 0; |
2119 | 1216 | } |
2120 | 1217 | |
2121 | -/* path to policy loader */ | |
2122 | -static const char *tomoyo_loader = "/sbin/tomoyo-init"; | |
2123 | - | |
2124 | 1218 | /** |
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 | -/** | |
2207 | 1219 | * tomoyo_print_header - Get header line of audit log. |
2208 | 1220 | * |
2209 | 1221 | * @r: Pointer to "struct tomoyo_request_info". |
... | ... | @@ -2601,7 +1613,7 @@ |
2601 | 1613 | * |
2602 | 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 | 1618 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); |
2607 | 1619 | |
... | ... | @@ -2744,8 +1756,8 @@ |
2744 | 1756 | * |
2745 | 1757 | * Caller holds tomoyo_read_lock(). |
2746 | 1758 | */ |
2747 | -static int tomoyo_read_control(struct file *file, char __user *buffer, | |
2748 | - const int buffer_len) | |
1759 | +int tomoyo_read_control(struct file *file, char __user *buffer, | |
1760 | + const int buffer_len) | |
2749 | 1761 | { |
2750 | 1762 | int len = 0; |
2751 | 1763 | struct tomoyo_io_buffer *head = file->private_data; |
... | ... | @@ -2789,8 +1801,8 @@ |
2789 | 1801 | * |
2790 | 1802 | * Caller holds tomoyo_read_lock(). |
2791 | 1803 | */ |
2792 | -static int tomoyo_write_control(struct file *file, const char __user *buffer, | |
2793 | - const int buffer_len) | |
1804 | +int tomoyo_write_control(struct file *file, const char __user *buffer, | |
1805 | + const int buffer_len) | |
2794 | 1806 | { |
2795 | 1807 | struct tomoyo_io_buffer *head = file->private_data; |
2796 | 1808 | int error = buffer_len; |
... | ... | @@ -2841,7 +1853,7 @@ |
2841 | 1853 | * |
2842 | 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 | 1858 | struct tomoyo_io_buffer *head = file->private_data; |
2847 | 1859 | const bool is_write = !!head->write_buf; |
2848 | 1860 | |
2849 | 1861 | |
2850 | 1862 | |
... | ... | @@ -2868,132 +1880,23 @@ |
2868 | 1880 | } |
2869 | 1881 | |
2870 | 1882 | /** |
2871 | - * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | |
2872 | - * | |
2873 | - * @inode: Pointer to "struct inode". | |
2874 | - * @file: Pointer to "struct file". | |
2875 | - * | |
2876 | - * Returns 0 on success, negative value otherwise. | |
1883 | + * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. | |
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) | |
2881 | - - ((u8 *) NULL); | |
2882 | - return tomoyo_open_control(key, file); | |
1887 | + struct tomoyo_domain_info *domain; | |
1888 | + const int idx = tomoyo_read_lock(); | |
1889 | + tomoyo_policy_loaded = true; | |
1890 | + /* Check all profiles currently assigned to domains are defined. */ | |
1891 | + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | |
1892 | + const u8 profile = domain->profile; | |
1893 | + if (tomoyo_profile_ptr[profile]) | |
1894 | + continue; | |
1895 | + panic("Profile %u (used by '%s') not defined.\n", | |
1896 | + profile, domain->domainname->name); | |
1897 | + } | |
1898 | + tomoyo_read_unlock(idx); | |
1899 | + printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n"); | |
1900 | + printk(KERN_INFO "Mandatory Access Control activated.\n"); | |
2883 | 1901 | } |
2884 | - | |
2885 | -/** | |
2886 | - * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. | |
2887 | - * | |
2888 | - * @inode: Pointer to "struct inode". | |
2889 | - * @file: Pointer to "struct file". | |
2890 | - * | |
2891 | - * Returns 0 on success, negative value otherwise. | |
2892 | - */ | |
2893 | -static int tomoyo_release(struct inode *inode, struct file *file) | |
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 | -} | |
2997 | - | |
2998 | -fs_initcall(tomoyo_initerface_init); |
security/tomoyo/common.h
... | ... | @@ -673,6 +673,31 @@ |
673 | 673 | extern asmlinkage long sys_getpid(void); |
674 | 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 | 701 | /* Check whether the given name matches the given name_union. */ |
677 | 702 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
678 | 703 | const struct tomoyo_name_union *ptr); |
... | ... | @@ -837,8 +862,8 @@ |
837 | 862 | /* Set memory quota. */ |
838 | 863 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); |
839 | 864 | |
840 | -/* Initialize realpath related code. */ | |
841 | -void __init tomoyo_realpath_init(void); | |
865 | +/* Initialize mm related code. */ | |
866 | +void __init tomoyo_mm_init(void); | |
842 | 867 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
843 | 868 | const struct tomoyo_path_info *filename); |
844 | 869 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
security/tomoyo/domain.c
1 | 1 | /* |
2 | 2 | * security/tomoyo/domain.c |
3 | 3 | * |
4 | - * Implementation of the Domain-Based Mandatory Access Control. | |
4 | + * Domain transition functions for TOMOYO. | |
5 | 5 | * |
6 | - * Copyright (C) 2005-2009 NTT DATA CORPORATION | |
7 | - * | |
8 | - * Version: 2.2.0 2009/04/01 | |
9 | - * | |
6 | + * Copyright (C) 2005-2010 NTT DATA CORPORATION | |
10 | 7 | */ |
11 | 8 | |
12 | 9 | #include "common.h" |
13 | 10 | |
... | ... | @@ -697,23 +694,10 @@ |
697 | 694 | struct tomoyo_path_info rn; /* real name */ |
698 | 695 | struct tomoyo_path_info sn; /* symlink name */ |
699 | 696 | struct tomoyo_path_info ln; /* last name */ |
700 | - static bool initialized; | |
701 | 697 | |
702 | 698 | tomoyo_init_request_info(&r, NULL); |
703 | 699 | if (!tmp) |
704 | 700 | goto out; |
705 | - | |
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 | 701 | |
718 | 702 | retry: |
719 | 703 | /* Get tomoyo_realpath of program. */ |
security/tomoyo/file.c
1 | 1 | /* |
2 | 2 | * security/tomoyo/file.c |
3 | 3 | * |
4 | - * Implementation of the Domain-Based Mandatory Access Control. | |
4 | + * Pathname restriction functions. | |
5 | 5 | * |
6 | - * Copyright (C) 2005-2009 NTT DATA CORPORATION | |
7 | - * | |
8 | - * Version: 2.2.0 2009/04/01 | |
9 | - * | |
6 | + * Copyright (C) 2005-2010 NTT DATA CORPORATION | |
10 | 7 | */ |
11 | 8 | |
12 | 9 | #include "common.h" |
... | ... | @@ -97,61 +94,6 @@ |
97 | 94 | if (ptr->is_group) |
98 | 95 | return tomoyo_number_matches_group(value, value, ptr->group); |
99 | 96 | return value >= ptr->values[0] && value <= ptr->values[1]; |
100 | -} | |
101 | - | |
102 | -/** | |
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 | 97 | } |
156 | 98 | |
157 | 99 | /** |
security/tomoyo/load_policy.c
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 | +} |
security/tomoyo/memory.c
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 | +} |
security/tomoyo/realpath.c
1 | 1 | /* |
2 | 2 | * security/tomoyo/realpath.c |
3 | 3 | * |
4 | - * Get the canonicalized absolute pathnames. The basis for TOMOYO. | |
4 | + * Pathname calculation functions for TOMOYO. | |
5 | 5 | * |
6 | - * Copyright (C) 2005-2009 NTT DATA CORPORATION | |
7 | - * | |
8 | - * Version: 2.2.0 2009/04/01 | |
9 | - * | |
6 | + * Copyright (C) 2005-2010 NTT DATA CORPORATION | |
10 | 7 | */ |
11 | 8 | |
12 | 9 | #include <linux/types.h> |
13 | 10 | #include <linux/mount.h> |
14 | 11 | #include <linux/mnt_namespace.h> |
15 | 12 | #include <linux/fs_struct.h> |
16 | -#include <linux/hash.h> | |
17 | 13 | #include <linux/magic.h> |
18 | 14 | #include <linux/slab.h> |
19 | 15 | #include "common.h" |
... | ... | @@ -123,7 +119,7 @@ |
123 | 119 | } |
124 | 120 | } |
125 | 121 | if (error) |
126 | - printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); | |
122 | + tomoyo_warn_oom(__func__); | |
127 | 123 | return error; |
128 | 124 | } |
129 | 125 | |
... | ... | @@ -141,6 +137,7 @@ |
141 | 137 | { |
142 | 138 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); |
143 | 139 | |
140 | + BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | |
144 | 141 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
145 | 142 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
146 | 143 | if (!buf) |
... | ... | @@ -188,208 +185,5 @@ |
188 | 185 | return buf; |
189 | 186 | } |
190 | 187 | return NULL; |
191 | -} | |
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 | 188 | } |
security/tomoyo/securityfs_if.c
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); |
security/tomoyo/tomoyo.c
... | ... | @@ -3,10 +3,7 @@ |
3 | 3 | * |
4 | 4 | * LSM hooks for TOMOYO Linux. |
5 | 5 | * |
6 | - * Copyright (C) 2005-2009 NTT DATA CORPORATION | |
7 | - * | |
8 | - * Version: 2.2.0 2009/04/01 | |
9 | - * | |
6 | + * Copyright (C) 2005-2010 NTT DATA CORPORATION | |
10 | 7 | */ |
11 | 8 | |
12 | 9 | #include <linux/security.h> |
... | ... | @@ -286,7 +283,7 @@ |
286 | 283 | panic("Failure registering TOMOYO Linux"); |
287 | 284 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
288 | 285 | cred->security = &tomoyo_kernel_domain; |
289 | - tomoyo_realpath_init(); | |
286 | + tomoyo_mm_init(); | |
290 | 287 | return 0; |
291 | 288 | } |
292 | 289 |
security/tomoyo/util.c
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 | +} |