Skip to content

Commit 6d98eb9

Browse files
toddkjosgregkh
authored andcommitted
binder: avoid potential data leakage when copying txn
Transactions are copied from the sender to the target first and objects like BINDER_TYPE_PTR and BINDER_TYPE_FDA are then fixed up. This means there is a short period where the sender's version of these objects are visible to the target prior to the fixups. Instead of copying all of the data first, copy data only after any needed fixups have been applied. Fixes: 457b9a6 ("Staging: android: add binder driver") Reviewed-by: Martijn Coenen <[email protected]> Acked-by: Christian Brauner <[email protected]> Signed-off-by: Todd Kjos <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fe6b186 commit 6d98eb9

File tree

1 file changed

+70
-24
lines changed

1 file changed

+70
-24
lines changed

drivers/android/binder.c

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,15 +1608,21 @@ static void binder_cleanup_transaction(struct binder_transaction *t,
16081608
/**
16091609
* binder_get_object() - gets object and checks for valid metadata
16101610
* @proc: binder_proc owning the buffer
1611+
* @u: sender's user pointer to base of buffer
16111612
* @buffer: binder_buffer that we're parsing.
16121613
* @offset: offset in the @buffer at which to validate an object.
16131614
* @object: struct binder_object to read into
16141615
*
1615-
* Return: If there's a valid metadata object at @offset in @buffer, the
1616+
* Copy the binder object at the given offset into @object. If @u is
1617+
* provided then the copy is from the sender's buffer. If not, then
1618+
* it is copied from the target's @buffer.
1619+
*
1620+
* Return: If there's a valid metadata object at @offset, the
16161621
* size of that object. Otherwise, it returns zero. The object
16171622
* is read into the struct binder_object pointed to by @object.
16181623
*/
16191624
static size_t binder_get_object(struct binder_proc *proc,
1625+
const void __user *u,
16201626
struct binder_buffer *buffer,
16211627
unsigned long offset,
16221628
struct binder_object *object)
@@ -1626,10 +1632,16 @@ static size_t binder_get_object(struct binder_proc *proc,
16261632
size_t object_size = 0;
16271633

16281634
read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset);
1629-
if (offset > buffer->data_size || read_size < sizeof(*hdr) ||
1630-
binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
1631-
offset, read_size))
1635+
if (offset > buffer->data_size || read_size < sizeof(*hdr))
16321636
return 0;
1637+
if (u) {
1638+
if (copy_from_user(object, u + offset, read_size))
1639+
return 0;
1640+
} else {
1641+
if (binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
1642+
offset, read_size))
1643+
return 0;
1644+
}
16331645

