History

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.

Todd Kjos committed 7 years ago

Commit ec741361 parent 8fdf9062 files · +102 −23Browse files

Unified · Split

2 files
  1. drivers/android/binder.c +83 −23
  2. include/uapi/linux/android/binder.h +19 −0
drivers/android/binder.c+83−23
@@ -329,6 +329,8 @@ struct binder_error { · 328 unmodified lines
329329 * (invariant after initialized)
330330 * @min_priority: minimum scheduling priority
331331 * (invariant after initialized)
332+ * @txn_security_ctx: require sender's security context
333+ * (invariant after initialized)
332334 * @async_todo: list of async work items
333335 * (protected by @proc->inner_lock)
334336 *
@@ -365,6 +367,7 @@ struct binder_node { · 30 unmodified lines
365367 * invariant after initialization
366368 */
367369 u8 accept_fds:1;
370+ u8 txn_security_ctx:1;
368371 u8 min_priority;
369372 };
370373 bool has_async_transaction;
@@ -615,6 +618,7 @@ struct binder_transaction { · 244 unmodified lines
615618 long saved_priority;
616619 kuid_t sender_euid;
617620 struct list_head fd_fixups;
621+ binder_uintptr_t security_ctx;
618622 /**
619623 * @lock: protects @from, @to_proc, and @to_thread
620624 *
@@ -1152,6 +1156,7 @@ static struct binder_node *binder_init_node_ilocked( · 531 unmodified lines
11521156 node->work.type = BINDER_WORK_NODE;
11531157 node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
11541158 node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
1159+ node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX);
11551160 spin_lock_init(&node->lock);
11561161 INIT_LIST_HEAD(&node->work.entry);
11571162 INIT_LIST_HEAD(&node->async_todo);
@@ -2778,6 +2783,8 @@ static void binder_transaction(struct binder_proc *proc, · 1620 unmodified lines
27782783 binder_size_t last_fixup_min_off = 0;
27792784 struct binder_context *context = proc->context;
27802785 int t_debug_id = atomic_inc_return(&binder_last_id);
2786+ char *secctx = NULL;
2787+ u32 secctx_sz = 0;
27812788
27822789 e = binder_transaction_log_add(&binder_transaction_log);
27832790 e->debug_id = t_debug_id;
@@ -3020,6 +3027,20 @@ static void binder_transaction(struct binder_proc *proc, · 236 unmodified lines
30203027 t->flags = tr->flags;
30213028 t->priority = task_nice(current);
30223029
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+
30233044 trace_binder_transaction(reply, t, target_node);
30243045
30253046 t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
@@ -3036,6 +3057,19 @@ static void binder_transaction(struct binder_proc *proc, · 10 unmodified lines
30363057 t->buffer = NULL;
30373058 goto err_binder_alloc_buf_failed;
30383059 }
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+ }
30393073 t->buffer->debug_id = t->debug_id;
30403074 t->buffer->transaction = t;
30413075 t->buffer->target_node = target_node;
@@ -3305,6 +3339,9 @@ err_copy_data_failed: · 263 unmodified lines
33053339 t->buffer->transaction = NULL;
33063340 binder_alloc_free_buf(&target_proc->alloc, t->buffer);
33073341 err_binder_alloc_buf_failed:
3342+ if (secctx)
3343+ security_release_secctx(secctx, secctx_sz);
3344+err_get_secctx_failed:
33083345 kfree(tcomplete);
33093346 binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
33103347 err_alloc_tcomplete_failed:
@@ -4036,11 +4073,13 @@ retry: · 725 unmodified lines
40364073
40374074 while (1) {
40384075 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;
40404078 struct binder_work *w = NULL;
40414079 struct list_head *list = NULL;
40424080 struct binder_transaction *t = NULL;
40434081 struct binder_thread *t_from;
4082+ size_t trsize = sizeof(*trd);
40444083
40454084 binder_inner_proc_lock(proc);
40464085 if (!binder_worklist_empty_ilocked(&thread->todo))
@@ -4240,8 +4279,8 @@ retry: · 193 unmodified lines
42404279 if (t->buffer->target_node) {
42414280 struct binder_node *target_node = t->buffer->target_node;
42424281
4243− tr.target.ptr = target_node->ptr;
4244− tr.cookie = target_node->cookie;
4282+ trd->target.ptr = target_node->ptr;
4283+ trd->cookie = target_node->cookie;
42454284 t->saved_priority = task_nice(current);
42464285 if (t->priority < target_node->min_priority &&
42474286 !(t->flags & TF_ONE_WAY))
@@ -4251,22 +4290,23 @@ retry: · 3 unmodified lines
42514290 binder_set_nice(target_node->min_priority);
42524291 cmd = BR_TRANSACTION;
42534292 } else {
4254− tr.target.ptr = 0;
4255− tr.cookie = 0;
4293+ trd->target.ptr = 0;
4294+ trd->cookie = 0;
42564295 cmd = BR_REPLY;
42574296 }
4258− tr.code = t->code;
4259− tr.flags = t->flags;
4260− tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
4297+ trd->code = t->code;
4298+ trd->flags = t->flags;
4299+ trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
42614300
42624301 t_from = binder_get_txn_from(t);
42634302 if (t_from) {
42644303 struct task_struct *sender = t_from->proc->tsk;
42654304
4266− tr.sender_pid = task_tgid_nr_ns(sender,
4267− task_active_pid_ns(current));
4305+ trd->sender_pid =
4306+ task_tgid_nr_ns(sender,
4307+ task_active_pid_ns(current));
42684308 } else {
4269− tr.sender_pid = 0;
4309+ trd->sender_pid = 0;
42704310 }
42714311
42724312 ret = binder_apply_fd_fixups(t);
@@ -4297,15 +4337,20 @@ retry: · 24 unmodified lines
42974337 }
42984338 continue;
42994339 }
4300− tr.data_size = t->buffer->data_size;
4301− tr.offsets_size = t->buffer->offsets_size;
4302− tr.data.ptr.buffer = (binder_uintptr_t)
4340+ trd->data_size = t->buffer->data_size;
4341+ trd->offsets_size = t->buffer->offsets_size;
4342+ trd->data.ptr.buffer = (binder_uintptr_t)
43034343 ((uintptr_t)t->buffer->data +
43044344 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 +
43064346 ALIGN(t->buffer->data_size,
43074347 sizeof(void *));
43084348
4349+ tr.secctx = t->security_ctx;
4350+ if (t->security_ctx) {
4351+ cmd = BR_TRANSACTION_SEC_CTX;
4352+ trsize = sizeof(tr);
4353+ }
43094354 if (put_user(cmd, (uint32_t __user *)ptr)) {
43104355 if (t_from)
43114356 binder_thread_dec_tmpref(t_from);
@@ -4316,7 +4361,7 @@ retry: · 4 unmodified lines
43164361 return -EFAULT;
43174362 }
43184363 ptr += sizeof(uint32_t);
4319− if (copy_to_user(ptr, &tr, sizeof(tr))) {
4364+ if (copy_to_user(ptr, &tr, trsize)) {
43204365 if (t_from)
43214366 binder_thread_dec_tmpref(t_from);
43224367
@@ -4325,7 +4370,7 @@ retry: · 2 unmodified lines
43254370
43264371 return -EFAULT;
43274372 }
4328− ptr += sizeof(tr);
4373+ ptr += trsize;
43294374
43304375 trace_binder_transaction_received(t);
43314376 binder_stat_br(proc, thread, cmd);
@@ -4333,16 +4378,18 @@ retry: · 1 unmodified line
43334378 "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
43344379 proc->pid, thread->pid,
43354380 (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
4336− "BR_REPLY",
4381+ (cmd == BR_TRANSACTION_SEC_CTX) ?
4382+ "BR_TRANSACTION_SEC_CTX" : "BR_REPLY",
43374383 t->debug_id, t_from ? t_from->proc->pid : 0,
43384384 t_from ? t_from->pid : 0, cmd,
43394385 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);
43414388
43424389 if (t_from)
43434390 binder_thread_dec_tmpref(t_from);
43444391 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)) {
43464393 binder_inner_proc_lock(thread->proc);
43474394 t->to_parent = thread->transaction_stack;
43484395 t->to_thread = thread;
@@ -4690,7 +4737,8 @@ out: · 341 unmodified lines
46904737 return ret;
46914738 }
46924739
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)
46944742 {
46954743 int ret = 0;
46964744 struct binder_proc *proc = filp->private_data;
@@ -4719,7 +4767,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) · 22 unmodified lines
47194767 } else {
47204768 context->binder_context_mgr_uid = curr_euid;
47214769 }
4722− new_node = binder_new_node(proc, NULL);
4770+ new_node = binder_new_node(proc, fbo);
47234771 if (!new_node) {
47244772 ret = -ENOMEM;
47254773 goto out;
@@ -4842,8 +4890,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 116 unmodified lines
48424890 binder_inner_proc_unlock(proc);
48434891 break;
48444892 }
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+ }
48454905 case BINDER_SET_CONTEXT_MGR:
4846− ret = binder_ioctl_set_ctx_mgr(filp);
4906+ ret = binder_ioctl_set_ctx_mgr(filp, NULL);
48474907 if (ret)
48484908 goto err;
48494909 break;
include/uapi/linux/android/binder.h+19−0
@@ -41,6 +41,14 @@ enum { · 40 unmodified lines
4141 enum {
4242 FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
4343 FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
44+
45+ /**
46+ * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts
47+ *
48+ * Only when set, causes senders to include their security
49+ * context
50+ */
51+ FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
4452 };
4553
4654 #ifdef BINDER_IPC_32BIT
@@ -218,6 +226,7 @@ struct binder_node_info_for_ref { · 171 unmodified lines
218226 #define BINDER_VERSION _IOWR('b', 9, struct binder_version)
219227 #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
220228 #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref)
229+#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
221230
222231 /*
223232 * NOTE: Two special error codes you should check for when calling
@@ -276,6 +285,11 @@ struct binder_transaction_data { · 52 unmodified lines
276285 } data;
277286 };
278287
288+struct binder_transaction_data_secctx {
289+ struct binder_transaction_data transaction_data;
290+ binder_uintptr_t secctx;
291+};
292+
279293 struct binder_transaction_data_sg {
280294 struct binder_transaction_data transaction_data;
281295 binder_size_t buffers_size;
@@ -311,6 +325,11 @@ enum binder_driver_return_protocol { · 29 unmodified lines
311325 BR_OK = _IO('r', 1),
312326 /* No parameters! */
313327
328+ BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
329+ struct binder_transaction_data_secctx),
330+ /*
331+ * binder_transaction_data_secctx: the received command.
332+ */
314333 BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
315334 BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
316335 /*