Loading drivers/staging/android/binder.c +137 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,9 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error, #define to_binder_buffer_object(hdr) \ container_of(hdr, struct binder_buffer_object, hdr) #define to_binder_fd_array_object(hdr) \ container_of(hdr, struct binder_fd_array_object, hdr) enum binder_stat_types { BINDER_STAT_PROC, BINDER_STAT_THREAD, Loading Loading @@ -1308,6 +1311,9 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) case BINDER_TYPE_PTR: object_size = sizeof(struct binder_buffer_object); break; case BINDER_TYPE_FDA: object_size = sizeof(struct binder_fd_array_object); break; default: return 0; } Loading Loading @@ -1501,6 +1507,47 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * transaction buffer gets freed */ break; case BINDER_TYPE_FDA: { struct binder_fd_array_object *fda; struct binder_buffer_object *parent; uintptr_t parent_buffer; u32 *fd_array; size_t fd_index; binder_size_t fd_buf_size; fda = to_binder_fd_array_object(hdr); parent = binder_validate_ptr(buffer, fda->parent, off_start, offp - off_start); if (!parent) { pr_err("transaction release %d bad parent offset", debug_id); continue; } /* * Since the parent was already fixed up, convert it * back to kernel address space to access it */ parent_buffer = parent->buffer - proc->user_buffer_offset; fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { pr_err("transaction release %d invalid number of fds (%lld)\n", debug_id, (u64)fda->num_fds); continue; } if (fd_buf_size > parent->length || fda->parent_offset > parent->length - fd_buf_size) { /* No space for all file descriptors here. */ pr_err("transaction release %d not enough space for %lld fds in buffer\n", debug_id, (u64)fda->num_fds); continue; } fd_array = (u32 *)(parent_buffer + fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) task_close_fd(proc, fd_array[fd_index]); } break; default: pr_err("transaction release %d bad object type %x\n", debug_id, hdr->type); Loading Loading @@ -1670,6 +1717,63 @@ err_fd_not_accepted: return ret; } static int binder_translate_fd_array(struct binder_fd_array_object *fda, struct binder_buffer_object *parent, struct binder_transaction *t, struct binder_thread *thread, struct binder_transaction *in_reply_to) { binder_size_t fdi, fd_buf_size, num_installed_fds; int target_fd; uintptr_t parent_buffer; u32 *fd_array; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { binder_user_error("%d:%d got transaction with invalid number of fds (%lld)\n", proc->pid, thread->pid, (u64)fda->num_fds); return -EINVAL; } if (fd_buf_size > parent->length || fda->parent_offset > parent->length - fd_buf_size) { /* No space for all file descriptors here. */ binder_user_error("%d:%d not enough space to store %lld fds in buffer\n", proc->pid, thread->pid, (u64)fda->num_fds); return -EINVAL; } /* * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ parent_buffer = parent->buffer - target_proc->user_buffer_offset; fd_array = (u32 *)(parent_buffer + fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", proc->pid, thread->pid); return -EINVAL; } for (fdi = 0; fdi < fda->num_fds; fdi++) { target_fd = binder_translate_fd(fd_array[fdi], t, thread, in_reply_to); if (target_fd < 0) goto err_translate_fd_failed; fd_array[fdi] = target_fd; } return 0; err_translate_fd_failed: /* * Failed to allocate fd or security error, free fds * installed so far. */ num_installed_fds = fdi; for (fdi = 0; fdi < num_installed_fds; fdi++) task_close_fd(target_proc, fd_array[fdi]); return target_fd; } static int binder_fixup_parent(struct binder_transaction *t, struct binder_thread *thread, struct binder_buffer_object *bp, Loading Loading @@ -1997,6 +2101,38 @@ static void binder_transaction(struct binder_proc *proc, fp->pad_binder = 0; fp->fd = target_fd; } break; case BINDER_TYPE_FDA: { struct binder_fd_array_object *fda = to_binder_fd_array_object(hdr); struct binder_buffer_object *parent = binder_validate_ptr(t->buffer, fda->parent, off_start, offp - off_start); if (!parent) { binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, parent, fda->parent_offset, last_fixup_obj, last_fixup_min_off)) { binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; goto err_translate_failed; } last_fixup_obj = parent; last_fixup_min_off = fda->parent_offset + sizeof(u32) * fda->num_fds; } break; case BINDER_TYPE_PTR: { struct binder_buffer_object *bp = to_binder_buffer_object(hdr); Loading Loading @@ -2075,6 +2211,7 @@ static void binder_transaction(struct binder_proc *proc, err_translate_failed: err_bad_object_type: err_bad_offset: err_bad_parent: err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); Loading drivers/staging/android/uapi/binder.h +28 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ enum { BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE), BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; Loading Loading @@ -128,6 +129,33 @@ enum { BINDER_BUFFER_FLAG_HAS_PARENT = 0x01, }; /* struct binder_fd_array_object - object describing an array of fds in a buffer * @hdr: common header structure * @num_fds: number of file descriptors in the buffer * @parent: index in offset array to buffer holding the fd array * @parent_offset: start offset of fd array in the buffer * * A binder_fd_array object represents an array of file * descriptors embedded in a binder_buffer_object. It is * different from a regular binder_buffer_object because it * describes a list of file descriptors to fix up, not an opaque * blob of memory, and hence the kernel needs to treat it differently. * * An example of how this would be used is with Android's * native_handle_t object, which is a struct with a list of integers * and a list of file descriptors. The native_handle_t struct itself * will be represented by a struct binder_buffer_objct, whereas the * embedded list of file descriptors is represented by a * struct binder_fd_array_object with that binder_buffer_object as * a parent. */ struct binder_fd_array_object { struct binder_object_header hdr; binder_size_t num_fds; binder_size_t parent; binder_size_t parent_offset; }; /* * On 64-bit platforms where user code may run in 32-bits the driver must * translate the buffer (and local binder) addresses appropriately. Loading Loading
drivers/staging/android/binder.c +137 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,9 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error, #define to_binder_buffer_object(hdr) \ container_of(hdr, struct binder_buffer_object, hdr) #define to_binder_fd_array_object(hdr) \ container_of(hdr, struct binder_fd_array_object, hdr) enum binder_stat_types { BINDER_STAT_PROC, BINDER_STAT_THREAD, Loading Loading @@ -1308,6 +1311,9 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) case BINDER_TYPE_PTR: object_size = sizeof(struct binder_buffer_object); break; case BINDER_TYPE_FDA: object_size = sizeof(struct binder_fd_array_object); break; default: return 0; } Loading Loading @@ -1501,6 +1507,47 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * transaction buffer gets freed */ break; case BINDER_TYPE_FDA: { struct binder_fd_array_object *fda; struct binder_buffer_object *parent; uintptr_t parent_buffer; u32 *fd_array; size_t fd_index; binder_size_t fd_buf_size; fda = to_binder_fd_array_object(hdr); parent = binder_validate_ptr(buffer, fda->parent, off_start, offp - off_start); if (!parent) { pr_err("transaction release %d bad parent offset", debug_id); continue; } /* * Since the parent was already fixed up, convert it * back to kernel address space to access it */ parent_buffer = parent->buffer - proc->user_buffer_offset; fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { pr_err("transaction release %d invalid number of fds (%lld)\n", debug_id, (u64)fda->num_fds); continue; } if (fd_buf_size > parent->length || fda->parent_offset > parent->length - fd_buf_size) { /* No space for all file descriptors here. */ pr_err("transaction release %d not enough space for %lld fds in buffer\n", debug_id, (u64)fda->num_fds); continue; } fd_array = (u32 *)(parent_buffer + fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) task_close_fd(proc, fd_array[fd_index]); } break; default: pr_err("transaction release %d bad object type %x\n", debug_id, hdr->type); Loading Loading @@ -1670,6 +1717,63 @@ err_fd_not_accepted: return ret; } static int binder_translate_fd_array(struct binder_fd_array_object *fda, struct binder_buffer_object *parent, struct binder_transaction *t, struct binder_thread *thread, struct binder_transaction *in_reply_to) { binder_size_t fdi, fd_buf_size, num_installed_fds; int target_fd; uintptr_t parent_buffer; u32 *fd_array; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { binder_user_error("%d:%d got transaction with invalid number of fds (%lld)\n", proc->pid, thread->pid, (u64)fda->num_fds); return -EINVAL; } if (fd_buf_size > parent->length || fda->parent_offset > parent->length - fd_buf_size) { /* No space for all file descriptors here. */ binder_user_error("%d:%d not enough space to store %lld fds in buffer\n", proc->pid, thread->pid, (u64)fda->num_fds); return -EINVAL; } /* * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ parent_buffer = parent->buffer - target_proc->user_buffer_offset; fd_array = (u32 *)(parent_buffer + fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", proc->pid, thread->pid); return -EINVAL; } for (fdi = 0; fdi < fda->num_fds; fdi++) { target_fd = binder_translate_fd(fd_array[fdi], t, thread, in_reply_to); if (target_fd < 0) goto err_translate_fd_failed; fd_array[fdi] = target_fd; } return 0; err_translate_fd_failed: /* * Failed to allocate fd or security error, free fds * installed so far. */ num_installed_fds = fdi; for (fdi = 0; fdi < num_installed_fds; fdi++) task_close_fd(target_proc, fd_array[fdi]); return target_fd; } static int binder_fixup_parent(struct binder_transaction *t, struct binder_thread *thread, struct binder_buffer_object *bp, Loading Loading @@ -1997,6 +2101,38 @@ static void binder_transaction(struct binder_proc *proc, fp->pad_binder = 0; fp->fd = target_fd; } break; case BINDER_TYPE_FDA: { struct binder_fd_array_object *fda = to_binder_fd_array_object(hdr); struct binder_buffer_object *parent = binder_validate_ptr(t->buffer, fda->parent, off_start, offp - off_start); if (!parent) { binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, parent, fda->parent_offset, last_fixup_obj, last_fixup_min_off)) { binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; goto err_translate_failed; } last_fixup_obj = parent; last_fixup_min_off = fda->parent_offset + sizeof(u32) * fda->num_fds; } break; case BINDER_TYPE_PTR: { struct binder_buffer_object *bp = to_binder_buffer_object(hdr); Loading Loading @@ -2075,6 +2211,7 @@ static void binder_transaction(struct binder_proc *proc, err_translate_failed: err_bad_object_type: err_bad_offset: err_bad_parent: err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); Loading
drivers/staging/android/uapi/binder.h +28 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ enum { BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE), BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; Loading Loading @@ -128,6 +129,33 @@ enum { BINDER_BUFFER_FLAG_HAS_PARENT = 0x01, }; /* struct binder_fd_array_object - object describing an array of fds in a buffer * @hdr: common header structure * @num_fds: number of file descriptors in the buffer * @parent: index in offset array to buffer holding the fd array * @parent_offset: start offset of fd array in the buffer * * A binder_fd_array object represents an array of file * descriptors embedded in a binder_buffer_object. It is * different from a regular binder_buffer_object because it * describes a list of file descriptors to fix up, not an opaque * blob of memory, and hence the kernel needs to treat it differently. * * An example of how this would be used is with Android's * native_handle_t object, which is a struct with a list of integers * and a list of file descriptors. The native_handle_t struct itself * will be represented by a struct binder_buffer_objct, whereas the * embedded list of file descriptors is represented by a * struct binder_fd_array_object with that binder_buffer_object as * a parent. */ struct binder_fd_array_object { struct binder_object_header hdr; binder_size_t num_fds; binder_size_t parent; binder_size_t parent_offset; }; /* * On 64-bit platforms where user code may run in 32-bits the driver must * translate the buffer (and local binder) addresses appropriately. Loading