16341646
/* Ok, now see if we read a complete object. */
16351647
hdr = &object->hdr;
@@ -1702,7 +1714,7 @@ static struct binder_buffer_object *binder_validate_ptr(
17021714
b, buffer_offset,
17031715
sizeof(object_offset)))
17041716
return NULL;
1705-
object_size = binder_get_object(proc, b, object_offset, object);
1717+
object_size = binder_get_object(proc, NULL, b, object_offset, object);
17061718
if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
17071719
return NULL;
17081720
if (object_offsetp)
@@ -1767,7 +1779,8 @@ static bool binder_validate_fixup(struct binder_proc *proc,
17671779
unsigned long buffer_offset;
17681780
struct binder_object last_object;
17691781
struct binder_buffer_object *last_bbo;
1770-
size_t object_size = binder_get_object(proc, b, last_obj_offset,
1782+
size_t object_size = binder_get_object(proc, NULL, b,
1783+
last_obj_offset,
17711784
&last_object);
17721785
if (object_size != sizeof(*last_bbo))
17731786
return false;
@@ -1882,7 +1895,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
18821895
if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
18831896
buffer, buffer_offset,
18841897
sizeof(object_offset)))
1885-
object_size = binder_get_object(proc, buffer,
1898+
object_size = binder_get_object(proc, NULL, buffer,
18861899
object_offset, &object);
18871900
if (object_size == 0) {
18881901
pr_err("transaction release %d bad object at offset %lld, size %zd\n",
@@ -2455,6 +2468,7 @@ static void binder_transaction(struct binder_proc *proc,
24552468
binder_size_t off_start_offset, off_end_offset;
24562469
binder_size_t off_min;
24572470
binder_size_t sg_buf_offset, sg_buf_end_offset;
2471+
binder_size_t user_offset = 0;
24582472
struct binder_proc *target_proc = NULL;
24592473
struct binder_thread *target_thread = NULL;
24602474
struct binder_node *target_node = NULL;
@@ -2469,6 +2483,8 @@ static void binder_transaction(struct binder_proc *proc,
24692483
int t_debug_id = atomic_inc_return(&binder_last_id);
24702484
char *secctx = NULL;
24712485
u32 secctx_sz = 0;
2486+
const void __user *user_buffer = (const void __user *)
2487+
(uintptr_t)tr->data.ptr.buffer;
24722488

24732489
e = binder_transaction_log_add(&binder_transaction_log);
24742490
e->debug_id = t_debug_id;
@@ -2780,19 +2796,6 @@ static void binder_transaction(struct binder_proc *proc,
27802796
t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF);
27812797
trace_binder_transaction_alloc_buf(t->buffer);
27822798

2783-
if (binder_alloc_copy_user_to_buffer(
2784-
&target_proc->alloc,
2785-
t->buffer, 0,
2786-
(const void __user *)
2787-
(uintptr_t)tr->data.ptr.buffer,
2788-
tr->data_size)) {
2789-
binder_user_error("%d:%d got transaction with invalid data ptr\n",
2790-
proc->pid, thread->pid);
2791-
return_error = BR_FAILED_REPLY;
2792-
return_error_param = -EFAULT;
2793-
return_error_line = __LINE__;
2794-
goto err_copy_data_failed;
2795-
}
27962799
if (binder_alloc_copy_user_to_buffer(
27972800
&target_proc->alloc,
27982801
t->buffer,
@@ -2837,6 +2840,7 @@ static void binder_transaction(struct binder_proc *proc,
28372840
size_t object_size;
28382841
struct binder_object object;
28392842
binder_size_t object_offset;
2843+
binder_size_t copy_size;
28402844

28412845
if (binder_alloc_copy_from_buffer(&target_proc->alloc,
28422846
&object_offset,
@@ -2848,8 +2852,27 @@ static void binder_transaction(struct binder_proc *proc,
28482852
return_error_line = __LINE__;
28492853
goto err_bad_offset;
28502854
}
2851-
object_size = binder_get_object(target_proc, t->buffer,
2852-
object_offset, &object);
2855+
2856+
/*
2857+
* Copy the source user buffer up to the next object
2858+
* that will be processed.
2859+
*/
2860+
copy_size = object_offset - user_offset;
2861+
if (copy_size && (user_offset > object_offset ||
2862+
binder_alloc_copy_user_to_buffer(
2863+
&target_proc->alloc,
2864+
t->buffer, user_offset,
2865+
user_buffer + user_offset,
2866+
copy_size))) {
2867+
binder_user_error("%d:%d got transaction with invalid data ptr\n",
2868+
proc->pid, thread->pid);
2869+
return_error = BR_FAILED_REPLY;
2870+
return_error_param = -EFAULT;
2871+
return_error_line = __LINE__;
2872+
goto err_copy_data_failed;
2873+
}
2874+
object_size = binder_get_object(target_proc, user_buffer,
2875+
t->buffer, object_offset, &object);
28532876
if (object_size == 0 || object_offset < off_min) {
28542877
binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n",
28552878
proc->pid, thread->pid,
@@ -2861,6 +2884,11 @@ static void binder_transaction(struct binder_proc *proc,
28612884
return_error_line = __LINE__;
28622885
goto err_bad_offset;
28632886
}
2887+
/*
2888+
* Set offset to the next buffer fragment to be
2889+
* copied
2890+
*/
2891+
user_offset = object_offset + object_size;
28642892

28652893
hdr = &object.hdr;
28662894
off_min = object_offset + object_size;
@@ -2956,9 +2984,14 @@ static void binder_transaction(struct binder_proc *proc,
29562984
}
29572985
ret = binder_translate_fd_array(fda, parent, t, thread,
29582986
in_reply_to);
2959-
if (ret < 0) {
2987+
if (!ret)
2988+
ret = binder_alloc_copy_to_buffer(&target_proc->alloc,
2989+
t->buffer,
2990+
object_offset,
2991+
fda, sizeof(*fda));
2992+
if (ret) {
29602993
return_error = BR_FAILED_REPLY;
2961-
return_error_param = ret;
2994+
return_error_param = ret > 0 ? -EINVAL : ret;
29622995
return_error_line = __LINE__;
29632996
goto err_translate_failed;
29642997
}
@@ -3028,6 +3061,19 @@ static void binder_transaction(struct binder_proc *proc,
30283061
goto err_bad_object_type;
30293062
}
30303063
}
3064+
/* Done processing objects, copy the rest of the buffer */
3065+
if (binder_alloc_copy_user_to_buffer(
3066+
&target_proc->alloc,
3067+
t->buffer, user_offset,
3068+
user_buffer + user_offset,
3069+
tr->data_size - user_offset)) {
3070+
binder_user_error("%d:%d got transaction with invalid data ptr\n",
3071+
proc->pid, thread->pid);
3072+
return_error = BR_FAILED_REPLY;
3073+
return_error_param = -EFAULT;
3074+
return_error_line = __LINE__;
3075+
goto err_copy_data_failed;
3076+
}
30313077
if (t->buffer->oneway_spam_suspect)
30323078
tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT;
30333079
else

0 commit comments

Comments
 (0)