Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

binder: fix use-after-free due to ksys_close() during fdget()

44d8047f1d8 ("binder: use standard functions to allocate fds")
exposed a pre-existing issue in the binder driver.

fdget() is used in ksys_ioctl() as a performance optimization.
One of the rules associated with fdget() is that ksys_close() must
not be called between the fdget() and the fdput(). There is a case
where this requirement is not met in the binder driver which results
in the reference count dropping to 0 when the device is still in
use. This can result in use-after-free or other issues.

If userpace has passed a file-descriptor for the binder driver using
a BINDER_TYPE_FDA object, then kys_close() is called on it when
handling a binder_ioctl(BC_FREE_BUFFER) command. This violates
the assumptions for using fdget().

The problem is fixed by deferring the close using task_work_add(). A
new variant of __close_fd() was created that returns a struct file
with a reference. The fput() is deferred instead of using ksys_close().

Fixes: 44d8047f1d87a ("binder: use standard functions to allocate fds")
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Todd Kjos <tkjos@google.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Todd Kjos and committed by
Greg Kroah-Hartman
80cd7956 2701e804

+91 -2
+61 -2
drivers/android/binder.c
··· 72 72 #include <linux/spinlock.h> 73 73 #include <linux/ratelimit.h> 74 74 #include <linux/syscalls.h> 75 + #include <linux/task_work.h> 75 76 76 77 #include <uapi/linux/android/binder.h> 77 78 ··· 2171 2170 return (fixup_offset >= last_min_offset); 2172 2171 } 2173 2172 2173 + /** 2174 + * struct binder_task_work_cb - for deferred close 2175 + * 2176 + * @twork: callback_head for task work 2177 + * @fd: fd to close 2178 + * 2179 + * Structure to pass task work to be handled after 2180 + * returning from binder_ioctl() via task_work_add(). 2181 + */ 2182 + struct binder_task_work_cb { 2183 + struct callback_head twork; 2184 + struct file *file; 2185 + }; 2186 + 2187 + /** 2188 + * binder_do_fd_close() - close list of file descriptors 2189 + * @twork: callback head for task work 2190 + * 2191 + * It is not safe to call ksys_close() during the binder_ioctl() 2192 + * function if there is a chance that binder's own file descriptor 2193 + * might be closed. This is to meet the requirements for using 2194 + * fdget() (see comments for __fget_light()). Therefore use 2195 + * task_work_add() to schedule the close operation once we have 2196 + * returned from binder_ioctl(). This function is a callback 2197 + * for that mechanism and does the actual ksys_close() on the 2198 + * given file descriptor. 2199 + */ 2200 + static void binder_do_fd_close(struct callback_head *twork) 2201 + { 2202 + struct binder_task_work_cb *twcb = container_of(twork, 2203 + struct binder_task_work_cb, twork); 2204 + 2205 + fput(twcb->file); 2206 + kfree(twcb); 2207 + } 2208 + 2209 + /** 2210 + * binder_deferred_fd_close() - schedule a close for the given file-descriptor 2211 + * @fd: file-descriptor to close 2212 + * 2213 + * See comments in binder_do_fd_close(). This function is used to schedule 2214 + * a file-descriptor to be closed after returning from binder_ioctl(). 2215 + */ 2216 + static void binder_deferred_fd_close(int fd) 2217 + { 2218 + struct binder_task_work_cb *twcb; 2219 + 2220 + twcb = kzalloc(sizeof(*twcb), GFP_KERNEL); 2221 + if (!twcb) 2222 + return; 2223 + init_task_work(&twcb->twork, binder_do_fd_close); 2224 + __close_fd_get_file(fd, &twcb->file); 2225 + if (twcb->file) 2226 + task_work_add(current, &twcb->twork, true); 2227 + else 2228 + kfree(twcb); 2229 + } 2230 + 2174 2231 static void binder_transaction_buffer_release(struct binder_proc *proc, 2175 2232 struct binder_buffer *buffer, 2176 2233 binder_size_t *failed_at) ··· 2368 2309 } 2369 2310 fd_array = (u32 *)(parent_buffer + (uintptr_t)fda->parent_offset); 2370 2311 for (fd_index = 0; fd_index < fda->num_fds; fd_index++) 2371 - ksys_close(fd_array[fd_index]); 2312 + binder_deferred_fd_close(fd_array[fd_index]); 2372 2313 } break; 2373 2314 default: 2374 2315 pr_err("transaction release %d bad object type %x\n", ··· 3987 3928 } else if (ret) { 3988 3929 u32 *fdp = (u32 *)(t->buffer->data + fixup->offset); 3989 3930 3990 - ksys_close(*fdp); 3931 + binder_deferred_fd_close(*fdp); 3991 3932 } 3992 3933 list_del(&fixup->fixup_entry); 3993 3934 kfree(fixup);
+29
fs/file.c
··· 640 640 } 641 641 EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ 642 642 643 + /* 644 + * variant of __close_fd that gets a ref on the file for later fput 645 + */ 646 + int __close_fd_get_file(unsigned int fd, struct file **res) 647 + { 648 + struct files_struct *files = current->files; 649 + struct file *file; 650 + struct fdtable *fdt; 651 + 652 + spin_lock(&files->file_lock); 653 + fdt = files_fdtable(files); 654 + if (fd >= fdt->max_fds) 655 + goto out_unlock; 656 + file = fdt->fd[fd]; 657 + if (!file) 658 + goto out_unlock; 659 + rcu_assign_pointer(fdt->fd[fd], NULL); 660 + __put_unused_fd(files, fd); 661 + spin_unlock(&files->file_lock); 662 + get_file(file); 663 + *res = file; 664 + return filp_close(file, files); 665 + 666 + out_unlock: 667 + spin_unlock(&files->file_lock); 668 + *res = NULL; 669 + return -ENOENT; 670 + } 671 + 643 672 void do_close_on_exec(struct files_struct *files) 644 673 { 645 674 unsigned i;
+1
include/linux/fdtable.h
··· 121 121 unsigned int fd, struct file *file); 122 122 extern int __close_fd(struct files_struct *files, 123 123 unsigned int fd); 124 + extern int __close_fd_get_file(unsigned int fd, struct file **res); 124 125 125 126 extern struct kmem_cache *files_cachep; 126 127