Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00bac145 authored by Todd Kjos's avatar Todd Kjos Committed by Todd Kjos
Browse files

FROMGIT: 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: default avatarTodd Kjos <tkjos@google.com>
Reviewed-by: default avatarJoel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>

(cherry picked from commit ec74136ded792deed80780a2f8baf3521eeb72f9
 https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git


 master)
Change-Id: I44496546e2d0dc0022f818a45cd52feb1c1a92cb
Signed-off-by: default avatarTodd Kjos <tkjos@google.com>
parent c97d2b53
Loading
Loading
Loading
Loading
+82 −23
Original line number Diff line number Diff line
@@ -358,6 +358,7 @@ struct binder_error {
 * @min_priority:         minimum scheduling priority
 *                        (invariant after initialized)
 * @inherit_rt:           inherit RT scheduling policy from caller
 * @txn_security_ctx:     require sender's security context
 *                        (invariant after initialized)
 * @async_todo:           list of async work items
 *                        (protected by @proc->inner_lock)
@@ -397,6 +398,7 @@ struct binder_node {
		u8 sched_policy:2;
		u8 inherit_rt:1;
		u8 accept_fds:1;
		u8 txn_security_ctx:1;
		u8 min_priority;
	};
	bool has_async_transaction;
@@ -654,6 +656,7 @@ struct binder_transaction {
	struct binder_priority	saved_priority;
	bool    set_priority_called;
	kuid_t	sender_euid;
	binder_uintptr_t security_ctx;
	/**
	 * @lock:  protects @from, @to_proc, and @to_thread
	 *
@@ -1363,6 +1366,7 @@ static struct binder_node *binder_init_node_ilocked(
	node->min_priority = to_kernel_prio(node->sched_policy, priority);
	node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
	node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);
	node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX);
	spin_lock_init(&node->lock);
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
@@ -2900,6 +2904,8 @@ static void binder_transaction(struct binder_proc *proc,
	binder_size_t last_fixup_min_off = 0;
	struct binder_context *context = proc->context;
	int t_debug_id = atomic_inc_return(&binder_last_id);
	char *secctx = NULL;
	u32 secctx_sz = 0;

	e = binder_transaction_log_add(&binder_transaction_log);
	e->debug_id = t_debug_id;
@@ -3123,6 +3129,20 @@ static void binder_transaction(struct binder_proc *proc,
		t->priority = target_proc->default_priority;
	}

	if (target_node && target_node->txn_security_ctx) {
		u32 secid;

		security_task_getsecid(proc->tsk, &secid);
		ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
		if (ret) {
			return_error = BR_FAILED_REPLY;
			return_error_param = ret;
			return_error_line = __LINE__;
			goto err_get_secctx_failed;
		}
		extra_buffers_size += ALIGN(secctx_sz, sizeof(u64));
	}

	trace_binder_transaction(reply, t, target_node);

	t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
@@ -3139,6 +3159,19 @@ static void binder_transaction(struct binder_proc *proc,
		t->buffer = NULL;
		goto err_binder_alloc_buf_failed;
	}
	if (secctx) {
		size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
				    ALIGN(tr->offsets_size, sizeof(void *)) +
				    ALIGN(extra_buffers_size, sizeof(void *)) -
				    ALIGN(secctx_sz, sizeof(u64));
		char *kptr = t->buffer->data + buf_offset;

		t->security_ctx = (uintptr_t)kptr +
		    binder_alloc_get_user_buffer_offset(&target_proc->alloc);
		memcpy(kptr, secctx, secctx_sz);
		security_release_secctx(secctx, secctx_sz);
		secctx = NULL;
	}
	t->buffer->debug_id = t->debug_id;
	t->buffer->transaction = t;
	t->buffer->target_node = target_node;
@@ -3409,6 +3442,9 @@ static void binder_transaction(struct binder_proc *proc,
	t->buffer->transaction = NULL;
	binder_alloc_free_buf(&target_proc->alloc, t->buffer);
err_binder_alloc_buf_failed:
	if (secctx)
		security_release_secctx(secctx, secctx_sz);
err_get_secctx_failed:
	kfree(tcomplete);
	binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
err_alloc_tcomplete_failed:
@@ -4055,11 +4091,13 @@ static int binder_thread_read(struct binder_proc *proc,

	while (1) {
		uint32_t cmd;
		struct binder_transaction_data tr;
		struct binder_transaction_data_secctx tr;
		struct binder_transaction_data *trd = &tr.transaction_data;
		struct binder_work *w = NULL;
		struct list_head *list = NULL;
		struct binder_transaction *t = NULL;
		struct binder_thread *t_from;
		size_t trsize = sizeof(*trd);

		binder_inner_proc_lock(proc);
		if (!binder_worklist_empty_ilocked(&thread->todo))
@@ -4255,41 +4293,47 @@ static int binder_thread_read(struct binder_proc *proc,
			struct binder_node *target_node = t->buffer->target_node;
			struct binder_priority node_prio;

			tr.target.ptr = target_node->ptr;
			tr.cookie =  target_node->cookie;
			trd->target.ptr = target_node->ptr;
			trd->cookie =  target_node->cookie;
			node_prio.sched_policy = target_node->sched_policy;
			node_prio.prio = target_node->min_priority;
			binder_transaction_priority(current, t, node_prio,
						    target_node->inherit_rt);
			cmd = BR_TRANSACTION;
		} else {
			tr.target.ptr = 0;
			tr.cookie = 0;
			trd->target.ptr = 0;
			trd->cookie = 0;
			cmd = BR_REPLY;
		}
		tr.code = t->code;
		tr.flags = t->flags;
		tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
		trd->code = t->code;
		trd->flags = t->flags;
		trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);

		t_from = binder_get_txn_from(t);
		if (t_from) {
			struct task_struct *sender = t_from->proc->tsk;

			tr.sender_pid = task_tgid_nr_ns(sender,
			trd->sender_pid =
				task_tgid_nr_ns(sender,
						task_active_pid_ns(current));
		} else {
			tr.sender_pid = 0;
			trd->sender_pid = 0;
		}

		tr.data_size = t->buffer->data_size;
		tr.offsets_size = t->buffer->offsets_size;
		tr.data.ptr.buffer = (binder_uintptr_t)
		trd->data_size = t->buffer->data_size;
		trd->offsets_size = t->buffer->offsets_size;
		trd->data.ptr.buffer = (binder_uintptr_t)
			((uintptr_t)t->buffer->data +
			binder_alloc_get_user_buffer_offset(&proc->alloc));
		tr.data.ptr.offsets = tr.data.ptr.buffer +
		trd->data.ptr.offsets = trd->data.ptr.buffer +
					ALIGN(t->buffer->data_size,
					    sizeof(void *));

		tr.secctx = t->security_ctx;
		if (t->security_ctx) {
			cmd = BR_TRANSACTION_SEC_CTX;
			trsize = sizeof(tr);
		}
		if (put_user(cmd, (uint32_t __user *)ptr)) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);
@@ -4300,7 +4344,7 @@ static int binder_thread_read(struct binder_proc *proc,
			return -EFAULT;
		}
		ptr += sizeof(uint32_t);
		if (copy_to_user(ptr, &tr, sizeof(tr))) {
		if (copy_to_user(ptr, &tr, trsize)) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);

@@ -4309,7 +4353,7 @@ static int binder_thread_read(struct binder_proc *proc,

			return -EFAULT;
		}
		ptr += sizeof(tr);
		ptr += trsize;

		trace_binder_transaction_received(t);
		binder_stat_br(proc, thread, cmd);
@@ -4317,16 +4361,18 @@ static int binder_thread_read(struct binder_proc *proc,
			     "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
			     proc->pid, thread->pid,
			     (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
			     "BR_REPLY",
				(cmd == BR_TRANSACTION_SEC_CTX) ?
				     "BR_TRANSACTION_SEC_CTX" : "BR_REPLY",
			     t->debug_id, t_from ? t_from->proc->pid : 0,
			     t_from ? t_from->pid : 0, cmd,
			     t->buffer->data_size, t->buffer->offsets_size,
			     (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
			     (u64)trd->data.ptr.buffer,
			     (u64)trd->data.ptr.offsets);

		if (t_from)
			binder_thread_dec_tmpref(t_from);
		t->buffer->allow_user_free = 1;
		if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
		if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) {
			binder_inner_proc_lock(thread->proc);
			t->to_parent = thread->transaction_stack;
			t->to_thread = thread;
@@ -4671,7 +4717,8 @@ static int binder_ioctl_write_read(struct file *filp,
	return ret;
}

static int binder_ioctl_set_ctx_mgr(struct file *filp)
static int binder_ioctl_set_ctx_mgr(struct file *filp,
				    struct flat_binder_object *fbo)
{
	int ret = 0;
	struct binder_proc *proc = filp->private_data;
@@ -4700,7 +4747,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
	} else {
		context->binder_context_mgr_uid = curr_euid;
	}
	new_node = binder_new_node(proc, NULL);
	new_node = binder_new_node(proc, fbo);
	if (!new_node) {
		ret = -ENOMEM;
		goto out;
@@ -4823,8 +4870,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		binder_inner_proc_unlock(proc);
		break;
	}
	case BINDER_SET_CONTEXT_MGR_EXT: {
		struct flat_binder_object fbo;

		if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {
			ret = -EINVAL;
			goto err;
		}
		ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
		if (ret)
			goto err;
		break;
	}
	case BINDER_SET_CONTEXT_MGR:
		ret = binder_ioctl_set_ctx_mgr(filp);
		ret = binder_ioctl_set_ctx_mgr(filp, NULL);
		if (ret)
			goto err;
		break;
+19 −0
Original line number Diff line number Diff line
@@ -88,6 +88,14 @@ enum flat_binder_object_flags {
	 * scheduling policy from the caller (for synchronous transactions).
	 */
	FLAT_BINDER_FLAG_INHERIT_RT = 0x800,

	/**
	 * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts
	 *
	 * Only when set, causes senders to include their security
	 * context
	 */
	FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
};

#ifdef BINDER_IPC_32BIT
@@ -265,6 +273,7 @@ struct binder_node_info_for_ref {
#define BINDER_VERSION			_IOWR('b', 9, struct binder_version)
#define BINDER_GET_NODE_DEBUG_INFO	_IOWR('b', 11, struct binder_node_debug_info)
#define BINDER_GET_NODE_INFO_FOR_REF	_IOWR('b', 12, struct binder_node_info_for_ref)
#define BINDER_SET_CONTEXT_MGR_EXT	_IOW('b', 13, struct flat_binder_object)

/*
 * NOTE: Two special error codes you should check for when calling
@@ -323,6 +332,11 @@ struct binder_transaction_data {
	} data;
};

struct binder_transaction_data_secctx {
	struct binder_transaction_data transaction_data;
	binder_uintptr_t secctx;
};

struct binder_transaction_data_sg {
	struct binder_transaction_data transaction_data;
	binder_size_t buffers_size;
@@ -358,6 +372,11 @@ enum binder_driver_return_protocol {
	BR_OK = _IO('r', 1),
	/* No parameters! */

	BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
				      struct binder_transaction_data_secctx),
	/*
	 * binder_transaction_data_secctx: the received command.
	 */
	BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
	BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
	/*