diff options
author | Arve Hjønnevåg <arve@android.com> | 2009-04-06 18:12:57 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-17 14:06:26 -0400 |
commit | 282ca175d4c440ec4d74bc622ee497e5b3530ce5 (patch) | |
tree | 4e336942fcfca0715a988332da6d0e7890fbad8e | |
parent | ea5c4cc68e2b5f4ec41d666376d3606d4d5c3426 (diff) |
Staging: binder: Keep a reference to the files_struct while the driver is mmapped
This prevents breaking fget_light if a single threaded application
allows incoming file descriptors (in replies or on nodes).
Should also prevent inserting a file in the wrong files_struct if the
receving process execs in the middle of a transaction (between
task_get_unused_fd_flags and task_fd_install).
Signed-off-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/android/binder.c | 79 |
1 files changed, 63 insertions, 16 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 64f95ee8a704..09962e87c600 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c | |||
@@ -41,6 +41,8 @@ static int binder_last_id; | |||
41 | static struct proc_dir_entry *binder_proc_dir_entry_root; | 41 | static struct proc_dir_entry *binder_proc_dir_entry_root; |
42 | static struct proc_dir_entry *binder_proc_dir_entry_proc; | 42 | static struct proc_dir_entry *binder_proc_dir_entry_proc; |
43 | static struct hlist_head binder_dead_nodes; | 43 | static struct hlist_head binder_dead_nodes; |
44 | static HLIST_HEAD(binder_release_files_list); | ||
45 | static DEFINE_MUTEX(binder_release_files_lock); | ||
44 | 46 | ||
45 | static int binder_read_proc_proc( | 47 | static int binder_read_proc_proc( |
46 | char *page, char **start, off_t off, int count, int *eof, void *data); | 48 | char *page, char **start, off_t off, int count, int *eof, void *data); |
@@ -241,6 +243,8 @@ struct binder_proc { | |||
241 | int pid; | 243 | int pid; |
242 | struct vm_area_struct *vma; | 244 | struct vm_area_struct *vma; |
243 | struct task_struct *tsk; | 245 | struct task_struct *tsk; |
246 | struct files_struct *files; | ||
247 | struct hlist_node release_files_node; | ||
244 | void *buffer; | 248 | void *buffer; |
245 | size_t user_buffer_offset; | 249 | size_t user_buffer_offset; |
246 | 250 | ||
@@ -309,9 +313,9 @@ struct binder_transaction { | |||
309 | /* | 313 | /* |
310 | * copied from get_unused_fd_flags | 314 | * copied from get_unused_fd_flags |
311 | */ | 315 | */ |
312 | int task_get_unused_fd_flags(struct task_struct *tsk, int flags) | 316 | int task_get_unused_fd_flags(struct binder_proc *proc, int flags) |
313 | { | 317 | { |
314 | struct files_struct *files = get_files_struct(tsk); | 318 | struct files_struct *files = proc->files; |
315 | int fd, error; | 319 | int fd, error; |
316 | struct fdtable *fdt; | 320 | struct fdtable *fdt; |
317 | unsigned long rlim_cur; | 321 | unsigned long rlim_cur; |
@@ -333,9 +337,9 @@ repeat: | |||
333 | * will limit the total number of files that can be opened. | 337 | * will limit the total number of files that can be opened. |
334 | */ | 338 | */ |
335 | rlim_cur = 0; | 339 | rlim_cur = 0; |
336 | if (lock_task_sighand(tsk, &irqs)) { | 340 | if (lock_task_sighand(proc->tsk, &irqs)) { |
337 | rlim_cur = tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; | 341 | rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; |
338 | unlock_task_sighand(tsk, &irqs); | 342 | unlock_task_sighand(proc->tsk, &irqs); |
339 | } | 343 | } |
340 | if (fd >= rlim_cur) | 344 | if (fd >= rlim_cur) |
341 | goto out; | 345 | goto out; |
@@ -371,7 +375,6 @@ repeat: | |||
371 | 375 | ||
372 | out: | 376 | out: |
373 | spin_unlock(&files->file_lock); | 377 | spin_unlock(&files->file_lock); |
374 | put_files_struct(files); | ||
375 | return error; | 378 | return error; |
376 | } | 379 | } |
377 | 380 | ||
@@ -379,9 +382,9 @@ out: | |||
379 | * copied from fd_install | 382 | * copied from fd_install |
380 | */ | 383 | */ |
381 | static void task_fd_install( | 384 | static void task_fd_install( |
382 | struct task_struct *tsk, unsigned int fd, struct file *file) | 385 | struct binder_proc *proc, unsigned int fd, struct file *file) |
383 | { | 386 | { |
384 | struct files_struct *files = get_files_struct(tsk); | 387 | struct files_struct *files = proc->files; |
385 | struct fdtable *fdt; | 388 | struct fdtable *fdt; |
386 | 389 | ||
387 | if (files == NULL) | 390 | if (files == NULL) |
@@ -392,7 +395,6 @@ static void task_fd_install( | |||
392 | BUG_ON(fdt->fd[fd] != NULL); | 395 | BUG_ON(fdt->fd[fd] != NULL); |
393 | rcu_assign_pointer(fdt->fd[fd], file); | 396 | rcu_assign_pointer(fdt->fd[fd], file); |
394 | spin_unlock(&files->file_lock); | 397 | spin_unlock(&files->file_lock); |
395 | put_files_struct(files); | ||
396 | } | 398 | } |
397 | 399 | ||
398 | /* | 400 | /* |
@@ -409,10 +411,10 @@ static void __put_unused_fd(struct files_struct *files, unsigned int fd) | |||
409 | /* | 411 | /* |
410 | * copied from sys_close | 412 | * copied from sys_close |
411 | */ | 413 | */ |
412 | static long task_close_fd(struct task_struct *tsk, unsigned int fd) | 414 | static long task_close_fd(struct binder_proc *proc, unsigned int fd) |
413 | { | 415 | { |
414 | struct file *filp; | 416 | struct file *filp; |
415 | struct files_struct *files = get_files_struct(tsk); | 417 | struct files_struct *files = proc->files; |
416 | struct fdtable *fdt; | 418 | struct fdtable *fdt; |
417 | int retval; | 419 | int retval; |
418 | 420 | ||
@@ -439,12 +441,10 @@ static long task_close_fd(struct task_struct *tsk, unsigned int fd) | |||
439 | retval == -ERESTART_RESTARTBLOCK)) | 441 | retval == -ERESTART_RESTARTBLOCK)) |
440 | retval = -EINTR; | 442 | retval = -EINTR; |
441 | 443 | ||
442 | put_files_struct(files); | ||
443 | return retval; | 444 | return retval; |
444 | 445 | ||
445 | out_unlock: | 446 | out_unlock: |
446 | spin_unlock(&files->file_lock); | 447 | spin_unlock(&files->file_lock); |
447 | put_files_struct(files); | ||
448 | return -EBADF; | 448 | return -EBADF; |
449 | } | 449 | } |
450 | 450 | ||
@@ -1549,13 +1549,13 @@ binder_transaction(struct binder_proc *proc, struct binder_thread *thread, | |||
1549 | return_error = BR_FAILED_REPLY; | 1549 | return_error = BR_FAILED_REPLY; |
1550 | goto err_fget_failed; | 1550 | goto err_fget_failed; |
1551 | } | 1551 | } |
1552 | target_fd = task_get_unused_fd_flags(target_proc->tsk, O_CLOEXEC); | 1552 | target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); |
1553 | if (target_fd < 0) { | 1553 | if (target_fd < 0) { |
1554 | fput(file); | 1554 | fput(file); |
1555 | return_error = BR_FAILED_REPLY; | 1555 | return_error = BR_FAILED_REPLY; |
1556 | goto err_get_unused_fd_failed; | 1556 | goto err_get_unused_fd_failed; |
1557 | } | 1557 | } |
1558 | task_fd_install(target_proc->tsk, target_fd, file); | 1558 | task_fd_install(target_proc, target_fd, file); |
1559 | if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) | 1559 | if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) |
1560 | printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); | 1560 | printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); |
1561 | /* TODO: fput? */ | 1561 | /* TODO: fput? */ |
@@ -1698,7 +1698,7 @@ binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer | |||
1698 | if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) | 1698 | if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) |
1699 | printk(KERN_INFO " fd %ld\n", fp->handle); | 1699 | printk(KERN_INFO " fd %ld\n", fp->handle); |
1700 | if (failed_at) | 1700 | if (failed_at) |
1701 | task_close_fd(proc->tsk, fp->handle); | 1701 | task_close_fd(proc, fp->handle); |
1702 | break; | 1702 | break; |
1703 | 1703 | ||
1704 | default: | 1704 | default: |
@@ -2663,6 +2663,34 @@ static void binder_vma_open(struct vm_area_struct *vma) | |||
2663 | (unsigned long)pgprot_val(vma->vm_page_prot)); | 2663 | (unsigned long)pgprot_val(vma->vm_page_prot)); |
2664 | dump_stack(); | 2664 | dump_stack(); |
2665 | } | 2665 | } |
2666 | |||
2667 | static void binder_release_files(struct work_struct *work) | ||
2668 | { | ||
2669 | struct binder_proc *proc; | ||
2670 | struct files_struct *files; | ||
2671 | do { | ||
2672 | mutex_lock(&binder_lock); | ||
2673 | mutex_lock(&binder_release_files_lock); | ||
2674 | if (!hlist_empty(&binder_release_files_list)) { | ||
2675 | proc = hlist_entry(binder_release_files_list.first, | ||
2676 | struct binder_proc, release_files_node); | ||
2677 | hlist_del_init(&proc->release_files_node); | ||
2678 | files = proc->files; | ||
2679 | if (files) | ||
2680 | proc->files = NULL; | ||
2681 | } else { | ||
2682 | proc = NULL; | ||
2683 | files = NULL; | ||
2684 | } | ||
2685 | mutex_unlock(&binder_release_files_lock); | ||
2686 | mutex_unlock(&binder_lock); | ||
2687 | if (files) | ||
2688 | put_files_struct(files); | ||
2689 | } while (proc); | ||
2690 | } | ||
2691 | |||
2692 | static DECLARE_WORK(binder_release_files_work, binder_release_files); | ||
2693 | |||
2666 | static void binder_vma_close(struct vm_area_struct *vma) | 2694 | static void binder_vma_close(struct vm_area_struct *vma) |
2667 | { | 2695 | { |
2668 | struct binder_proc *proc = vma->vm_private_data; | 2696 | struct binder_proc *proc = vma->vm_private_data; |
@@ -2673,6 +2701,13 @@ static void binder_vma_close(struct vm_area_struct *vma) | |||
2673 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, | 2701 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, |
2674 | (unsigned long)pgprot_val(vma->vm_page_prot)); | 2702 | (unsigned long)pgprot_val(vma->vm_page_prot)); |
2675 | proc->vma = NULL; | 2703 | proc->vma = NULL; |
2704 | mutex_lock(&binder_release_files_lock); | ||
2705 | if (proc->files) { | ||
2706 | hlist_add_head(&proc->release_files_node, | ||
2707 | &binder_release_files_list); | ||
2708 | schedule_work(&binder_release_files_work); | ||
2709 | } | ||
2710 | mutex_unlock(&binder_release_files_lock); | ||
2676 | } | 2711 | } |
2677 | 2712 | ||
2678 | static struct vm_operations_struct binder_vm_ops = { | 2713 | static struct vm_operations_struct binder_vm_ops = { |
@@ -2751,6 +2786,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) | |||
2751 | binder_insert_free_buffer(proc, buffer); | 2786 | binder_insert_free_buffer(proc, buffer); |
2752 | proc->free_async_space = proc->buffer_size / 2; | 2787 | proc->free_async_space = proc->buffer_size / 2; |
2753 | barrier(); | 2788 | barrier(); |
2789 | proc->files = get_files_struct(current); | ||
2754 | proc->vma = vma; | 2790 | proc->vma = vma; |
2755 | 2791 | ||
2756 | /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ | 2792 | /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ |
@@ -2831,6 +2867,7 @@ static int binder_release(struct inode *nodp, struct file *filp) | |||
2831 | struct hlist_node *pos; | 2867 | struct hlist_node *pos; |
2832 | struct binder_transaction *t; | 2868 | struct binder_transaction *t; |
2833 | struct rb_node *n; | 2869 | struct rb_node *n; |
2870 | struct files_struct *files; | ||
2834 | struct binder_proc *proc = filp->private_data; | 2871 | struct binder_proc *proc = filp->private_data; |
2835 | int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; | 2872 | int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; |
2836 | 2873 | ||
@@ -2840,6 +2877,14 @@ static int binder_release(struct inode *nodp, struct file *filp) | |||
2840 | remove_proc_entry(strbuf, binder_proc_dir_entry_proc); | 2877 | remove_proc_entry(strbuf, binder_proc_dir_entry_proc); |
2841 | } | 2878 | } |
2842 | mutex_lock(&binder_lock); | 2879 | mutex_lock(&binder_lock); |
2880 | mutex_lock(&binder_release_files_lock); | ||
2881 | if (!hlist_unhashed(&proc->release_files_node)) | ||
2882 | hlist_del(&proc->release_files_node); | ||
2883 | files = proc->files; | ||
2884 | if (files) | ||
2885 | proc->files = NULL; | ||
2886 | mutex_unlock(&binder_release_files_lock); | ||
2887 | |||
2843 | hlist_del(&proc->proc_node); | 2888 | hlist_del(&proc->proc_node); |
2844 | if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { | 2889 | if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { |
2845 | if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) | 2890 | if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) |
@@ -2937,6 +2982,8 @@ static int binder_release(struct inode *nodp, struct file *filp) | |||
2937 | proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); | 2982 | proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); |
2938 | 2983 | ||
2939 | kfree(proc); | 2984 | kfree(proc); |
2985 | if (files) | ||
2986 | put_files_struct(files); | ||
2940 | return 0; | 2987 | return 0; |
2941 | } | 2988 | } |
2942 | 2989 | ||