Skip to content

Commit bb4a2e4

Browse files
Todd Kjosgregkh
authored andcommitted
binder: return errors from buffer copy functions
The buffer copy functions assumed the caller would ensure correct alignment and that the memory to be copied was completely within the binder buffer. There have been a few cases discovered by syzkallar where a malformed transaction created by a user could violated the assumptions and resulted in a BUG_ON. The fix is to remove the BUG_ON and always return the error to be handled appropriately by the caller. Acked-by: Martijn Coenen <[email protected]> Reported-by: [email protected] Fixes: bde4a19 ("binder: use userspace pointer as base of buffer space") Suggested-by: Dan Carpenter <[email protected]> Signed-off-by: Todd Kjos <[email protected]> Cc: stable <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 25c7eab commit bb4a2e4

File tree

3 files changed

+126
-93
lines changed

3 files changed

+126
-93
lines changed

drivers/android/binder.c

Lines changed: 92 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,10 +2059,9 @@ static size_t binder_get_object(struct binder_proc *proc,
20592059

20602060
read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset);
20612061
if (offset > buffer->data_size || read_size < sizeof(*hdr) ||
2062-
!IS_ALIGNED(offset, sizeof(u32)))
2062+
binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
2063+
offset, read_size))
20632064
return 0;
2064-
binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
2065-
offset, read_size);
20662065

20672066
/* Ok, now see if we read a complete object. */
20682067
hdr = &object->hdr;
@@ -2131,8 +2130,10 @@ static struct binder_buffer_object *binder_validate_ptr(
21312130
return NULL;
21322131

21332132
buffer_offset = start_offset + sizeof(binder_size_t) * index;
2134-
binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
2135-
b, buffer_offset, sizeof(object_offset));
2133+
if (binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
2134+
b, buffer_offset,
2135+
sizeof(object_offset)))
2136+
return NULL;
21362137
object_size = binder_get_object(proc, b, object_offset, object);
21372138
if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
21382139
return NULL;
@@ -2212,10 +2213,12 @@ static bool binder_validate_fixup(struct binder_proc *proc,
22122213
return false;
22132214
last_min_offset = last_bbo->parent_offset + sizeof(uintptr_t);
22142215
buffer_offset = objects_start_offset +
2215-
sizeof(binder_size_t) * last_bbo->parent,
2216-
binder_alloc_copy_from_buffer(&proc->alloc, &last_obj_offset,
2217-
b, buffer_offset,
2218-
sizeof(last_obj_offset));
2216+
sizeof(binder_size_t) * last_bbo->parent;
2217+
if (binder_alloc_copy_from_buffer(&proc->alloc,
2218+
&last_obj_offset,
2219+
b, buffer_offset,
2220+
sizeof(last_obj_offset)))
2221+
return false;
22192222
}
22202223
return (fixup_offset >= last_min_offset);
22212224
}
@@ -2301,15 +2304,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
23012304
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
23022305
buffer_offset += sizeof(binder_size_t)) {
23032306
struct binder_object_header *hdr;
2304-
size_t object_size;
2307+
size_t object_size = 0;
23052308
struct binder_object object;
23062309
binder_size_t object_offset;
23072310

2308-
binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
2309-
buffer, buffer_offset,
2310-
sizeof(object_offset));
2311-
object_size = binder_get_object(proc, buffer,
2312-
object_offset, &object);
2311+
if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
2312+
buffer, buffer_offset,
2313+
sizeof(object_offset)))
2314+
object_size = binder_get_object(proc, buffer,
2315+
object_offset, &object);
23132316
if (object_size == 0) {
23142317
pr_err("transaction release %d bad object at offset %lld, size %zd\n",
23152318
debug_id, (u64)object_offset, buffer->data_size);
@@ -2432,15 +2435,16 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
24322435
for (fd_index = 0; fd_index < fda->num_fds;
24332436
fd_index++) {
24342437
u32 fd;
2438+
int err;
24352439
binder_size_t offset = fda_offset +
24362440
fd_index * sizeof(fd);
24372441

2438-
binder_alloc_copy_from_buffer(&proc->alloc,
2439-
&fd,
2440-
buffer,
2441-
offset,
2442-
sizeof(fd));
2443-
binder_deferred_fd_close(fd);
2442+
err = binder_alloc_copy_from_buffer(
2443+
&proc->alloc, &fd, buffer,
2444+
offset, sizeof(fd));
2445+
WARN_ON(err);
2446+
if (!err)
2447+
binder_deferred_fd_close(fd);
24442448
}
24452449
} break;
24462450
default:
@@ -2683,11 +2687,12 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
26832687
int ret;
26842688
binder_size_t offset = fda_offset + fdi * sizeof(fd);
26852689

