diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 426 | ||||
-rw-r--r-- | security/tomoyo/common.h | 28 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 47 | ||||
-rw-r--r-- | security/tomoyo/file.c | 140 | ||||
-rw-r--r-- | security/tomoyo/mount.c | 24 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 19 |
6 files changed, 564 insertions, 120 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0c6f9a5c37a5..ee46aaa3566f 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -74,6 +74,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, | |||
74 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ | 74 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ |
75 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 75 | static int tomoyo_write_control(struct file *file, const char __user *buffer, |
76 | const int buffer_len); | 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); | ||
77 | 79 | ||
78 | /** | 80 | /** |
79 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | 81 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. |
@@ -1031,7 +1033,7 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) | |||
1031 | * | 1033 | * |
1032 | * Caller holds tomoyo_read_lock(). | 1034 | * Caller holds tomoyo_read_lock(). |
1033 | */ | 1035 | */ |
1034 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | 1036 | static bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) |
1035 | { | 1037 | { |
1036 | unsigned int count = 0; | 1038 | unsigned int count = 0; |
1037 | struct tomoyo_domain_info *domain = r->domain; | 1039 | struct tomoyo_domain_info *domain = r->domain; |
@@ -1531,6 +1533,24 @@ static int tomoyo_delete_domain(char *domainname) | |||
1531 | } | 1533 | } |
1532 | 1534 | ||
1533 | /** | 1535 | /** |
1536 | * tomoyo_write_domain_policy2 - Write domain policy. | ||
1537 | * | ||
1538 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1539 | * | ||
1540 | * Returns 0 on success, negative value otherwise. | ||
1541 | * | ||
1542 | * Caller holds tomoyo_read_lock(). | ||
1543 | */ | ||
1544 | static int tomoyo_write_domain_policy2(char *data, | ||
1545 | struct tomoyo_domain_info *domain, | ||
1546 | const bool is_delete) | ||
1547 | { | ||
1548 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) | ||
1549 | return tomoyo_write_mount_policy(data, domain, is_delete); | ||
1550 | return tomoyo_write_file_policy(data, domain, is_delete); | ||
1551 | } | ||
1552 | |||
1553 | /** | ||
1534 | * tomoyo_write_domain_policy - Write domain policy. | 1554 | * tomoyo_write_domain_policy - Write domain policy. |
1535 | * | 1555 | * |
1536 | * @head: Pointer to "struct tomoyo_io_buffer". | 1556 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1580,9 +1600,7 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1580 | domain->ignore_global_allow_read = !is_delete; | 1600 | domain->ignore_global_allow_read = !is_delete; |
1581 | return 0; | 1601 | return 0; |
1582 | } | 1602 | } |
1583 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) | 1603 | return tomoyo_write_domain_policy2(data, domain, is_delete); |
1584 | return tomoyo_write_mount_policy(data, domain, is_delete); | ||
1585 | return tomoyo_write_file_policy(data, domain, is_delete); | ||
1586 | } | 1604 | } |
1587 | 1605 | ||
1588 | /** | 1606 | /** |
@@ -2186,6 +2204,357 @@ void tomoyo_load_policy(const char *filename) | |||
2186 | } | 2204 | } |
2187 | 2205 | ||
2188 | /** | 2206 | /** |
2207 | * tomoyo_print_header - Get header line of audit log. | ||
2208 | * | ||
2209 | * @r: Pointer to "struct tomoyo_request_info". | ||
2210 | * | ||
2211 | * Returns string representation. | ||
2212 | * | ||
2213 | * This function uses kmalloc(), so caller must kfree() if this function | ||
2214 | * didn't return NULL. | ||
2215 | */ | ||
2216 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | ||
2217 | { | ||
2218 | static const char *tomoyo_mode_4[4] = { | ||
2219 | "disabled", "learning", "permissive", "enforcing" | ||
2220 | }; | ||
2221 | struct timeval tv; | ||
2222 | const pid_t gpid = task_pid_nr(current); | ||
2223 | static const int tomoyo_buffer_len = 4096; | ||
2224 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | ||
2225 | if (!buffer) | ||
2226 | return NULL; | ||
2227 | do_gettimeofday(&tv); | ||
2228 | snprintf(buffer, tomoyo_buffer_len - 1, | ||
2229 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" | ||
2230 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" | ||
2231 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", | ||
2232 | tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid, | ||
2233 | (pid_t) sys_getpid(), (pid_t) sys_getppid(), | ||
2234 | current_uid(), current_gid(), current_euid(), | ||
2235 | current_egid(), current_suid(), current_sgid(), | ||
2236 | current_fsuid(), current_fsgid()); | ||
2237 | return buffer; | ||
2238 | } | ||
2239 | |||
2240 | /** | ||
2241 | * tomoyo_init_audit_log - Allocate buffer for audit logs. | ||
2242 | * | ||
2243 | * @len: Required size. | ||
2244 | * @r: Pointer to "struct tomoyo_request_info". | ||
2245 | * | ||
2246 | * Returns pointer to allocated memory. | ||
2247 | * | ||
2248 | * The @len is updated to add the header lines' size on success. | ||
2249 | * | ||
2250 | * This function uses kzalloc(), so caller must kfree() if this function | ||
2251 | * didn't return NULL. | ||
2252 | */ | ||
2253 | static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) | ||
2254 | { | ||
2255 | char *buf = NULL; | ||
2256 | const char *header; | ||
2257 | const char *domainname; | ||
2258 | if (!r->domain) | ||
2259 | r->domain = tomoyo_domain(); | ||
2260 | domainname = r->domain->domainname->name; | ||
2261 | header = tomoyo_print_header(r); | ||
2262 | if (!header) | ||
2263 | return NULL; | ||
2264 | *len += strlen(domainname) + strlen(header) + 10; | ||
2265 | buf = kzalloc(*len, GFP_NOFS); | ||
2266 | if (buf) | ||
2267 | snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); | ||
2268 | kfree(header); | ||
2269 | return buf; | ||
2270 | } | ||
2271 | |||
2272 | /* Wait queue for tomoyo_query_list. */ | ||
2273 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); | ||
2274 | |||
2275 | /* Lock for manipulating tomoyo_query_list. */ | ||
2276 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | ||
2277 | |||
2278 | /* Structure for query. */ | ||
2279 | struct tomoyo_query_entry { | ||
2280 | struct list_head list; | ||
2281 | char *query; | ||
2282 | int query_len; | ||
2283 | unsigned int serial; | ||
2284 | int timer; | ||
2285 | int answer; | ||
2286 | }; | ||
2287 | |||
2288 | /* The list for "struct tomoyo_query_entry". */ | ||
2289 | static LIST_HEAD(tomoyo_query_list); | ||
2290 | |||
2291 | /* | ||
2292 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query | ||
2293 | * interface. | ||
2294 | */ | ||
2295 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | ||
2296 | |||
2297 | /** | ||
2298 | * tomoyo_supervisor - Ask for the supervisor's decision. | ||
2299 | * | ||
2300 | * @r: Pointer to "struct tomoyo_request_info". | ||
2301 | * @fmt: The printf()'s format string, followed by parameters. | ||
2302 | * | ||
2303 | * Returns 0 if the supervisor decided to permit the access request which | ||
2304 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the | ||
2305 | * supervisor decided to retry the access request which violated the policy in | ||
2306 | * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. | ||
2307 | */ | ||
2308 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | ||
2309 | { | ||
2310 | va_list args; | ||
2311 | int error = -EPERM; | ||
2312 | int pos; | ||
2313 | int len; | ||
2314 | static unsigned int tomoyo_serial; | ||
2315 | struct tomoyo_query_entry *tomoyo_query_entry = NULL; | ||
2316 | bool quota_exceeded = false; | ||
2317 | char *header; | ||
2318 | switch (r->mode) { | ||
2319 | char *buffer; | ||
2320 | case TOMOYO_CONFIG_LEARNING: | ||
2321 | if (!tomoyo_domain_quota_is_ok(r)) | ||
2322 | return 0; | ||
2323 | va_start(args, fmt); | ||
2324 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; | ||
2325 | va_end(args); | ||
2326 | buffer = kmalloc(len, GFP_NOFS); | ||
2327 | if (!buffer) | ||
2328 | return 0; | ||
2329 | va_start(args, fmt); | ||
2330 | vsnprintf(buffer, len - 1, fmt, args); | ||
2331 | va_end(args); | ||
2332 | tomoyo_normalize_line(buffer); | ||
2333 | tomoyo_write_domain_policy2(buffer, r->domain, false); | ||
2334 | kfree(buffer); | ||
2335 | /* fall through */ | ||
2336 | case TOMOYO_CONFIG_PERMISSIVE: | ||
2337 | return 0; | ||
2338 | } | ||
2339 | if (!r->domain) | ||
2340 | r->domain = tomoyo_domain(); | ||
2341 | if (!atomic_read(&tomoyo_query_observers)) | ||
2342 | return -EPERM; | ||
2343 | va_start(args, fmt); | ||
2344 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; | ||
2345 | va_end(args); | ||
2346 | header = tomoyo_init_audit_log(&len, r); | ||
2347 | if (!header) | ||
2348 | goto out; | ||
2349 | tomoyo_query_entry = kzalloc(sizeof(*tomoyo_query_entry), GFP_NOFS); | ||
2350 | if (!tomoyo_query_entry) | ||
2351 | goto out; | ||
2352 | tomoyo_query_entry->query = kzalloc(len, GFP_NOFS); | ||
2353 | if (!tomoyo_query_entry->query) | ||
2354 | goto out; | ||
2355 | len = ksize(tomoyo_query_entry->query); | ||
2356 | INIT_LIST_HEAD(&tomoyo_query_entry->list); | ||
2357 | spin_lock(&tomoyo_query_list_lock); | ||
2358 | if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + | ||
2359 | sizeof(*tomoyo_query_entry) >= tomoyo_quota_for_query) { | ||
2360 | quota_exceeded = true; | ||
2361 | } else { | ||
2362 | tomoyo_query_memory_size += len + sizeof(*tomoyo_query_entry); | ||
2363 | tomoyo_query_entry->serial = tomoyo_serial++; | ||
2364 | } | ||
2365 | spin_unlock(&tomoyo_query_list_lock); | ||
2366 | if (quota_exceeded) | ||
2367 | goto out; | ||
2368 | pos = snprintf(tomoyo_query_entry->query, len - 1, "Q%u-%hu\n%s", | ||
2369 | tomoyo_query_entry->serial, r->retry, header); | ||
2370 | kfree(header); | ||
2371 | header = NULL; | ||
2372 | va_start(args, fmt); | ||
2373 | vsnprintf(tomoyo_query_entry->query + pos, len - 1 - pos, fmt, args); | ||
2374 | tomoyo_query_entry->query_len = strlen(tomoyo_query_entry->query) + 1; | ||
2375 | va_end(args); | ||
2376 | spin_lock(&tomoyo_query_list_lock); | ||
2377 | list_add_tail(&tomoyo_query_entry->list, &tomoyo_query_list); | ||
2378 | spin_unlock(&tomoyo_query_list_lock); | ||
2379 | /* Give 10 seconds for supervisor's opinion. */ | ||
2380 | for (tomoyo_query_entry->timer = 0; | ||
2381 | atomic_read(&tomoyo_query_observers) && tomoyo_query_entry->timer < 100; | ||
2382 | tomoyo_query_entry->timer++) { | ||
2383 | wake_up(&tomoyo_query_wait); | ||
2384 | set_current_state(TASK_INTERRUPTIBLE); | ||
2385 | schedule_timeout(HZ / 10); | ||
2386 | if (tomoyo_query_entry->answer) | ||
2387 | break; | ||
2388 | } | ||
2389 | spin_lock(&tomoyo_query_list_lock); | ||
2390 | list_del(&tomoyo_query_entry->list); | ||
2391 | tomoyo_query_memory_size -= len + sizeof(*tomoyo_query_entry); | ||
2392 | spin_unlock(&tomoyo_query_list_lock); | ||
2393 | switch (tomoyo_query_entry->answer) { | ||
2394 | case 3: /* Asked to retry by administrator. */ | ||
2395 | error = TOMOYO_RETRY_REQUEST; | ||
2396 | r->retry++; | ||
2397 | break; | ||
2398 | case 1: | ||
2399 | /* Granted by administrator. */ | ||
2400 | error = 0; | ||
2401 | break; | ||
2402 | case 0: | ||
2403 | /* Timed out. */ | ||
2404 | break; | ||
2405 | default: | ||
2406 | /* Rejected by administrator. */ | ||
2407 | break; | ||
2408 | } | ||
2409 | out: | ||
2410 | if (tomoyo_query_entry) | ||
2411 | kfree(tomoyo_query_entry->query); | ||
2412 | kfree(tomoyo_query_entry); | ||
2413 | kfree(header); | ||
2414 | return error; | ||
2415 | } | ||
2416 | |||
2417 | /** | ||
2418 | * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. | ||
2419 | * | ||
2420 | * @file: Pointer to "struct file". | ||
2421 | * @wait: Pointer to "poll_table". | ||
2422 | * | ||
2423 | * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. | ||
2424 | * | ||
2425 | * Waits for access requests which violated policy in enforcing mode. | ||
2426 | */ | ||
2427 | static int tomoyo_poll_query(struct file *file, poll_table *wait) | ||
2428 | { | ||
2429 | struct list_head *tmp; | ||
2430 | bool found = false; | ||
2431 | u8 i; | ||
2432 | for (i = 0; i < 2; i++) { | ||
2433 | spin_lock(&tomoyo_query_list_lock); | ||
2434 | list_for_each(tmp, &tomoyo_query_list) { | ||
2435 | struct tomoyo_query_entry *ptr | ||
2436 | = list_entry(tmp, struct tomoyo_query_entry, | ||
2437 | list); | ||
2438 | if (ptr->answer) | ||
2439 | continue; | ||
2440 | found = true; | ||
2441 | break; | ||
2442 | } | ||
2443 | spin_unlock(&tomoyo_query_list_lock); | ||
2444 | if (found) | ||
2445 | return POLLIN | POLLRDNORM; | ||
2446 | if (i) | ||
2447 | break; | ||
2448 | poll_wait(file, &tomoyo_query_wait, wait); | ||
2449 | } | ||
2450 | return 0; | ||
2451 | } | ||
2452 | |||
2453 | /** | ||
2454 | * tomoyo_read_query - Read access requests which violated policy in enforcing mode. | ||
2455 | * | ||
2456 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2457 | * | ||
2458 | * Returns 0. | ||
2459 | */ | ||
2460 | static int tomoyo_read_query(struct tomoyo_io_buffer *head) | ||
2461 | { | ||
2462 | struct list_head *tmp; | ||
2463 | int pos = 0; | ||
2464 | int len = 0; | ||
2465 | char *buf; | ||
2466 | if (head->read_avail) | ||
2467 | return 0; | ||
2468 | if (head->read_buf) { | ||
2469 | kfree(head->read_buf); | ||
2470 | head->read_buf = NULL; | ||
2471 | head->readbuf_size = 0; | ||
2472 | } | ||
2473 | spin_lock(&tomoyo_query_list_lock); | ||
2474 | list_for_each(tmp, &tomoyo_query_list) { | ||
2475 | struct tomoyo_query_entry *ptr | ||
2476 | = list_entry(tmp, struct tomoyo_query_entry, list); | ||
2477 | if (ptr->answer) | ||
2478 | continue; | ||
2479 | if (pos++ != head->read_step) | ||
2480 | continue; | ||
2481 | len = ptr->query_len; | ||
2482 | break; | ||
2483 | } | ||
2484 | spin_unlock(&tomoyo_query_list_lock); | ||
2485 | if (!len) { | ||
2486 | head->read_step = 0; | ||
2487 | return 0; | ||
2488 | } | ||
2489 | buf = kzalloc(len, GFP_NOFS); | ||
2490 | if (!buf) | ||
2491 | return 0; | ||
2492 | pos = 0; | ||
2493 | spin_lock(&tomoyo_query_list_lock); | ||
2494 | list_for_each(tmp, &tomoyo_query_list) { | ||
2495 | struct tomoyo_query_entry *ptr | ||
2496 | = list_entry(tmp, struct tomoyo_query_entry, list); | ||
2497 | if (ptr->answer) | ||
2498 | continue; | ||
2499 | if (pos++ != head->read_step) | ||
2500 | continue; | ||
2501 | /* | ||
2502 | * Some query can be skipped because tomoyo_query_list | ||
2503 | * can change, but I don't care. | ||
2504 | */ | ||
2505 | if (len == ptr->query_len) | ||
2506 | memmove(buf, ptr->query, len); | ||
2507 | break; | ||
2508 | } | ||
2509 | spin_unlock(&tomoyo_query_list_lock); | ||
2510 | if (buf[0]) { | ||
2511 | head->read_avail = len; | ||
2512 | head->readbuf_size = head->read_avail; | ||
2513 | head->read_buf = buf; | ||
2514 | head->read_step++; | ||
2515 | } else { | ||
2516 | kfree(buf); | ||
2517 | } | ||
2518 | return 0; | ||
2519 | } | ||
2520 | |||
2521 | /** | ||
2522 | * tomoyo_write_answer - Write the supervisor's decision. | ||
2523 | * | ||
2524 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2525 | * | ||
2526 | * Returns 0 on success, -EINVAL otherwise. | ||
2527 | */ | ||
2528 | static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | ||
2529 | { | ||
2530 | char *data = head->write_buf; | ||
2531 | struct list_head *tmp; | ||
2532 | unsigned int serial; | ||
2533 | unsigned int answer; | ||
2534 | spin_lock(&tomoyo_query_list_lock); | ||
2535 | list_for_each(tmp, &tomoyo_query_list) { | ||
2536 | struct tomoyo_query_entry *ptr | ||
2537 | = list_entry(tmp, struct tomoyo_query_entry, list); | ||
2538 | ptr->timer = 0; | ||
2539 | } | ||
2540 | spin_unlock(&tomoyo_query_list_lock); | ||
2541 | if (sscanf(data, "A%u=%u", &serial, &answer) != 2) | ||
2542 | return -EINVAL; | ||
2543 | spin_lock(&tomoyo_query_list_lock); | ||
2544 | list_for_each(tmp, &tomoyo_query_list) { | ||
2545 | struct tomoyo_query_entry *ptr | ||
2546 | = list_entry(tmp, struct tomoyo_query_entry, list); | ||
2547 | if (ptr->serial != serial) | ||
2548 | continue; | ||
2549 | if (!ptr->answer) | ||
2550 | ptr->answer = answer; | ||
2551 | break; | ||
2552 | } | ||
2553 | spin_unlock(&tomoyo_query_list_lock); | ||
2554 | return 0; | ||
2555 | } | ||
2556 | |||
2557 | /** | ||
2189 | * tomoyo_read_version: Get version. | 2558 | * tomoyo_read_version: Get version. |
2190 | * | 2559 | * |
2191 | * @head: Pointer to "struct tomoyo_io_buffer". | 2560 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -2239,6 +2608,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2239 | if (!head) | 2608 | if (!head) |
2240 | return -ENOMEM; | 2609 | return -ENOMEM; |
2241 | mutex_init(&head->io_sem); | 2610 | mutex_init(&head->io_sem); |
2611 | head->type = type; | ||
2242 | switch (type) { | 2612 | switch (type) { |
2243 | case TOMOYO_DOMAINPOLICY: | 2613 | case TOMOYO_DOMAINPOLICY: |
2244 | /* /sys/kernel/security/tomoyo/domain_policy */ | 2614 | /* /sys/kernel/security/tomoyo/domain_policy */ |
@@ -2280,6 +2650,11 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2280 | head->write = tomoyo_write_profile; | 2650 | head->write = tomoyo_write_profile; |
2281 | head->read = tomoyo_read_profile; | 2651 | head->read = tomoyo_read_profile; |
2282 | break; | 2652 | break; |
2653 | case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ | ||
2654 | head->poll = tomoyo_poll_query; | ||
2655 | head->write = tomoyo_write_answer; | ||
2656 | head->read = tomoyo_read_query; | ||
2657 | break; | ||
2283 | case TOMOYO_MANAGER: | 2658 | case TOMOYO_MANAGER: |
2284 | /* /sys/kernel/security/tomoyo/manager */ | 2659 | /* /sys/kernel/security/tomoyo/manager */ |
2285 | head->write = tomoyo_write_manager_policy; | 2660 | head->write = tomoyo_write_manager_policy; |
@@ -2292,7 +2667,9 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2292 | * for reading. | 2667 | * for reading. |
2293 | */ | 2668 | */ |
2294 | head->read = NULL; | 2669 | head->read = NULL; |
2295 | } else { | 2670 | head->poll = NULL; |
2671 | } else if (!head->poll) { | ||
2672 | /* Don't allocate read_buf for poll() access. */ | ||
2296 | if (!head->readbuf_size) | 2673 | if (!head->readbuf_size) |
2297 | head->readbuf_size = 4096 * 2; | 2674 | head->readbuf_size = 4096 * 2; |
2298 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); | 2675 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); |
@@ -2316,7 +2693,8 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2316 | return -ENOMEM; | 2693 | return -ENOMEM; |
2317 | } | 2694 | } |
2318 | } | 2695 | } |
2319 | head->reader_idx = tomoyo_read_lock(); | 2696 | if (type != TOMOYO_QUERY) |
2697 | head->reader_idx = tomoyo_read_lock(); | ||
2320 | file->private_data = head; | 2698 | file->private_data = head; |
2321 | /* | 2699 | /* |
2322 | * Call the handler now if the file is | 2700 | * Call the handler now if the file is |
@@ -2327,10 +2705,35 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2327 | */ | 2705 | */ |
2328 | if (type == TOMOYO_SELFDOMAIN) | 2706 | if (type == TOMOYO_SELFDOMAIN) |
2329 | tomoyo_read_control(file, NULL, 0); | 2707 | tomoyo_read_control(file, NULL, 0); |
2708 | /* | ||
2709 | * If the file is /sys/kernel/security/tomoyo/query , increment the | ||
2710 | * observer counter. | ||
2711 | * The obserber counter is used by tomoyo_supervisor() to see if | ||
2712 | * there is some process monitoring /sys/kernel/security/tomoyo/query. | ||
2713 | */ | ||
2714 | else if (type == TOMOYO_QUERY) | ||
2715 | atomic_inc(&tomoyo_query_observers); | ||
2330 | return 0; | 2716 | return 0; |
2331 | } | 2717 | } |
2332 | 2718 | ||
2333 | /** | 2719 | /** |
2720 | * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. | ||
2721 | * | ||
2722 | * @file: Pointer to "struct file". | ||
2723 | * @wait: Pointer to "poll_table". | ||
2724 | * | ||
2725 | * Waits for read readiness. | ||
2726 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . | ||
2727 | */ | ||
2728 | int tomoyo_poll_control(struct file *file, poll_table *wait) | ||
2729 | { | ||
2730 | struct tomoyo_io_buffer *head = file->private_data; | ||
2731 | if (!head->poll) | ||
2732 | return -ENOSYS; | ||
2733 | return head->poll(file, wait); | ||
2734 | } | ||
2735 | |||
2736 | /** | ||
2334 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 2737 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
2335 | * | 2738 | * |
2336 | * @file: Pointer to "struct file". | 2739 | * @file: Pointer to "struct file". |
@@ -2443,7 +2846,14 @@ static int tomoyo_close_control(struct file *file) | |||
2443 | struct tomoyo_io_buffer *head = file->private_data; | 2846 | struct tomoyo_io_buffer *head = file->private_data; |
2444 | const bool is_write = !!head->write_buf; | 2847 | const bool is_write = !!head->write_buf; |
2445 | 2848 | ||
2446 | tomoyo_read_unlock(head->reader_idx); | 2849 | /* |
2850 | * If the file is /sys/kernel/security/tomoyo/query , decrement the | ||
2851 | * observer counter. | ||
2852 | */ | ||
2853 | if (head->type == TOMOYO_QUERY) | ||
2854 | atomic_dec(&tomoyo_query_observers); | ||
2855 | else | ||
2856 | tomoyo_read_unlock(head->reader_idx); | ||
2447 | /* Release memory used for policy I/O. */ | 2857 | /* Release memory used for policy I/O. */ |
2448 | kfree(head->read_buf); | 2858 | kfree(head->read_buf); |
2449 | head->read_buf = NULL; | 2859 | head->read_buf = NULL; |
@@ -2562,6 +2972,8 @@ static int __init tomoyo_initerface_init(void) | |||
2562 | return 0; | 2972 | return 0; |
2563 | 2973 | ||
2564 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | 2974 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); |
2975 | tomoyo_create_entry("query", 0600, tomoyo_dir, | ||
2976 | TOMOYO_QUERY); | ||
2565 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, | 2977 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, |
2566 | TOMOYO_DOMAINPOLICY); | 2978 | TOMOYO_DOMAINPOLICY); |
2567 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | 2979 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 3d819b139165..dc5f98f52f61 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/cred.h> | 22 | #include <linux/cred.h> |
23 | #include <linux/poll.h> | ||
23 | struct linux_binprm; | 24 | struct linux_binprm; |
24 | 25 | ||
25 | /********** Constants definitions. **********/ | 26 | /********** Constants definitions. **********/ |
@@ -156,9 +157,12 @@ enum tomoyo_securityfs_interface_index { | |||
156 | TOMOYO_SELFDOMAIN, | 157 | TOMOYO_SELFDOMAIN, |
157 | TOMOYO_VERSION, | 158 | TOMOYO_VERSION, |
158 | TOMOYO_PROFILE, | 159 | TOMOYO_PROFILE, |
160 | TOMOYO_QUERY, | ||
159 | TOMOYO_MANAGER | 161 | TOMOYO_MANAGER |
160 | }; | 162 | }; |
161 | 163 | ||
164 | #define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */ | ||
165 | |||
162 | /********** Structure definitions. **********/ | 166 | /********** Structure definitions. **********/ |
163 | 167 | ||
164 | /* | 168 | /* |
@@ -176,10 +180,14 @@ struct tomoyo_page_buffer { | |||
176 | * tomoyo_request_info is a structure which is used for holding | 180 | * tomoyo_request_info is a structure which is used for holding |
177 | * | 181 | * |
178 | * (1) Domain information of current process. | 182 | * (1) Domain information of current process. |
179 | * (2) Access control mode of the profile. | 183 | * (2) How many retries are made for this request. |
184 | * (3) Profile number used for this request. | ||
185 | * (4) Access control mode of the profile. | ||
180 | */ | 186 | */ |
181 | struct tomoyo_request_info { | 187 | struct tomoyo_request_info { |
182 | struct tomoyo_domain_info *domain; | 188 | struct tomoyo_domain_info *domain; |
189 | u8 retry; | ||
190 | u8 profile; | ||
183 | u8 mode; /* One of tomoyo_mode_index . */ | 191 | u8 mode; /* One of tomoyo_mode_index . */ |
184 | }; | 192 | }; |
185 | 193 | ||
@@ -484,6 +492,7 @@ struct tomoyo_mount_acl { | |||
484 | struct tomoyo_io_buffer { | 492 | struct tomoyo_io_buffer { |
485 | int (*read) (struct tomoyo_io_buffer *); | 493 | int (*read) (struct tomoyo_io_buffer *); |
486 | int (*write) (struct tomoyo_io_buffer *); | 494 | int (*write) (struct tomoyo_io_buffer *); |
495 | int (*poll) (struct file *file, poll_table *wait); | ||
487 | /* Exclusive lock for this structure. */ | 496 | /* Exclusive lock for this structure. */ |
488 | struct mutex io_sem; | 497 | struct mutex io_sem; |
489 | /* Index returned by tomoyo_read_lock(). */ | 498 | /* Index returned by tomoyo_read_lock(). */ |
@@ -514,6 +523,8 @@ struct tomoyo_io_buffer { | |||
514 | int write_avail; | 523 | int write_avail; |
515 | /* Size of write buffer. */ | 524 | /* Size of write buffer. */ |
516 | int writebuf_size; | 525 | int writebuf_size; |
526 | /* Type of this interface. */ | ||
527 | u8 type; | ||
517 | }; | 528 | }; |
518 | 529 | ||
519 | /* | 530 | /* |
@@ -659,14 +670,15 @@ struct tomoyo_policy_manager_entry { | |||
659 | 670 | ||
660 | /********** Function prototypes. **********/ | 671 | /********** Function prototypes. **********/ |
661 | 672 | ||
673 | extern asmlinkage long sys_getpid(void); | ||
674 | extern asmlinkage long sys_getppid(void); | ||
675 | |||
662 | /* Check whether the given name matches the given name_union. */ | 676 | /* Check whether the given name matches the given name_union. */ |
663 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 677 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
664 | const struct tomoyo_name_union *ptr); | 678 | const struct tomoyo_name_union *ptr); |
665 | /* Check whether the given number matches the given number_union. */ | 679 | /* Check whether the given number matches the given number_union. */ |
666 | bool tomoyo_compare_number_union(const unsigned long value, | 680 | bool tomoyo_compare_number_union(const unsigned long value, |
667 | const struct tomoyo_number_union *ptr); | 681 | const struct tomoyo_number_union *ptr); |
668 | /* Check whether the domain has too many ACL entries to hold. */ | ||
669 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); | ||
670 | /* Transactional sprintf() for policy dump. */ | 682 | /* Transactional sprintf() for policy dump. */ |
671 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 683 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
672 | __attribute__ ((format(printf, 2, 3))); | 684 | __attribute__ ((format(printf, 2, 3))); |
@@ -763,6 +775,8 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); | |||
763 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); | 775 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); |
764 | /* Create "path_group" entry in exception policy. */ | 776 | /* Create "path_group" entry in exception policy. */ |
765 | int tomoyo_write_path_group_policy(char *data, const bool is_delete); | 777 | int tomoyo_write_path_group_policy(char *data, const bool is_delete); |
778 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | ||
779 | __attribute__ ((format(printf, 2, 3))); | ||
766 | /* Create "number_group" entry in exception policy. */ | 780 | /* Create "number_group" entry in exception policy. */ |
767 | int tomoyo_write_number_group_policy(char *data, const bool is_delete); | 781 | int tomoyo_write_number_group_policy(char *data, const bool is_delete); |
768 | /* Find a domain by the given name. */ | 782 | /* Find a domain by the given name. */ |
@@ -771,9 +785,6 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | |||
771 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 785 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
772 | domainname, | 786 | domainname, |
773 | const u8 profile); | 787 | const u8 profile); |
774 | /* Get patterned pathname. */ | ||
775 | const struct tomoyo_path_info * | ||
776 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename); | ||
777 | /* Allocate memory for "struct tomoyo_path_group". */ | 788 | /* Allocate memory for "struct tomoyo_path_group". */ |
778 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); | 789 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); |
779 | struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name); | 790 | struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name); |
@@ -807,6 +818,8 @@ char *tomoyo_realpath(const char *pathname); | |||
807 | char *tomoyo_realpath_nofollow(const char *pathname); | 818 | char *tomoyo_realpath_nofollow(const char *pathname); |
808 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ | 819 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ |
809 | char *tomoyo_realpath_from_path(struct path *path); | 820 | char *tomoyo_realpath_from_path(struct path *path); |
821 | /* Get patterned pathname. */ | ||
822 | const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename); | ||
810 | 823 | ||
811 | /* Check memory quota. */ | 824 | /* Check memory quota. */ |
812 | bool tomoyo_memory_ok(void *ptr); | 825 | bool tomoyo_memory_ok(void *ptr); |
@@ -878,6 +891,9 @@ extern bool tomoyo_policy_loaded; | |||
878 | /* The kernel's domain. */ | 891 | /* The kernel's domain. */ |
879 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 892 | extern struct tomoyo_domain_info tomoyo_kernel_domain; |
880 | 893 | ||
894 | extern unsigned int tomoyo_quota_for_query; | ||
895 | extern unsigned int tomoyo_query_memory_size; | ||
896 | |||
881 | /********** Inlined functions. **********/ | 897 | /********** Inlined functions. **********/ |
882 | 898 | ||
883 | static inline int tomoyo_read_lock(void) | 899 | static inline int tomoyo_read_lock(void) |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index afdf26128bfe..7e242d27da5a 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -678,6 +678,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
678 | */ | 678 | */ |
679 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 679 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
680 | { | 680 | { |
681 | struct tomoyo_request_info r; | ||
681 | /* | 682 | /* |
682 | * This function assumes that the size of buffer returned by | 683 | * This function assumes that the size of buffer returned by |
683 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 684 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
@@ -693,11 +694,12 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
693 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); | 694 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); |
694 | const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); | 695 | const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); |
695 | int retval = -ENOMEM; | 696 | int retval = -ENOMEM; |
696 | struct tomoyo_path_info r; /* real name */ | 697 | struct tomoyo_path_info rn; /* real name */ |
697 | struct tomoyo_path_info s; /* symlink name */ | 698 | struct tomoyo_path_info sn; /* symlink name */ |
698 | struct tomoyo_path_info l; /* last name */ | 699 | struct tomoyo_path_info ln; /* last name */ |
699 | static bool initialized; | 700 | static bool initialized; |
700 | 701 | ||
702 | tomoyo_init_request_info(&r, NULL); | ||
701 | if (!tmp) | 703 | if (!tmp) |
702 | goto out; | 704 | goto out; |
703 | 705 | ||
@@ -713,6 +715,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
713 | initialized = true; | 715 | initialized = true; |
714 | } | 716 | } |
715 | 717 | ||
718 | retry: | ||
716 | /* Get tomoyo_realpath of program. */ | 719 | /* Get tomoyo_realpath of program. */ |
717 | retval = -ENOENT; | 720 | retval = -ENOENT; |
718 | /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ | 721 | /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ |
@@ -724,37 +727,39 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
724 | if (!symlink_program_name) | 727 | if (!symlink_program_name) |
725 | goto out; | 728 | goto out; |
726 | 729 | ||
727 | r.name = real_program_name; | 730 | rn.name = real_program_name; |
728 | tomoyo_fill_path_info(&r); | 731 | tomoyo_fill_path_info(&rn); |
729 | s.name = symlink_program_name; | 732 | sn.name = symlink_program_name; |
730 | tomoyo_fill_path_info(&s); | 733 | tomoyo_fill_path_info(&sn); |
731 | l.name = tomoyo_get_last_name(old_domain); | 734 | ln.name = tomoyo_get_last_name(old_domain); |
732 | tomoyo_fill_path_info(&l); | 735 | tomoyo_fill_path_info(&ln); |
733 | 736 | ||
734 | /* Check 'alias' directive. */ | 737 | /* Check 'alias' directive. */ |
735 | if (tomoyo_pathcmp(&r, &s)) { | 738 | if (tomoyo_pathcmp(&rn, &sn)) { |
736 | struct tomoyo_alias_entry *ptr; | 739 | struct tomoyo_alias_entry *ptr; |
737 | /* Is this program allowed to be called via symbolic links? */ | 740 | /* Is this program allowed to be called via symbolic links? */ |
738 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | 741 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
739 | if (ptr->is_deleted || | 742 | if (ptr->is_deleted || |
740 | tomoyo_pathcmp(&r, ptr->original_name) || | 743 | tomoyo_pathcmp(&rn, ptr->original_name) || |
741 | tomoyo_pathcmp(&s, ptr->aliased_name)) | 744 | tomoyo_pathcmp(&sn, ptr->aliased_name)) |
742 | continue; | 745 | continue; |
743 | memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); | 746 | memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); |
744 | strncpy(real_program_name, ptr->aliased_name->name, | 747 | strncpy(real_program_name, ptr->aliased_name->name, |
745 | TOMOYO_MAX_PATHNAME_LEN - 1); | 748 | TOMOYO_MAX_PATHNAME_LEN - 1); |
746 | tomoyo_fill_path_info(&r); | 749 | tomoyo_fill_path_info(&rn); |
747 | break; | 750 | break; |
748 | } | 751 | } |
749 | } | 752 | } |
750 | 753 | ||
751 | /* Check execute permission. */ | 754 | /* Check execute permission. */ |
752 | retval = tomoyo_check_exec_perm(old_domain, &r); | 755 | retval = tomoyo_check_exec_perm(old_domain, &rn); |
756 | if (retval == TOMOYO_RETRY_REQUEST) | ||
757 | goto retry; | ||
753 | if (retval < 0) | 758 | if (retval < 0) |
754 | goto out; | 759 | goto out; |
755 | 760 | ||
756 | new_domain_name = tmp->buffer; | 761 | new_domain_name = tmp->buffer; |
757 | if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) { | 762 | if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) { |
758 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 763 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
759 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, | 764 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, |
760 | TOMOYO_ROOT_NAME " " "%s", real_program_name); | 765 | TOMOYO_ROOT_NAME " " "%s", real_program_name); |
@@ -766,7 +771,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
766 | * initializers because they might start before /sbin/init. | 771 | * initializers because they might start before /sbin/init. |
767 | */ | 772 | */ |
768 | domain = old_domain; | 773 | domain = old_domain; |
769 | } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) { | 774 | } else if (tomoyo_is_domain_keeper(old_domain->domainname, &rn, &ln)) { |
770 | /* Keep current domain. */ | 775 | /* Keep current domain. */ |
771 | domain = old_domain; | 776 | domain = old_domain; |
772 | } else { | 777 | } else { |
@@ -779,8 +784,14 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
779 | domain = tomoyo_find_domain(new_domain_name); | 784 | domain = tomoyo_find_domain(new_domain_name); |
780 | if (domain) | 785 | if (domain) |
781 | goto done; | 786 | goto done; |
782 | if (is_enforce) | 787 | if (is_enforce) { |
783 | goto done; | 788 | int error = tomoyo_supervisor(&r, "# wants to create domain\n" |
789 | "%s\n", new_domain_name); | ||
790 | if (error == TOMOYO_RETRY_REQUEST) | ||
791 | goto retry; | ||
792 | if (error < 0) | ||
793 | goto done; | ||
794 | } | ||
784 | domain = tomoyo_find_or_assign_new_domain(new_domain_name, | 795 | domain = tomoyo_find_or_assign_new_domain(new_domain_name, |
785 | old_domain->profile); | 796 | old_domain->profile); |
786 | done: | 797 | done: |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index ae32cab8ec7e..c629cb4e2c66 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -478,7 +478,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
478 | } | 478 | } |
479 | 479 | ||
480 | /** | 480 | /** |
481 | * tomoyo_get_file_pattern - Get patterned pathname. | 481 | * tomoyo_file_pattern - Get patterned pathname. |
482 | * | 482 | * |
483 | * @filename: The filename to find patterned pathname. | 483 | * @filename: The filename to find patterned pathname. |
484 | * | 484 | * |
@@ -486,8 +486,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
486 | * | 486 | * |
487 | * Caller holds tomoyo_read_lock(). | 487 | * Caller holds tomoyo_read_lock(). |
488 | */ | 488 | */ |
489 | const struct tomoyo_path_info * | 489 | const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) |
490 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | ||
491 | { | 490 | { |
492 | struct tomoyo_pattern_entry *ptr; | 491 | struct tomoyo_pattern_entry *ptr; |
493 | const struct tomoyo_path_info *pattern = NULL; | 492 | const struct tomoyo_path_info *pattern = NULL; |
@@ -507,7 +506,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
507 | } | 506 | } |
508 | if (pattern) | 507 | if (pattern) |
509 | filename = pattern; | 508 | filename = pattern; |
510 | return filename; | 509 | return filename->name; |
511 | } | 510 | } |
512 | 511 | ||
513 | /** | 512 | /** |
@@ -812,23 +811,25 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r, | |||
812 | perm = 1 << TOMOYO_TYPE_EXECUTE; | 811 | perm = 1 << TOMOYO_TYPE_EXECUTE; |
813 | } else | 812 | } else |
814 | BUG(); | 813 | BUG(); |
815 | error = tomoyo_path_acl(r, filename, perm, mode != 1); | 814 | do { |
816 | if (error && mode == 4 && !r->domain->ignore_global_allow_read | 815 | error = tomoyo_path_acl(r, filename, perm, mode != 1); |
817 | && tomoyo_is_globally_readable_file(filename)) | 816 | if (error && mode == 4 && !r->domain->ignore_global_allow_read |
817 | && tomoyo_is_globally_readable_file(filename)) | ||
818 | error = 0; | ||
819 | if (!error) | ||
820 | break; | ||
821 | tomoyo_warn_log(r, "%s %s", msg, filename->name); | ||
822 | error = tomoyo_supervisor(r, "allow_%s %s\n", msg, | ||
823 | mode == 1 ? filename->name : | ||
824 | tomoyo_file_pattern(filename)); | ||
825 | /* | ||
826 | * Do not retry for execute request, for alias may have | ||
827 | * changed. | ||
828 | */ | ||
829 | } while (error == TOMOYO_RETRY_REQUEST && mode != 1); | ||
830 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
818 | error = 0; | 831 | error = 0; |
819 | if (!error) | 832 | return error; |
820 | return 0; | ||
821 | tomoyo_warn_log(r, "%s %s", msg, filename->name); | ||
822 | if (r->mode == TOMOYO_CONFIG_ENFORCING) | ||
823 | return error; | ||
824 | if (tomoyo_domain_quota_is_ok(r)) { | ||
825 | /* Don't use patterns for execute permission. */ | ||
826 | const struct tomoyo_path_info *patterned_file = (mode != 1) ? | ||
827 | tomoyo_get_file_pattern(filename) : filename; | ||
828 | tomoyo_update_file_acl(mode, patterned_file->name, r->domain, | ||
829 | false); | ||
830 | } | ||
831 | return 0; | ||
832 | } | 833 | } |
833 | 834 | ||
834 | /** | 835 | /** |
@@ -1123,21 +1124,21 @@ static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type, | |||
1123 | static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | 1124 | static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, |
1124 | const struct tomoyo_path_info *filename) | 1125 | const struct tomoyo_path_info *filename) |
1125 | { | 1126 | { |
1127 | const char *msg; | ||
1126 | int error; | 1128 | int error; |
1127 | 1129 | ||
1128 | next: | 1130 | next: |
1129 | error = tomoyo_path_acl(r, filename, 1 << operation, 1); | 1131 | do { |
1130 | if (!error) | 1132 | error = tomoyo_path_acl(r, filename, 1 << operation, 1); |
1131 | goto ok; | 1133 | if (!error) |
1132 | tomoyo_warn_log(r, "%s %s", tomoyo_path2keyword(operation), | 1134 | break; |
1133 | filename->name); | 1135 | msg = tomoyo_path2keyword(operation); |
1134 | if (tomoyo_domain_quota_is_ok(r)) { | 1136 | tomoyo_warn_log(r, "%s %s", msg, filename->name); |
1135 | const char *name = tomoyo_get_file_pattern(filename)->name; | 1137 | error = tomoyo_supervisor(r, "allow_%s %s\n", msg, |
1136 | tomoyo_update_path_acl(operation, name, r->domain, false); | 1138 | tomoyo_file_pattern(filename)); |
1137 | } | 1139 | } while (error == TOMOYO_RETRY_REQUEST); |
1138 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | 1140 | if (r->mode != TOMOYO_CONFIG_ENFORCING) |
1139 | error = 0; | 1141 | error = 0; |
1140 | ok: | ||
1141 | /* | 1142 | /* |
1142 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, | 1143 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, |
1143 | * we need to check "allow_rewrite" permission if the filename is | 1144 | * we need to check "allow_rewrite" permission if the filename is |
@@ -1267,6 +1268,7 @@ static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, | |||
1267 | char buffer[64]; | 1268 | char buffer[64]; |
1268 | int error; | 1269 | int error; |
1269 | u8 radix; | 1270 | u8 radix; |
1271 | const char *msg; | ||
1270 | 1272 | ||
1271 | if (!filename) | 1273 | if (!filename) |
1272 | return 0; | 1274 | return 0; |
@@ -1286,15 +1288,16 @@ static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, | |||
1286 | break; | 1288 | break; |
1287 | } | 1289 | } |
1288 | tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); | 1290 | tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); |
1289 | error = tomoyo_path_number_acl(r, type, filename, number); | 1291 | do { |
1290 | if (!error) | 1292 | error = tomoyo_path_number_acl(r, type, filename, number); |
1291 | return 0; | 1293 | if (!error) |
1292 | tomoyo_warn_log(r, "%s %s %s", tomoyo_path_number2keyword(type), | 1294 | break; |
1293 | filename->name, buffer); | 1295 | msg = tomoyo_path_number2keyword(type); |
1294 | if (tomoyo_domain_quota_is_ok(r)) | 1296 | tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer); |
1295 | tomoyo_update_path_number_acl(type, | 1297 | error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg, |
1296 | tomoyo_get_file_pattern(filename) | 1298 | tomoyo_file_pattern(filename), |
1297 | ->name, buffer, r->domain, false); | 1299 | buffer); |
1300 | } while (error == TOMOYO_RETRY_REQUEST); | ||
1298 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | 1301 | if (r->mode != TOMOYO_CONFIG_ENFORCING) |
1299 | error = 0; | 1302 | error = 0; |
1300 | return error; | 1303 | return error; |
@@ -1484,32 +1487,23 @@ static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, | |||
1484 | const unsigned int dev) | 1487 | const unsigned int dev) |
1485 | { | 1488 | { |
1486 | int error; | 1489 | int error; |
1490 | const char *msg; | ||
1487 | const unsigned int major = MAJOR(dev); | 1491 | const unsigned int major = MAJOR(dev); |
1488 | const unsigned int minor = MINOR(dev); | 1492 | const unsigned int minor = MINOR(dev); |
1489 | 1493 | ||
1490 | error = tomoyo_path_number3_acl(r, filename, 1 << operation, mode, | 1494 | do { |
1491 | major, minor); | 1495 | error = tomoyo_path_number3_acl(r, filename, 1 << operation, |
1492 | if (!error) | 1496 | mode, major, minor); |
1493 | return 0; | 1497 | if (!error) |
1494 | tomoyo_warn_log(r, "%s %s 0%o %u %u", | 1498 | break; |
1495 | tomoyo_path_number32keyword(operation), | 1499 | msg = tomoyo_path_number32keyword(operation); |
1496 | filename->name, mode, major, minor); | 1500 | tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name, |
1497 | if (tomoyo_domain_quota_is_ok(r)) { | 1501 | mode, major, minor); |
1498 | char mode_buf[64]; | 1502 | error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg, |
1499 | char major_buf[64]; | 1503 | tomoyo_file_pattern(filename), mode, |
1500 | char minor_buf[64]; | 1504 | major, minor); |
1501 | memset(mode_buf, 0, sizeof(mode_buf)); | 1505 | } while (error == TOMOYO_RETRY_REQUEST); |
1502 | memset(major_buf, 0, sizeof(major_buf)); | 1506 | if (r->mode != TOMOYO_CONFIG_ENFORCING) |
1503 | memset(minor_buf, 0, sizeof(minor_buf)); | ||
1504 | snprintf(mode_buf, sizeof(mode_buf) - 1, "0%o", mode); | ||
1505 | snprintf(major_buf, sizeof(major_buf) - 1, "%u", major); | ||
1506 | snprintf(minor_buf, sizeof(minor_buf) - 1, "%u", minor); | ||
1507 | tomoyo_update_path_number3_acl(operation, | ||
1508 | tomoyo_get_file_pattern(filename) | ||
1509 | ->name, mode_buf, major_buf, | ||
1510 | minor_buf, r->domain, false); | ||
1511 | } | ||
1512 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
1513 | error = 0; | 1507 | error = 0; |
1514 | return error; | 1508 | return error; |
1515 | } | 1509 | } |
@@ -1562,6 +1556,7 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1562 | struct path *path2) | 1556 | struct path *path2) |
1563 | { | 1557 | { |
1564 | int error = -ENOMEM; | 1558 | int error = -ENOMEM; |
1559 | const char *msg; | ||
1565 | struct tomoyo_path_info *buf1; | 1560 | struct tomoyo_path_info *buf1; |
1566 | struct tomoyo_path_info *buf2; | 1561 | struct tomoyo_path_info *buf2; |
1567 | struct tomoyo_request_info r; | 1562 | struct tomoyo_request_info r; |
@@ -1591,17 +1586,16 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1591 | } | 1586 | } |
1592 | } | 1587 | } |
1593 | } | 1588 | } |
1594 | error = tomoyo_path2_acl(&r, operation, buf1, buf2); | 1589 | do { |
1595 | if (!error) | 1590 | error = tomoyo_path2_acl(&r, operation, buf1, buf2); |
1596 | goto out; | 1591 | if (!error) |
1597 | tomoyo_warn_log(&r, "%s %s %s", tomoyo_path22keyword(operation), | 1592 | break; |
1598 | buf1->name, buf2->name); | 1593 | msg = tomoyo_path22keyword(operation); |
1599 | if (tomoyo_domain_quota_is_ok(&r)) { | 1594 | tomoyo_warn_log(&r, "%s %s %s", msg, buf1->name, buf2->name); |
1600 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; | 1595 | error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, |
1601 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; | 1596 | tomoyo_file_pattern(buf1), |
1602 | tomoyo_update_path2_acl(operation, name1, name2, r.domain, | 1597 | tomoyo_file_pattern(buf2)); |
1603 | false); | 1598 | } while (error == TOMOYO_RETRY_REQUEST); |
1604 | } | ||
1605 | out: | 1599 | out: |
1606 | kfree(buf1); | 1600 | kfree(buf1); |
1607 | kfree(buf2); | 1601 | kfree(buf2); |
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 507be09e93a9..aeac619f787d 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c | |||
@@ -178,19 +178,12 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name, | |||
178 | error = 0; | 178 | error = 0; |
179 | break; | 179 | break; |
180 | } | 180 | } |
181 | if (error) { | 181 | if (error) |
182 | const char *dev = tomoyo_get_file_pattern(&rdev)->name; | 182 | error = tomoyo_supervisor(r, TOMOYO_KEYWORD_ALLOW_MOUNT |
183 | const char *dir = tomoyo_get_file_pattern(&rdir)->name; | 183 | "%s %s %s 0x%lX\n", |
184 | int len = strlen(dev) + strlen(dir) + strlen(requested_type) | 184 | tomoyo_file_pattern(&rdev), |
185 | + 64; | 185 | tomoyo_file_pattern(&rdir), |
186 | char *buf = kzalloc(len, GFP_NOFS); | 186 | requested_type, flags); |
187 | if (buf) { | ||
188 | snprintf(buf, len - 1, "%s %s %s 0x%lX", | ||
189 | dev, dir, requested_type, flags); | ||
190 | tomoyo_write_mount_policy(buf, r->domain, false); | ||
191 | kfree(buf); | ||
192 | } | ||
193 | } | ||
194 | out: | 187 | out: |
195 | kfree(requested_dev_name); | 188 | kfree(requested_dev_name); |
196 | kfree(requested_dir_name); | 189 | kfree(requested_dir_name); |
@@ -279,7 +272,10 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
279 | TOMOYO_MOUNT_MAKE_SHARED_KEYWORD, | 272 | TOMOYO_MOUNT_MAKE_SHARED_KEYWORD, |
280 | flags & ~MS_SHARED); | 273 | flags & ~MS_SHARED); |
281 | else | 274 | else |
282 | error = tomoyo_mount_acl2(r, dev_name, dir, type, flags); | 275 | do { |
276 | error = tomoyo_mount_acl2(r, dev_name, dir, type, | ||
277 | flags); | ||
278 | } while (error == TOMOYO_RETRY_REQUEST); | ||
283 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | 279 | if (r->mode != TOMOYO_CONFIG_ENFORCING) |
284 | error = 0; | 280 | error = 0; |
285 | return error; | 281 | return error; |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index d1b96f019621..3ceb1724c92d 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -333,6 +333,9 @@ void __init tomoyo_realpath_init(void) | |||
333 | panic("Can't register tomoyo_kernel_domain"); | 333 | panic("Can't register tomoyo_kernel_domain"); |
334 | } | 334 | } |
335 | 335 | ||
336 | unsigned int tomoyo_quota_for_query; | ||
337 | unsigned int tomoyo_query_memory_size; | ||
338 | |||
336 | /** | 339 | /** |
337 | * tomoyo_read_memory_counter - Check for memory usage in bytes. | 340 | * tomoyo_read_memory_counter - Check for memory usage in bytes. |
338 | * | 341 | * |
@@ -345,6 +348,7 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | |||
345 | if (!head->read_eof) { | 348 | if (!head->read_eof) { |
346 | const unsigned int policy | 349 | const unsigned int policy |
347 | = atomic_read(&tomoyo_policy_memory_size); | 350 | = atomic_read(&tomoyo_policy_memory_size); |
351 | const unsigned int query = tomoyo_query_memory_size; | ||
348 | char buffer[64]; | 352 | char buffer[64]; |
349 | 353 | ||
350 | memset(buffer, 0, sizeof(buffer)); | 354 | memset(buffer, 0, sizeof(buffer)); |
@@ -354,8 +358,17 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | |||
354 | tomoyo_quota_for_policy); | 358 | tomoyo_quota_for_policy); |
355 | else | 359 | else |
356 | buffer[0] = '\0'; | 360 | buffer[0] = '\0'; |
357 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); | 361 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, |
358 | tomoyo_io_printf(head, "Total: %10u\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); | ||
359 | head->read_eof = true; | 372 | head->read_eof = true; |
360 | } | 373 | } |
361 | return 0; | 374 | return 0; |
@@ -375,5 +388,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
375 | 388 | ||
376 | if (sscanf(data, "Policy: %u", &size) == 1) | 389 | if (sscanf(data, "Policy: %u", &size) == 1) |
377 | tomoyo_quota_for_policy = size; | 390 | tomoyo_quota_for_policy = size; |
391 | else if (sscanf(data, "Query lists: %u", &size) == 1) | ||
392 | tomoyo_quota_for_query = size; | ||
378 | return 0; | 393 | return 0; |
379 | } | 394 | } |