diff options
-rw-r--r-- | security/tomoyo/common.c | 205 | ||||
-rw-r--r-- | security/tomoyo/common.h | 7 | ||||
-rw-r--r-- | security/tomoyo/util.c | 39 |
3 files changed, 83 insertions, 168 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 465df022c211..2b280350708f 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -11,16 +11,6 @@ | |||
11 | #include <linux/security.h> | 11 | #include <linux/security.h> |
12 | #include "common.h" | 12 | #include "common.h" |
13 | 13 | ||
14 | static struct tomoyo_profile tomoyo_default_profile = { | ||
15 | .learning = &tomoyo_default_profile.preference, | ||
16 | .permissive = &tomoyo_default_profile.preference, | ||
17 | .enforcing = &tomoyo_default_profile.preference, | ||
18 | .preference.enforcing_verbose = true, | ||
19 | .preference.learning_max_entry = 2048, | ||
20 | .preference.learning_verbose = false, | ||
21 | .preference.permissive_verbose = true | ||
22 | }; | ||
23 | |||
24 | /* Profile version. Currently only 20090903 is defined. */ | 14 | /* Profile version. Currently only 20090903 is defined. */ |
25 | static unsigned int tomoyo_profile_version; | 15 | static unsigned int tomoyo_profile_version; |
26 | 16 | ||
@@ -61,6 +51,11 @@ static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | |||
61 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | 51 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", |
62 | }; | 52 | }; |
63 | 53 | ||
54 | /* String table for PREFERENCE keyword. */ | ||
55 | static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { | ||
56 | [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", | ||
57 | }; | ||
58 | |||
64 | /* Permit policy management by non-root user? */ | 59 | /* Permit policy management by non-root user? */ |
65 | static bool tomoyo_manage_by_non_root; | 60 | static bool tomoyo_manage_by_non_root; |
66 | 61 | ||
@@ -71,11 +66,22 @@ static bool tomoyo_manage_by_non_root; | |||
71 | * | 66 | * |
72 | * @value: Bool value. | 67 | * @value: Bool value. |
73 | */ | 68 | */ |
69 | /* | ||
74 | static const char *tomoyo_yesno(const unsigned int value) | 70 | static const char *tomoyo_yesno(const unsigned int value) |
75 | { | 71 | { |
76 | return value ? "yes" : "no"; | 72 | return value ? "yes" : "no"; |
77 | } | 73 | } |
74 | */ | ||
78 | 75 | ||
76 | /** | ||
77 | * tomoyo_addprintf - strncat()-like-snprintf(). | ||
78 | * | ||
79 | * @buffer: Buffer to write to. Must be '\0'-terminated. | ||
80 | * @len: Size of @buffer. | ||
81 | * @fmt: The printf()'s format string, followed by parameters. | ||
82 | * | ||
83 | * Returns nothing. | ||
84 | */ | ||
79 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | 85 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) |
80 | { | 86 | { |
81 | va_list args; | 87 | va_list args; |
@@ -294,12 +300,10 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
294 | ptr = tomoyo_profile_ptr[profile]; | 300 | ptr = tomoyo_profile_ptr[profile]; |
295 | if (!ptr && tomoyo_memory_ok(entry)) { | 301 | if (!ptr && tomoyo_memory_ok(entry)) { |
296 | ptr = entry; | 302 | ptr = entry; |
297 | ptr->learning = &tomoyo_default_profile.preference; | ||
298 | ptr->permissive = &tomoyo_default_profile.preference; | ||
299 | ptr->enforcing = &tomoyo_default_profile.preference; | ||
300 | ptr->default_config = TOMOYO_CONFIG_DISABLED; | 303 | ptr->default_config = TOMOYO_CONFIG_DISABLED; |
301 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, | 304 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, |
302 | sizeof(ptr->config)); | 305 | sizeof(ptr->config)); |
306 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | ||
303 | mb(); /* Avoid out-of-order execution. */ | 307 | mb(); /* Avoid out-of-order execution. */ |
304 | tomoyo_profile_ptr[profile] = ptr; | 308 | tomoyo_profile_ptr[profile] = ptr; |
305 | entry = NULL; | 309 | entry = NULL; |
@@ -319,13 +323,22 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
319 | */ | 323 | */ |
320 | struct tomoyo_profile *tomoyo_profile(const u8 profile) | 324 | struct tomoyo_profile *tomoyo_profile(const u8 profile) |
321 | { | 325 | { |
326 | static struct tomoyo_profile tomoyo_null_profile; | ||
322 | struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; | 327 | struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; |
323 | if (!tomoyo_policy_loaded) | 328 | if (!ptr) |
324 | return &tomoyo_default_profile; | 329 | ptr = &tomoyo_null_profile; |
325 | BUG_ON(!ptr); | ||
326 | return ptr; | 330 | return ptr; |
327 | } | 331 | } |
328 | 332 | ||
333 | /** | ||
334 | * tomoyo_find_yesno - Find values for specified keyword. | ||
335 | * | ||
336 | * @string: String to check. | ||
337 | * @find: Name of keyword. | ||
338 | * | ||
339 | * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. | ||
340 | */ | ||
341 | /* | ||
329 | static s8 tomoyo_find_yesno(const char *string, const char *find) | 342 | static s8 tomoyo_find_yesno(const char *string, const char *find) |
330 | { | 343 | { |
331 | const char *cp = strstr(string, find); | 344 | const char *cp = strstr(string, find); |
@@ -338,19 +351,17 @@ static s8 tomoyo_find_yesno(const char *string, const char *find) | |||
338 | } | 351 | } |
339 | return -1; | 352 | return -1; |
340 | } | 353 | } |
354 | */ | ||
341 | 355 | ||
342 | static void tomoyo_set_bool(bool *b, const char *string, const char *find) | 356 | /** |
343 | { | 357 | * tomoyo_set_uint - Set value for specified preference. |
344 | switch (tomoyo_find_yesno(string, find)) { | 358 | * |
345 | case 1: | 359 | * @i: Pointer to "unsigned int". |
346 | *b = true; | 360 | * @string: String to check. |
347 | break; | 361 | * @find: Name of keyword. |
348 | case 0: | 362 | * |
349 | *b = false; | 363 | * Returns nothing. |
350 | break; | 364 | */ |
351 | } | ||
352 | } | ||
353 | |||
354 | static void tomoyo_set_uint(unsigned int *i, const char *string, | 365 | static void tomoyo_set_uint(unsigned int *i, const char *string, |
355 | const char *find) | 366 | const char *find) |
356 | { | 367 | { |
@@ -359,51 +370,16 @@ static void tomoyo_set_uint(unsigned int *i, const char *string, | |||
359 | sscanf(cp + strlen(find), "=%u", i); | 370 | sscanf(cp + strlen(find), "=%u", i); |
360 | } | 371 | } |
361 | 372 | ||
362 | static void tomoyo_set_pref(const char *name, const char *value, | 373 | /** |
363 | const bool use_default, | 374 | * tomoyo_set_mode - Set mode for specified profile. |
364 | struct tomoyo_profile *profile) | 375 | * |
365 | { | 376 | * @name: Name of functionality. |
366 | struct tomoyo_preference **pref; | 377 | * @value: Mode for @name. |
367 | bool *verbose; | 378 | * @profile: Pointer to "struct tomoyo_profile". |
368 | if (!strcmp(name, "enforcing")) { | 379 | * |
369 | if (use_default) { | 380 | * Returns 0 on success, negative value otherwise. |
370 | pref = &profile->enforcing; | 381 | */ |
371 | goto set_default; | ||
372 | } | ||
373 | profile->enforcing = &profile->preference; | ||
374 | verbose = &profile->preference.enforcing_verbose; | ||
375 | goto set_verbose; | ||
376 | } | ||
377 | if (!strcmp(name, "permissive")) { | ||
378 | if (use_default) { | ||
379 | pref = &profile->permissive; | ||
380 | goto set_default; | ||
381 | } | ||
382 | profile->permissive = &profile->preference; | ||
383 | verbose = &profile->preference.permissive_verbose; | ||
384 | goto set_verbose; | ||
385 | } | ||
386 | if (!strcmp(name, "learning")) { | ||
387 | if (use_default) { | ||
388 | pref = &profile->learning; | ||
389 | goto set_default; | ||
390 | } | ||
391 | profile->learning = &profile->preference; | ||
392 | tomoyo_set_uint(&profile->preference.learning_max_entry, value, | ||
393 | "max_entry"); | ||
394 | verbose = &profile->preference.learning_verbose; | ||
395 | goto set_verbose; | ||
396 | } | ||
397 | return; | ||
398 | set_default: | ||
399 | *pref = &tomoyo_default_profile.preference; | ||
400 | return; | ||
401 | set_verbose: | ||
402 | tomoyo_set_bool(verbose, value, "verbose"); | ||
403 | } | ||
404 | |||
405 | static int tomoyo_set_mode(char *name, const char *value, | 382 | static int tomoyo_set_mode(char *name, const char *value, |
406 | const bool use_default, | ||
407 | struct tomoyo_profile *profile) | 383 | struct tomoyo_profile *profile) |
408 | { | 384 | { |
409 | u8 i; | 385 | u8 i; |
@@ -425,7 +401,7 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
425 | } else { | 401 | } else { |
426 | return -EINVAL; | 402 | return -EINVAL; |
427 | } | 403 | } |
428 | if (use_default) { | 404 | if (strstr(value, "use_default")) { |
429 | config = TOMOYO_CONFIG_USE_DEFAULT; | 405 | config = TOMOYO_CONFIG_USE_DEFAULT; |
430 | } else { | 406 | } else { |
431 | u8 mode; | 407 | u8 mode; |
@@ -455,34 +431,21 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
455 | { | 431 | { |
456 | char *data = head->write_buf; | 432 | char *data = head->write_buf; |
457 | unsigned int i; | 433 | unsigned int i; |
458 | bool use_default = false; | ||
459 | char *cp; | 434 | char *cp; |
460 | struct tomoyo_profile *profile; | 435 | struct tomoyo_profile *profile; |
461 | if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) | 436 | if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) |
462 | return 0; | 437 | return 0; |
463 | i = simple_strtoul(data, &cp, 10); | 438 | i = simple_strtoul(data, &cp, 10); |
464 | if (data == cp) { | 439 | if (*cp != '-') |
465 | profile = &tomoyo_default_profile; | 440 | return -EINVAL; |
466 | } else { | 441 | data = cp + 1; |
467 | if (*cp != '-') | 442 | profile = tomoyo_assign_profile(i); |
468 | return -EINVAL; | 443 | if (!profile) |
469 | data = cp + 1; | 444 | return -EINVAL; |
470 | profile = tomoyo_assign_profile(i); | ||
471 | if (!profile) | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | cp = strchr(data, '='); | 445 | cp = strchr(data, '='); |
475 | if (!cp) | 446 | if (!cp) |
476 | return -EINVAL; | 447 | return -EINVAL; |
477 | *cp++ = '\0'; | 448 | *cp++ = '\0'; |
478 | if (profile != &tomoyo_default_profile) | ||
479 | use_default = strstr(cp, "use_default") != NULL; | ||
480 | if (tomoyo_str_starts(&data, "PREFERENCE::")) { | ||
481 | tomoyo_set_pref(data, cp, use_default, profile); | ||
482 | return 0; | ||
483 | } | ||
484 | if (profile == &tomoyo_default_profile) | ||
485 | return -EINVAL; | ||
486 | if (!strcmp(data, "COMMENT")) { | 449 | if (!strcmp(data, "COMMENT")) { |
487 | static DEFINE_SPINLOCK(lock); | 450 | static DEFINE_SPINLOCK(lock); |
488 | const struct tomoyo_path_info *new_comment | 451 | const struct tomoyo_path_info *new_comment |
@@ -497,48 +460,13 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
497 | tomoyo_put_name(old_comment); | 460 | tomoyo_put_name(old_comment); |
498 | return 0; | 461 | return 0; |
499 | } | 462 | } |
500 | return tomoyo_set_mode(data, cp, use_default, profile); | 463 | if (!strcmp(data, "PREFERENCE")) { |
501 | } | 464 | for (i = 0; i < TOMOYO_MAX_PREF; i++) |
502 | 465 | tomoyo_set_uint(&profile->pref[i], cp, | |
503 | static void tomoyo_print_preference(struct tomoyo_io_buffer *head, | 466 | tomoyo_pref_keywords[i]); |
504 | const int idx) | 467 | return 0; |
505 | { | ||
506 | struct tomoyo_preference *pref = &tomoyo_default_profile.preference; | ||
507 | const struct tomoyo_profile *profile = idx >= 0 ? | ||
508 | tomoyo_profile_ptr[idx] : NULL; | ||
509 | char buffer[16] = ""; | ||
510 | if (profile) { | ||
511 | buffer[sizeof(buffer) - 1] = '\0'; | ||
512 | snprintf(buffer, sizeof(buffer) - 1, "%u-", idx); | ||
513 | } | ||
514 | if (profile) { | ||
515 | pref = profile->learning; | ||
516 | if (pref == &tomoyo_default_profile.preference) | ||
517 | goto skip1; | ||
518 | } | ||
519 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ " | ||
520 | "verbose=%s max_entry=%u }\n", | ||
521 | buffer, "learning", | ||
522 | tomoyo_yesno(pref->learning_verbose), | ||
523 | pref->learning_max_entry); | ||
524 | skip1: | ||
525 | if (profile) { | ||
526 | pref = profile->permissive; | ||
527 | if (pref == &tomoyo_default_profile.preference) | ||
528 | goto skip2; | ||
529 | } | ||
530 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | ||
531 | buffer, "permissive", | ||
532 | tomoyo_yesno(pref->permissive_verbose)); | ||
533 | skip2: | ||
534 | if (profile) { | ||
535 | pref = profile->enforcing; | ||
536 | if (pref == &tomoyo_default_profile.preference) | ||
537 | return; | ||
538 | } | 468 | } |
539 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | 469 | return tomoyo_set_mode(data, cp, profile); |
540 | buffer, "enforcing", | ||
541 | tomoyo_yesno(pref->enforcing_verbose)); | ||
542 | } | 470 | } |
543 | 471 | ||
544 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | 472 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) |
@@ -561,7 +489,6 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
561 | switch (head->r.step) { | 489 | switch (head->r.step) { |
562 | case 0: | 490 | case 0: |
563 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); | 491 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); |
564 | tomoyo_print_preference(head, -1); | ||
565 | head->r.step++; | 492 | head->r.step++; |
566 | break; | 493 | break; |
567 | case 1: | 494 | case 1: |
@@ -575,11 +502,18 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
575 | break; | 502 | break; |
576 | case 2: | 503 | case 2: |
577 | { | 504 | { |
505 | u8 i; | ||
578 | const struct tomoyo_path_info *comment = | 506 | const struct tomoyo_path_info *comment = |
579 | profile->comment; | 507 | profile->comment; |
580 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 508 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
581 | tomoyo_set_string(head, comment ? comment->name : ""); | 509 | tomoyo_set_string(head, comment ? comment->name : ""); |
582 | tomoyo_set_lf(head); | 510 | tomoyo_set_lf(head); |
511 | tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); | ||
512 | for (i = 0; i < TOMOYO_MAX_PREF; i++) | ||
513 | tomoyo_io_printf(head, "%s=%u ", | ||
514 | tomoyo_pref_keywords[i], | ||
515 | profile->pref[i]); | ||
516 | tomoyo_set_string(head, "}\n"); | ||
583 | head->r.step++; | 517 | head->r.step++; |
584 | } | 518 | } |
585 | break; | 519 | break; |
@@ -606,7 +540,6 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
606 | } | 540 | } |
607 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX | 541 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX |
608 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { | 542 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { |
609 | tomoyo_print_preference(head, index); | ||
610 | head->r.index++; | 543 | head->r.index++; |
611 | head->r.step = 1; | 544 | head->r.step = 1; |
612 | } | 545 | } |
@@ -1777,7 +1710,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
1777 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 1710 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
1778 | { | 1711 | { |
1779 | if (!head->r.eof) { | 1712 | if (!head->r.eof) { |
1780 | tomoyo_io_printf(head, "2.3.0"); | 1713 | tomoyo_io_printf(head, "2.4.0"); |
1781 | head->r.eof = true; | 1714 | head->r.eof = true; |
1782 | } | 1715 | } |
1783 | } | 1716 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 139ad7544460..2b39e63234c8 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -211,6 +211,12 @@ enum tomoyo_mac_category_index { | |||
211 | */ | 211 | */ |
212 | #define TOMOYO_RETRY_REQUEST 1 | 212 | #define TOMOYO_RETRY_REQUEST 1 |
213 | 213 | ||
214 | /* Index numbers for profile's PREFERENCE values. */ | ||
215 | enum tomoyo_pref_index { | ||
216 | TOMOYO_PREF_MAX_LEARNING_ENTRY, | ||
217 | TOMOYO_MAX_PREF | ||
218 | }; | ||
219 | |||
214 | /********** Structure definitions. **********/ | 220 | /********** Structure definitions. **********/ |
215 | 221 | ||
216 | /* Common header for holding ACL entries. */ | 222 | /* Common header for holding ACL entries. */ |
@@ -497,6 +503,7 @@ struct tomoyo_profile { | |||
497 | struct tomoyo_preference preference; | 503 | struct tomoyo_preference preference; |
498 | u8 default_config; | 504 | u8 default_config; |
499 | u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX]; | 505 | u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX]; |
506 | unsigned int pref[TOMOYO_MAX_PREF]; | ||
500 | }; | 507 | }; |
501 | 508 | ||
502 | /********** Function prototypes. **********/ | 509 | /********** Function prototypes. **********/ |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 72cd2b97cae8..adcbdebd7352 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -899,35 +899,10 @@ const char *tomoyo_last_word(const char *name) | |||
899 | */ | 899 | */ |
900 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | 900 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) |
901 | { | 901 | { |
902 | va_list args; | 902 | /* |
903 | char *buffer; | 903 | * Temporarily disabled. |
904 | const struct tomoyo_domain_info * const domain = r->domain; | 904 | * Will be replaced with /sys/kernel/security/tomoyo/audit interface. |
905 | const struct tomoyo_profile *profile = tomoyo_profile(domain->profile); | 905 | */ |
906 | switch (r->mode) { | ||
907 | case TOMOYO_CONFIG_ENFORCING: | ||
908 | if (!profile->enforcing->enforcing_verbose) | ||
909 | return; | ||
910 | break; | ||
911 | case TOMOYO_CONFIG_PERMISSIVE: | ||
912 | if (!profile->permissive->permissive_verbose) | ||
913 | return; | ||
914 | break; | ||
915 | case TOMOYO_CONFIG_LEARNING: | ||
916 | if (!profile->learning->learning_verbose) | ||
917 | return; | ||
918 | break; | ||
919 | } | ||
920 | buffer = kmalloc(4096, GFP_NOFS); | ||
921 | if (!buffer) | ||
922 | return; | ||
923 | va_start(args, fmt); | ||
924 | vsnprintf(buffer, 4095, fmt, args); | ||
925 | va_end(args); | ||
926 | buffer[4095] = '\0'; | ||
927 | printk(KERN_WARNING "%s: Access %s denied for %s\n", | ||
928 | r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer, | ||
929 | tomoyo_last_word(domain->domainname->name)); | ||
930 | kfree(buffer); | ||
931 | } | 906 | } |
932 | 907 | ||
933 | /** | 908 | /** |
@@ -978,13 +953,13 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
978 | if (perm & (1 << i)) | 953 | if (perm & (1 << i)) |
979 | count++; | 954 | count++; |
980 | } | 955 | } |
981 | if (count < tomoyo_profile(domain->profile)->learning-> | 956 | if (count < tomoyo_profile(domain->profile)-> |
982 | learning_max_entry) | 957 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) |
983 | return true; | 958 | return true; |
984 | if (!domain->quota_warned) { | 959 | if (!domain->quota_warned) { |
985 | domain->quota_warned = true; | 960 | domain->quota_warned = true; |
986 | printk(KERN_WARNING "TOMOYO-WARNING: " | 961 | printk(KERN_WARNING "TOMOYO-WARNING: " |
987 | "Domain '%s' has so many ACLs to hold. " | 962 | "Domain '%s' has too many ACLs to hold. " |
988 | "Stopped learning mode.\n", domain->domainname->name); | 963 | "Stopped learning mode.\n", domain->domainname->name); |
989 | } | 964 | } |
990 | return false; | 965 | return false; |