Skip to content

Commit ea5c00b

Browse files
toddkjospundiramit
authored andcommitted
FROMLIST: binder: fix proc->files use-after-free
(from https://patchwork.kernel.org/patch/10058587/) proc->files cleanup is initiated by binder_vma_close. Therefore a reference on the binder_proc is not enough to prevent the files_struct from being released while the binder_proc still has a reference. This can lead to an attempt to dereference the stale pointer obtained from proc->files prior to proc->files cleanup. This has been seen once in task_get_unused_fd_flags() when __alloc_fd() is called with a stale "files". The fix is to always use get_files_struct() to obtain struct_files so that the refcount on the files_struct is used to prevent a premature free. proc->files is removed since we get it every time. Bug: 69164715 Change-Id: I6431027d3d569e76913935c21885201505627982 Signed-off-by: Todd Kjos <tkjos@google.com>
1 parent 3f883f9 commit ea5c00b

1 file changed

Lines changed: 30 additions & 33 deletions

File tree

drivers/android/binder.c

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,8 @@ struct binder_ref {
466466
};
467467

468468
enum binder_deferred_state {
469-
BINDER_DEFERRED_PUT_FILES = 0x01,
470-
BINDER_DEFERRED_FLUSH = 0x02,
471-
BINDER_DEFERRED_RELEASE = 0x04,
469+
BINDER_DEFERRED_FLUSH = 0x01,
470+
BINDER_DEFERRED_RELEASE = 0x02,
472471
};
473472

474473
/**
@@ -505,8 +504,6 @@ struct binder_priority {
505504
* (invariant after initialized)
506505
* @tsk task_struct for group_leader of process
507506
* (invariant after initialized)
508-
* @files files_struct for process
509-
* (invariant after initialized)
510507
* @deferred_work_node: element for binder_deferred_list
511508
* (protected by binder_deferred_lock)
512509
* @deferred_work: bitmap of deferred work to perform
@@ -553,7 +550,6 @@ struct binder_proc {
553550
struct list_head waiting_threads;
554551
int pid;
555552
struct task_struct *tsk;
556-
struct files_struct *files;
557553
struct hlist_node deferred_work_node;
558554
int deferred_work;
559555
bool is_dead;
@@ -949,22 +945,34 @@ static void binder_free_thread(struct binder_thread *thread);
949945
static void binder_free_proc(struct binder_proc *proc);
950946
static void binder_inc_node_tmpref_ilocked(struct binder_node *node);
951947

948+
struct files_struct *binder_get_files_struct(struct binder_proc *proc)
949+
{
950+
return get_files_struct(proc->tsk);
951+
}
952+
952953
static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
953954
{
954-
struct files_struct *files = proc->files;
955+
struct files_struct *files;
955956
unsigned long rlim_cur;
956957
unsigned long irqs;
958+
int ret;
957959

960+
files = binder_get_files_struct(proc);
958961
if (files == NULL)
959962
return -ESRCH;
960963

961-
if (!lock_task_sighand(proc->tsk, &irqs))
962-
return -EMFILE;
964+
if (!lock_task_sighand(proc->tsk, &irqs)) {
965+
ret = -EMFILE;
966+
goto err;
967+
}
963968

964969
rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
965970
unlock_task_sighand(proc->tsk, &irqs);
966971

967-
return __alloc_fd(files, 0, rlim_cur, flags);
972+
ret = __alloc_fd(files, 0, rlim_cur, flags);
973+
err:
974+
put_files_struct(files);
975+
return ret;
968976
}
969977

970978
/*
@@ -973,27 +981,33 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
973981
static void task_fd_install(
974982
struct binder_proc *proc, unsigned int fd, struct file *file)
975983
{
976-
if (proc->files)
977-
__fd_install(proc->files, fd, file);
984+
struct files_struct *files = binder_get_files_struct(proc);
985+
986+
if (files) {
987+
__fd_install(files, fd, file);
988+
put_files_struct(files);
989+
}
978990
}
979991

980992
/*
981993
* copied from sys_close
982994
*/
983995
static long task_close_fd(struct binder_proc *proc, unsigned int fd)
984996
{
997+
struct files_struct *files = binder_get_files_struct(proc);
985998
int retval;
986999

987-
if (proc->files == NULL)
1000+
if (files == NULL)
9881001
return -ESRCH;
9891002

990-
retval = __close_fd(proc->files, fd);
1003+
retval = __close_fd(files, fd);
9911004
/* can't restart close syscall because file table entry was cleared */
9921005
if (unlikely(retval == -ERESTARTSYS ||
9931006
retval == -ERESTARTNOINTR ||
9941007
retval == -ERESTARTNOHAND ||
9951008
retval == -ERESTART_RESTARTBLOCK))
9961009
retval = -EINTR;
1010+
put_files_struct(files);
9971011

9981012
return retval;
9991013
}
@@ -4818,7 +4832,6 @@ static void binder_vma_close(struct vm_area_struct *vma)
48184832
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
48194833
(unsigned long)pgprot_val(vma->vm_page_prot));
48204834
binder_alloc_vma_close(&proc->alloc);
4821-
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
48224835
}
48234836

48244837
static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -4860,10 +4873,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
48604873
vma->vm_private_data = proc;
48614874

48624875
ret = binder_alloc_mmap_handler(&proc->alloc, vma);
4863-
if (ret)
4864-
return ret;
4865-
proc->files = get_files_struct(current);
4866-
return 0;
4876+
4877+
return ret;
48674878

48684879
err_bad_arg:
48694880
pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
@@ -5042,8 +5053,6 @@ static void binder_deferred_release(struct binder_proc *proc)
50425053
struct rb_node *n;
50435054
int threads, nodes, incoming_refs, outgoing_refs, active_transactions;
50445055

5045-
BUG_ON(proc->files);
5046-
50475056
mutex_lock(&binder_procs_lock);
50485057
hlist_del(&proc->proc_node);
50495058
mutex_unlock(&binder_procs_lock);
@@ -5125,8 +5134,6 @@ static void binder_deferred_release(struct binder_proc *proc)
51255134
static void binder_deferred_func(struct work_struct *work)
51265135
{
51275136
struct binder_proc *proc;
5128-
struct files_struct *files;
5129-
51305137
int defer;
51315138

51325139
do {
@@ -5143,21 +5150,11 @@ static void binder_deferred_func(struct work_struct *work)
51435150
}
51445151
mutex_unlock(&binder_deferred_lock);
51455152

5146-
files = NULL;
5147-
if (defer & BINDER_DEFERRED_PUT_FILES) {
5148-
files = proc->files;
5149-
if (files)
5150-
proc->files = NULL;
5151-
}
5152-
51535153
if (defer & BINDER_DEFERRED_FLUSH)
51545154
binder_deferred_flush(proc);
51555155

51565156
if (defer & BINDER_DEFERRED_RELEASE)
51575157
binder_deferred_release(proc); /* frees proc */
5158-
5159-
if (files)
5160-
put_files_struct(files);
51615158
} while (proc);
51625159
}
51635160
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);

0 commit comments

Comments
 (0)