diff options
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 426 |
1 files changed, 419 insertions, 7 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, |