diff options
| author | Todd Kjos <tkjos@android.com> | 2019-01-14 12:10:21 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-01-22 07:55:08 -0500 |
| commit | ec74136ded792deed80780a2f8baf3521eeb72f9 (patch) | |
| tree | ba8f8c2506386a221b7efe1f5ac069819d281651 /drivers/android | |
| parent | 8fdf90626588bc02af1200f6320d1d9c0540526f (diff) | |
binder: create node flag to request sender's security context
To allow servers to verify client identity, allow a node
flag to be set that causes the sender's security context
to be delivered with the transaction. The BR_TRANSACTION
command is extended in BR_TRANSACTION_SEC_CTX to
contain a pointer to the security context string.
Signed-off-by: Todd Kjos <tkjos@google.com>
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android')
| -rw-r--r-- | drivers/android/binder.c | 106 |
1 files changed, 83 insertions, 23 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index cdfc87629efb..5f6ef5e63b91 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
| @@ -329,6 +329,8 @@ struct binder_error { | |||
| 329 | * (invariant after initialized) | 329 | * (invariant after initialized) |
| 330 | * @min_priority: minimum scheduling priority | 330 | * @min_priority: minimum scheduling priority |
| 331 | * (invariant after initialized) | 331 | * (invariant after initialized) |
| 332 | * @txn_security_ctx: require sender's security context | ||
| 333 | * (invariant after initialized) | ||
| 332 | * @async_todo: list of async work items | 334 | * @async_todo: list of async work items |
| 333 | * (protected by @proc->inner_lock) | 335 | * (protected by @proc->inner_lock) |
| 334 | * | 336 | * |
| @@ -365,6 +367,7 @@ struct binder_node { | |||
| 365 | * invariant after initialization | 367 | * invariant after initialization |
| 366 | */ | 368 | */ |
| 367 | u8 accept_fds:1; | 369 | u8 accept_fds:1; |
| 370 | u8 txn_security_ctx:1; | ||
| 368 | u8 min_priority; | 371 | u8 min_priority; |
| 369 | }; | 372 | }; |
| 370 | bool has_async_transaction; | 373 | bool has_async_transaction; |
| @@ -615,6 +618,7 @@ struct binder_transaction { | |||
| 615 | long saved_priority; | 618 | long saved_priority; |
| 616 | kuid_t sender_euid; | 619 | kuid_t sender_euid; |
| 617 | struct list_head fd_fixups; | 620 | struct list_head fd_fixups; |
| 621 | binder_uintptr_t security_ctx; | ||
| 618 | /** | 622 | /** |
| 619 | * @lock: protects @from, @to_proc, and @to_thread | 623 | * @lock: protects @from, @to_proc, and @to_thread |
| 620 | * | 624 | * |
| @@ -1152,6 +1156,7 @@ static struct binder_node *binder_init_node_ilocked( | |||
| 1152 | node->work.type = BINDER_WORK_NODE; | 1156 | node->work.type = BINDER_WORK_NODE; |
| 1153 | node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; | 1157 | node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; |
| 1154 | node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); | 1158 | node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); |
| 1159 | node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX); | ||
| 1155 | spin_lock_init(&node->lock); | 1160 | spin_lock_init(&node->lock); |
| 1156 | INIT_LIST_HEAD(&node->work.entry); | 1161 | INIT_LIST_HEAD(&node->work.entry); |
| 1157 | INIT_LIST_HEAD(&node->async_todo); | 1162 | INIT_LIST_HEAD(&node->async_todo); |
| @@ -2778,6 +2783,8 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 2778 | binder_size_t last_fixup_min_off = 0; | 2783 | binder_size_t last_fixup_min_off = 0; |
| 2779 | struct binder_context *context = proc->context; | 2784 | struct binder_context *context = proc->context; |
| 2780 | int t_debug_id = atomic_inc_return(&binder_last_id); | 2785 | int t_debug_id = atomic_inc_return(&binder_last_id); |
| 2786 | char *secctx = NULL; | ||
| 2787 | u32 secctx_sz = 0; | ||
| 2781 | 2788 | ||
| 2782 | e = binder_transaction_log_add(&binder_transaction_log); | 2789 | e = binder_transaction_log_add(&binder_transaction_log); |
| 2783 | e->debug_id = t_debug_id; | 2790 | e->debug_id = t_debug_id; |
| @@ -3020,6 +3027,20 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 3020 | t->flags = tr->flags; | 3027 | t->flags = tr->flags; |
| 3021 | t->priority = task_nice(current); | 3028 | t->priority = task_nice(current); |
| 3022 | 3029 | ||
| 3030 | if (target_node && target_node->txn_security_ctx) { | ||
| 3031 | u32 secid; | ||
| 3032 | |||
| 3033 | security_task_getsecid(proc->tsk, &secid); | ||
| 3034 | ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); | ||
| 3035 | if (ret) { | ||
| 3036 | return_error = BR_FAILED_REPLY; | ||
| 3037 | return_error_param = ret; | ||
| 3038 | return_error_line = __LINE__; | ||
| 3039 | goto err_get_secctx_failed; | ||
| 3040 | } | ||
| 3041 | extra_buffers_size += ALIGN(secctx_sz, sizeof(u64)); | ||
| 3042 | } | ||
| 3043 | |||
| 3023 | trace_binder_transaction(reply, t, target_node); | 3044 | trace_binder_transaction(reply, t, target_node); |
| 3024 | 3045 | ||
| 3025 | t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, | 3046 | t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, |
| @@ -3036,6 +3057,19 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 3036 | t->buffer = NULL; | 3057 | t->buffer = NULL; |
| 3037 | goto err_binder_alloc_buf_failed; | 3058 | goto err_binder_alloc_buf_failed; |
| 3038 | } | 3059 | } |
| 3060 | if (secctx) { | ||
| 3061 | size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + | ||
| 3062 | ALIGN(tr->offsets_size, sizeof(void *)) + | ||
| 3063 | ALIGN(extra_buffers_size, sizeof(void *)) - | ||
| 3064 | ALIGN(secctx_sz, sizeof(u64)); | ||
| 3065 | char *kptr = t->buffer->data + buf_offset; | ||
| 3066 | |||
| 3067 | t->security_ctx = (uintptr_t)kptr + | ||
| 3068 | binder_alloc_get_user_buffer_offset(&target_proc->alloc); | ||
| 3069 | memcpy(kptr, secctx, secctx_sz); | ||
| 3070 | security_release_secctx(secctx, secctx_sz); | ||
| 3071 | secctx = NULL; | ||
| 3072 | } | ||
| 3039 | t->buffer->debug_id = t->debug_id; | 3073 | t->buffer->debug_id = t->debug_id; |
| 3040 | t->buffer->transaction = t; | 3074 | t->buffer->transaction = t; |
| 3041 | t->buffer->target_node = target_node; | 3075 | t->buffer->target_node = target_node; |
| @@ -3305,6 +3339,9 @@ err_copy_data_failed: | |||
| 3305 | t->buffer->transaction = NULL; | 3339 | t->buffer->transaction = NULL; |
| 3306 | binder_alloc_free_buf(&target_proc->alloc, t->buffer); | 3340 | binder_alloc_free_buf(&target_proc->alloc, t->buffer); |
| 3307 | err_binder_alloc_buf_failed: | 3341 | err_binder_alloc_buf_failed: |
| 3342 | if (secctx) | ||
| 3343 | security_release_secctx(secctx, secctx_sz); | ||
| 3344 | err_get_secctx_failed: | ||
| 3308 | kfree(tcomplete); | 3345 | kfree(tcomplete); |
| 3309 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); | 3346 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); |
| 3310 | err_alloc_tcomplete_failed: | 3347 | err_alloc_tcomplete_failed: |
| @@ -4036,11 +4073,13 @@ retry: | |||
| 4036 | 4073 | ||
| 4037 | while (1) { | 4074 | while (1) { |
| 4038 | uint32_t cmd; | 4075 | uint32_t cmd; |
| 4039 | struct binder_transaction_data tr; | 4076 | struct binder_transaction_data_secctx tr; |
| 4077 | struct binder_transaction_data *trd = &tr.transaction_data; | ||
| 4040 | struct binder_work *w = NULL; | 4078 | struct binder_work *w = NULL; |
| 4041 | struct list_head *list = NULL; | 4079 | struct list_head *list = NULL; |
| 4042 | struct binder_transaction *t = NULL; | 4080 | struct binder_transaction *t = NULL; |
| 4043 | struct binder_thread *t_from; | 4081 | struct binder_thread *t_from; |
| 4082 | size_t trsize = sizeof(*trd); | ||
| 4044 | 4083 | ||
| 4045 | binder_inner_proc_lock(proc); | 4084 | binder_inner_proc_lock(proc); |
| 4046 | if (!binder_worklist_empty_ilocked(&thread->todo)) | 4085 | if (!binder_worklist_empty_ilocked(&thread->todo)) |
| @@ -4240,8 +4279,8 @@ retry: | |||
| 4240 | if (t->buffer->target_node) { | 4279 | if (t->buffer->target_node) { |
| 4241 | struct binder_node *target_node = t->buffer->target_node; | 4280 | struct binder_node *target_node = t->buffer->target_node; |
| 4242 | 4281 | ||
| 4243 | tr.target.ptr = target_node->ptr; | 4282 | trd->target.ptr = target_node->ptr; |
| 4244 | tr.cookie = target_node->cookie; | 4283 | trd->cookie = target_node->cookie; |
| 4245 | t->saved_priority = task_nice(current); | 4284 | t->saved_priority = task_nice(current); |
| 4246 | if (t->priority < target_node->min_priority && | 4285 | if (t->priority < target_node->min_priority && |
| 4247 | !(t->flags & TF_ONE_WAY)) | 4286 | !(t->flags & TF_ONE_WAY)) |
| @@ -4251,22 +4290,23 @@ retry: | |||
| 4251 | binder_set_nice(target_node->min_priority); | 4290 | binder_set_nice(target_node->min_priority); |
| 4252 | cmd = BR_TRANSACTION; | 4291 | cmd = BR_TRANSACTION; |
| 4253 | } else { | 4292 | } else { |
| 4254 | tr.target.ptr = 0; | 4293 | trd->target.ptr = 0; |
| 4255 | tr.cookie = 0; | 4294 | trd->cookie = 0; |
| 4256 | cmd = BR_REPLY; | 4295 | cmd = BR_REPLY; |
| 4257 | } | 4296 | } |
| 4258 | tr.code = t->code; | 4297 | trd->code = t->code; |
| 4259 | tr.flags = t->flags; | 4298 | trd->flags = t->flags; |
| 4260 | tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); | 4299 | trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid); |
| 4261 | 4300 | ||
| 4262 | t_from = binder_get_txn_from(t); | 4301 | t_from = binder_get_txn_from(t); |
| 4263 | if (t_from) { | 4302 | if (t_from) { |
| 4264 | struct task_struct *sender = t_from->proc->tsk; | 4303 | struct task_struct *sender = t_from->proc->tsk; |
| 4265 | 4304 | ||
| 4266 | tr.sender_pid = task_tgid_nr_ns(sender, | 4305 | trd->sender_pid = |
| 4267 | task_active_pid_ns(current)); | 4306 | task_tgid_nr_ns(sender, |
| 4307 | task_active_pid_ns(current)); | ||
| 4268 | } else { | 4308 | } else { |
| 4269 | tr.sender_pid = 0; | 4309 | trd->sender_pid = 0; |
| 4270 | } | 4310 | } |
| 4271 | 4311 | ||
| 4272 | ret = binder_apply_fd_fixups(t); | 4312 | ret = binder_apply_fd_fixups(t); |
| @@ -4297,15 +4337,20 @@ retry: | |||
| 4297 | } | 4337 | } |
| 4298 | continue; | 4338 | continue; |
| 4299 | } | 4339 | } |
| 4300 | tr.data_size = t->buffer->data_size; | 4340 | trd->data_size = t->buffer->data_size; |
| 4301 | tr.offsets_size = t->buffer->offsets_size; | 4341 | trd->offsets_size = t->buffer->offsets_size; |
| 4302 | tr.data.ptr.buffer = (binder_uintptr_t) | 4342 | trd->data.ptr.buffer = (binder_uintptr_t) |
| 4303 | ((uintptr_t)t->buffer->data + | 4343 | ((uintptr_t)t->buffer->data + |
| 4304 | binder_alloc_get_user_buffer_offset(&proc->alloc)); | 4344 | binder_alloc_get_user_buffer_offset(&proc->alloc)); |
| 4305 | tr.data.ptr.offsets = tr.data.ptr.buffer + | 4345 | trd->data.ptr.offsets = trd->data.ptr.buffer + |
| 4306 | ALIGN(t->buffer->data_size, | 4346 | ALIGN(t->buffer->data_size, |
| 4307 | sizeof(void *)); | 4347 | sizeof(void *)); |
| 4308 | 4348 | ||
| 4349 | tr.secctx = t->security_ctx; | ||
| 4350 | if (t->security_ctx) { | ||
| 4351 | cmd = BR_TRANSACTION_SEC_CTX; | ||
| 4352 | trsize = sizeof(tr); | ||
| 4353 | } | ||
| 4309 | if (put_user(cmd, (uint32_t __user *)ptr)) { | 4354 | if (put_user(cmd, (uint32_t __user *)ptr)) { |
| 4310 | if (t_from) | 4355 | if (t_from) |
| 4311 | binder_thread_dec_tmpref(t_from); | 4356 | binder_thread_dec_tmpref(t_from); |
| @@ -4316,7 +4361,7 @@ retry: | |||
| 4316 | return -EFAULT; | 4361 | return -EFAULT; |
| 4317 | } | 4362 | } |
| 4318 | ptr += sizeof(uint32_t); | 4363 | ptr += sizeof(uint32_t); |
| 4319 | if (copy_to_user(ptr, &tr, sizeof(tr))) { | 4364 | if (copy_to_user(ptr, &tr, trsize)) { |
| 4320 | if (t_from) | 4365 | if (t_from) |
| 4321 | binder_thread_dec_tmpref(t_from); | 4366 | binder_thread_dec_tmpref(t_from); |
| 4322 | 4367 | ||
| @@ -4325,7 +4370,7 @@ retry: | |||
| 4325 | 4370 | ||
| 4326 | return -EFAULT; | 4371 | return -EFAULT; |
| 4327 | } | 4372 | } |
| 4328 | ptr += sizeof(tr); | 4373 | ptr += trsize; |
| 4329 | 4374 | ||
| 4330 | trace_binder_transaction_received(t); | 4375 | trace_binder_transaction_received(t); |
| 4331 | binder_stat_br(proc, thread, cmd); | 4376 | binder_stat_br(proc, thread, cmd); |
| @@ -4333,16 +4378,18 @@ retry: | |||
| 4333 | "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", | 4378 | "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", |
| 4334 | proc->pid, thread->pid, | 4379 | proc->pid, thread->pid, |
| 4335 | (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : | 4380 | (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : |
| 4336 | "BR_REPLY", | 4381 | (cmd == BR_TRANSACTION_SEC_CTX) ? |
| 4382 | "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", | ||
| 4337 | t->debug_id, t_from ? t_from->proc->pid : 0, | 4383 | t->debug_id, t_from ? t_from->proc->pid : 0, |
| 4338 | t_from ? t_from->pid : 0, cmd, | 4384 | t_from ? t_from->pid : 0, cmd, |
| 4339 | t->buffer->data_size, t->buffer->offsets_size, | 4385 | t->buffer->data_size, t->buffer->offsets_size, |
| 4340 | (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); | 4386 | (u64)trd->data.ptr.buffer, |
| 4387 | (u64)trd->data.ptr.offsets); | ||
| 4341 | 4388 | ||
| 4342 | if (t_from) | 4389 | if (t_from) |
| 4343 | binder_thread_dec_tmpref(t_from); | 4390 | binder_thread_dec_tmpref(t_from); |
| 4344 | t->buffer->allow_user_free = 1; | 4391 | t->buffer->allow_user_free = 1; |
| 4345 | if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { | 4392 | if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) { |
| 4346 | binder_inner_proc_lock(thread->proc); | 4393 | binder_inner_proc_lock(thread->proc); |
| 4347 | t->to_parent = thread->transaction_stack; | 4394 | t->to_parent = thread->transaction_stack; |
| 4348 | t->to_thread = thread; | 4395 | t->to_thread = thread; |
| @@ -4690,7 +4737,8 @@ out: | |||
| 4690 | return ret; | 4737 | return ret; |
| 4691 | } | 4738 | } |
| 4692 | 4739 | ||
| 4693 | static int binder_ioctl_set_ctx_mgr(struct file *filp) | 4740 | static int binder_ioctl_set_ctx_mgr(struct file *filp, |
| 4741 | struct flat_binder_object *fbo) | ||
| 4694 | { | 4742 | { |
| 4695 | int ret = 0; | 4743 | int ret = 0; |
| 4696 | struct binder_proc *proc = filp->private_data; | 4744 | struct binder_proc *proc = filp->private_data; |
| @@ -4719,7 +4767,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) | |||
| 4719 | } else { | 4767 | } else { |
| 4720 | context->binder_context_mgr_uid = curr_euid; | 4768 | context->binder_context_mgr_uid = curr_euid; |
| 4721 | } | 4769 | } |
| 4722 | new_node = binder_new_node(proc, NULL); | 4770 | new_node = binder_new_node(proc, fbo); |
| 4723 | if (!new_node) { | 4771 | if (!new_node) { |
| 4724 | ret = -ENOMEM; | 4772 | ret = -ENOMEM; |
| 4725 | goto out; | 4773 | goto out; |
| @@ -4842,8 +4890,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 4842 | binder_inner_proc_unlock(proc); | 4890 | binder_inner_proc_unlock(proc); |
| 4843 | break; | 4891 | break; |
| 4844 | } | 4892 | } |
| 4893 | case BINDER_SET_CONTEXT_MGR_EXT: { | ||
| 4894 | struct flat_binder_object fbo; | ||
| 4895 | |||
| 4896 | if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { | ||
| 4897 | ret = -EINVAL; | ||
| 4898 | goto err; | ||
| 4899 | } | ||
| 4900 | ret = binder_ioctl_set_ctx_mgr(filp, &fbo); | ||
| 4901 | if (ret) | ||
| 4902 | goto err; | ||
| 4903 | break; | ||
| 4904 | } | ||
| 4845 | case BINDER_SET_CONTEXT_MGR: | 4905 | case BINDER_SET_CONTEXT_MGR: |
| 4846 | ret = binder_ioctl_set_ctx_mgr(filp); | 4906 | ret = binder_ioctl_set_ctx_mgr(filp, NULL); |
| 4847 | if (ret) | 4907 | if (ret) |
| 4848 | goto err; | 4908 | goto err; |
| 4849 | break; | 4909 | break; |