2686-
binder_alloc_copy_from_buffer(&target_proc->alloc,
2687-
&fd, t->buffer,
2688-
offset, sizeof(fd));
2689-
ret = binder_translate_fd(fd, offset, t, thread,
2690-
in_reply_to);
2690+
ret = binder_alloc_copy_from_buffer(&target_proc->alloc,
2691+
&fd, t->buffer,
2692+
offset, sizeof(fd));
2693+
if (!ret)
2694+
ret = binder_translate_fd(fd, offset, t, thread,
2695+
in_reply_to);
26912696
if (ret < 0)
26922697
return ret;
26932698
}
@@ -2740,8 +2745,12 @@ static int binder_fixup_parent(struct binder_transaction *t,
27402745
}
27412746
buffer_offset = bp->parent_offset +
27422747
(uintptr_t)parent->buffer - (uintptr_t)b->user_data;
2743-
binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
2744-
&bp->buffer, sizeof(bp->buffer));
2748+
if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
2749+
&bp->buffer, sizeof(bp->buffer))) {
2750+
binder_user_error("%d:%d got transaction with invalid parent offset\n",
2751+
proc->pid, thread->pid);
2752+
return -EINVAL;
2753+
}
27452754

27462755
return 0;
27472756
}
@@ -3160,15 +3169,20 @@ static void binder_transaction(struct binder_proc *proc,
31603169
goto err_binder_alloc_buf_failed;
31613170
}
31623171
if (secctx) {
3172+
int err;
31633173
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
31643174
ALIGN(tr->offsets_size, sizeof(void *)) +
31653175
ALIGN(extra_buffers_size, sizeof(void *)) -
31663176
ALIGN(secctx_sz, sizeof(u64));
31673177

31683178
t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
3169-
binder_alloc_copy_to_buffer(&target_proc->alloc,
3170-
t->buffer, buf_offset,
3171-
secctx, secctx_sz);
3179+
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
3180+
t->buffer, buf_offset,
3181+
secctx, secctx_sz);
3182+
if (err) {
3183+
t->security_ctx = 0;
3184+
WARN_ON(1);
3185+
}
31723186
security_release_secctx(secctx, secctx_sz);
31733187
secctx = NULL;
31743188
}
@@ -3234,11 +3248,16 @@ static void binder_transaction(struct binder_proc *proc,
32343248
struct binder_object object;
32353249
binder_size_t object_offset;
32363250

3237-
binder_alloc_copy_from_buffer(&target_proc->alloc,
3238-
&object_offset,
3239-
t->buffer,
3240-
buffer_offset,
3241-
sizeof(object_offset));
3251+
if (binder_alloc_copy_from_buffer(&target_proc->alloc,
3252+
&object_offset,
3253+
t->buffer,
3254+
buffer_offset,
3255+
sizeof(object_offset))) {
3256+
return_error = BR_FAILED_REPLY;
3257+
return_error_param = -EINVAL;
3258+
return_error_line = __LINE__;
3259+
goto err_bad_offset;
3260+
}
32423261
object_size = binder_get_object(target_proc, t->buffer,
32433262
object_offset, &object);
32443263
if (object_size == 0 || object_offset < off_min) {
@@ -3262,31 +3281,34 @@ static void binder_transaction(struct binder_proc *proc,
32623281

32633282
fp = to_flat_binder_object(hdr);
32643283
ret = binder_translate_binder(fp, t, thread);
3265-
if (ret < 0) {
3284+
3285+
if (ret < 0 ||
3286+
binder_alloc_copy_to_buffer(&target_proc->alloc,
3287+
t->buffer,
3288+
object_offset,
3289+
fp, sizeof(*fp))) {
32663290
return_error = BR_FAILED_REPLY;
32673291
return_error_param = ret;
32683292
return_error_line = __LINE__;
32693293
goto err_translate_failed;
32703294
}
3271-
binder_alloc_copy_to_buffer(&target_proc->alloc,
3272-
t->buffer, object_offset,
3273-
fp, sizeof(*fp));
32743295
} break;
32753296
case BINDER_TYPE_HANDLE:
32763297
case BINDER_TYPE_WEAK_HANDLE: {
32773298
struct flat_binder_object *fp;
32783299

32793300
fp = to_flat_binder_object(hdr);
32803301
ret = binder_translate_handle(fp, t, thread);
3281-
if (ret < 0) {
3302+
if (ret < 0 ||
3303+
binder_alloc_copy_to_buffer(&target_proc->alloc,
3304+
t->buffer,
3305+
object_offset,
3306+
fp, sizeof(*fp))) {
32823307
return_error = BR_FAILED_REPLY;
32833308
return_error_param = ret;
32843309
return_error_line = __LINE__;
32853310
goto err_translate_failed;
32863311
}
3287-
binder_alloc_copy_to_buffer(&target_proc->alloc,
3288-
t->buffer, object_offset,
3289-
fp, sizeof(*fp));
32903312
} break;
32913313

32923314
case BINDER_TYPE_FD: {
@@ -3296,16 +3318,17 @@ static void binder_transaction(struct binder_proc *proc,
32963318
int ret = binder_translate_fd(fp->fd, fd_offset, t,
32973319
thread, in_reply_to);
32983320

3299-
if (ret < 0) {
3321+
fp->pad_binder = 0;
3322+
if (ret < 0 ||
3323+
binder_alloc_copy_to_buffer(&target_proc->alloc,
3324+
t->buffer,
3325+
object_offset,
3326+
fp, sizeof(*fp))) {
33003327
return_error = BR_FAILED_REPLY;
33013328
return_error_param = ret;
33023329
return_error_line = __LINE__;
33033330
goto err_translate_failed;
33043331
}
3305-
fp->pad_binder = 0;
3306-
binder_alloc_copy_to_buffer(&target_proc->alloc,
3307-
t->buffer, object_offset,
3308-
fp, sizeof(*fp));
33093332
} break;
33103333
case BINDER_TYPE_FDA: {
33113334
struct binder_object ptr_object;
@@ -3393,15 +3416,16 @@ static void binder_transaction(struct binder_proc *proc,
33933416
num_valid,
33943417
last_fixup_obj_off,
33953418
last_fixup_min_off);
3396-
if (ret < 0) {
3419+
if (ret < 0 ||
3420+
binder_alloc_copy_to_buffer(&target_proc->alloc,
3421+
t->buffer,
3422+
object_offset,
3423+
bp, sizeof(*bp))) {
33973424
return_error = BR_FAILED_REPLY;
33983425
return_error_param = ret;
33993426
return_error_line = __LINE__;
34003427
goto err_translate_failed;
34013428
}
3402-
binder_alloc_copy_to_buffer(&target_proc->alloc,
3403-
t->buffer, object_offset,
3404-
bp, sizeof(*bp));
34053429
last_fixup_obj_off = object_offset;
34063430
last_fixup_min_off = 0;
34073431
} break;
@@ -4140,20 +4164,27 @@ static int binder_apply_fd_fixups(struct binder_proc *proc,
41404164
trace_binder_transaction_fd_recv(t, fd, fixup->offset);
41414165
fd_install(fd, fixup->file);
41424166
fixup->file = NULL;
4143-
binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
4144-
fixup->offset, &fd,
4145-
sizeof(u32));
4167+
if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
4168+
fixup->offset, &fd,
4169+
sizeof(u32))) {
4170+
ret = -EINVAL;
4171+
break;
4172+
}
41464173
}
41474174
list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
41484175
if (fixup->file) {
41494176
fput(fixup->file);
41504177
} else if (ret) {
41514178
u32 fd;
4152-
4153-
binder_alloc_copy_from_buffer(&proc->alloc, &fd,
4154-
t->buffer, fixup->offset,
4155-
sizeof(fd));
4156-
binder_deferred_fd_close(fd);
4179+
int err;
4180+
4181+
err = binder_alloc_copy_from_buffer(&proc->alloc, &fd,
4182+
t->buffer,
4183+
fixup->offset,
4184+
sizeof(fd));
4185+
WARN_ON(err);
4186+
if (!err)
4187+
binder_deferred_fd_close(fd);
41574188
}
41584189
list_del(&fixup->fixup_entry);
41594190
kfree(fixup);

drivers/android/binder_alloc.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,15 +1119,16 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
11191119
return 0;
11201120
}
11211121

1122-
static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
1123-
bool to_buffer,
1124-
struct binder_buffer *buffer,
1125-
binder_size_t buffer_offset,
1126-
void *ptr,
1127-
size_t bytes)
1122+
static int binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
1123+
bool to_buffer,
1124+
struct binder_buffer *buffer,
1125+
binder_size_t buffer_offset,
1126+
void *ptr,
1127+
size_t bytes)
11281128
{
11291129
/* All copies must be 32-bit aligned and 32-bit size */
1130-
BUG_ON(!check_buffer(alloc, buffer, buffer_offset, bytes));
1130+
if (!check_buffer(alloc, buffer, buffer_offset, bytes))
1131+
return -EINVAL;
11311132

11321133
while (bytes) {
11331134
unsigned long size;
@@ -1155,25 +1156,26 @@ static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
11551156
ptr = ptr + size;
11561157
buffer_offset += size;
11571158
}
1159+
return 0;
11581160
}
11591161

1160-
void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
1161-
struct binder_buffer *buffer,
1162-
binder_size_t buffer_offset,
1163-
void *src,
1164-
size_t bytes)
1162+
int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
1163+
struct binder_buffer *buffer,
1164+
binder_size_t buffer_offset,
1165+
void *src,
1166+
size_t bytes)
11651167
{
1166-
binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
1167-
src, bytes);
1168+
return binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
1169+
src, bytes);
11681170
}
11691171

1170-
void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
1171-
void *dest,
1172-
struct binder_buffer *buffer,
1173-
binder_size_t buffer_offset,
1174-
size_t bytes)
1172+
int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
1173+
void *dest,
1174+
struct binder_buffer *buffer,
1175+
binder_size_t buffer_offset,
1176+
size_t bytes)
11751177
{
1176-
binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
1177-
dest, bytes);
1178+
return binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
1179+
dest, bytes);
11781180
}
11791181

drivers/android/binder_alloc.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,17 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
159159
const void __user *from,
160160
size_t bytes);
161161

162-
void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
163-
struct binder_buffer *buffer,
164-
binder_size_t buffer_offset,
165-
void *src,
166-
size_t bytes);
167-
168-
void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
169-
void *dest,
170-
struct binder_buffer *buffer,
171-
binder_size_t buffer_offset,
172-
size_t bytes);
162+
int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
163+
struct binder_buffer *buffer,
164+
binder_size_t buffer_offset,
165+
void *src,
166+
size_t bytes);
167+
168+
int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
169+
void *dest,
170+
struct binder_buffer *buffer,
171+
binder_size_t buffer_offset,
172+
size_t bytes);
173173

174174
#endif /* _LINUX_BINDER_ALLOC_H */
175175

0 commit comments

Comments
 (0)