diff options
author | Todd Kjos <tkjos@android.com> | 2017-06-29 15:01:59 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-17 08:48:23 -0400 |
commit | adc1884222276df6eb018f78bccacbcd78a0b9f6 (patch) | |
tree | 3b041b13a03729009bd2fa063fc2163bc27aac0f /drivers/android/binder.c | |
parent | 372e3147df7016ebeaa372939e8774a1292db558 (diff) |
binder: use node->tmp_refs to ensure node safety
When obtaining a node via binder_get_node(),
binder_get_node_from_ref() or binder_new_node(),
increment node->tmp_refs to take a
temporary reference on the node to ensure the node
persists while being used. binder_put_node() must
be called to remove the temporary reference.
Signed-off-by: Todd Kjos <tkjos@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android/binder.c')
-rw-r--r-- | drivers/android/binder.c | 124 |
1 files changed, 104 insertions, 20 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4d0b99862339..ec050c6d1192 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
@@ -274,6 +274,7 @@ struct binder_node { | |||
274 | int internal_strong_refs; | 274 | int internal_strong_refs; |
275 | int local_weak_refs; | 275 | int local_weak_refs; |
276 | int local_strong_refs; | 276 | int local_strong_refs; |
277 | int tmp_refs; | ||
277 | binder_uintptr_t ptr; | 278 | binder_uintptr_t ptr; |
278 | binder_uintptr_t cookie; | 279 | binder_uintptr_t cookie; |
279 | unsigned has_strong_ref:1; | 280 | unsigned has_strong_ref:1; |
@@ -427,6 +428,7 @@ static void | |||
427 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); | 428 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); |
428 | static void binder_free_thread(struct binder_thread *thread); | 429 | static void binder_free_thread(struct binder_thread *thread); |
429 | static void binder_free_proc(struct binder_proc *proc); | 430 | static void binder_free_proc(struct binder_proc *proc); |
431 | static void binder_inc_node_tmpref(struct binder_node *node); | ||
430 | 432 | ||
431 | static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) | 433 | static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) |
432 | { | 434 | { |
@@ -521,8 +523,15 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, | |||
521 | n = n->rb_left; | 523 | n = n->rb_left; |
522 | else if (ptr > node->ptr) | 524 | else if (ptr > node->ptr) |
523 | n = n->rb_right; | 525 | n = n->rb_right; |
524 | else | 526 | else { |
527 | /* | ||
528 | * take an implicit weak reference | ||
529 | * to ensure node stays alive until | ||
530 | * call to binder_put_node() | ||
531 | */ | ||
532 | binder_inc_node_tmpref(node); | ||
525 | return node; | 533 | return node; |
534 | } | ||
526 | } | 535 | } |
527 | return NULL; | 536 | return NULL; |
528 | } | 537 | } |
@@ -551,6 +560,7 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, | |||
551 | if (node == NULL) | 560 | if (node == NULL) |
552 | return NULL; | 561 | return NULL; |
553 | binder_stats_created(BINDER_STAT_NODE); | 562 | binder_stats_created(BINDER_STAT_NODE); |
563 | node->tmp_refs++; | ||
554 | rb_link_node(&node->rb_node, parent, p); | 564 | rb_link_node(&node->rb_node, parent, p); |
555 | rb_insert_color(&node->rb_node, &proc->nodes); | 565 | rb_insert_color(&node->rb_node, &proc->nodes); |
556 | node->debug_id = atomic_inc_return(&binder_last_id); | 566 | node->debug_id = atomic_inc_return(&binder_last_id); |
@@ -615,7 +625,8 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) | |||
615 | } else { | 625 | } else { |
616 | if (!internal) | 626 | if (!internal) |
617 | node->local_weak_refs--; | 627 | node->local_weak_refs--; |
618 | if (node->local_weak_refs || !hlist_empty(&node->refs)) | 628 | if (node->local_weak_refs || node->tmp_refs || |
629 | !hlist_empty(&node->refs)) | ||
619 | return 0; | 630 | return 0; |
620 | } | 631 | } |
621 | if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { | 632 | if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { |
@@ -625,7 +636,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) | |||
625 | } | 636 | } |
626 | } else { | 637 | } else { |
627 | if (hlist_empty(&node->refs) && !node->local_strong_refs && | 638 | if (hlist_empty(&node->refs) && !node->local_strong_refs && |
628 | !node->local_weak_refs) { | 639 | !node->local_weak_refs && !node->tmp_refs) { |
629 | list_del_init(&node->work.entry); | 640 | list_del_init(&node->work.entry); |
630 | if (node->proc) { | 641 | if (node->proc) { |
631 | rb_erase(&node->rb_node, &node->proc->nodes); | 642 | rb_erase(&node->rb_node, &node->proc->nodes); |
@@ -648,6 +659,46 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) | |||
648 | return 0; | 659 | return 0; |
649 | } | 660 | } |
650 | 661 | ||
662 | /** | ||
663 | * binder_inc_node_tmpref() - take a temporary reference on node | ||
664 | * @node: node to reference | ||
665 | * | ||
666 | * Take reference on node to prevent the node from being freed | ||
667 | * while referenced only by a local variable | ||
668 | */ | ||
669 | static void binder_inc_node_tmpref(struct binder_node *node) | ||
670 | { | ||
671 | /* | ||
672 | * No call to binder_inc_node() is needed since we | ||
673 | * don't need to inform userspace of any changes to | ||
674 | * tmp_refs | ||
675 | */ | ||
676 | node->tmp_refs++; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * binder_dec_node_tmpref() - remove a temporary reference on node | ||
681 | * @node: node to reference | ||
682 | * | ||
683 | * Release temporary reference on node taken via binder_inc_node_tmpref() | ||
684 | */ | ||
685 | static void binder_dec_node_tmpref(struct binder_node *node) | ||
686 | { | ||
687 | node->tmp_refs--; | ||
688 | BUG_ON(node->tmp_refs < 0); | ||
689 | /* | ||
690 | * Call binder_dec_node() to check if all refcounts are 0 | ||
691 | * and cleanup is needed. Calling with strong=0 and internal=1 | ||
692 | * causes no actual reference to be released in binder_dec_node(). | ||
693 | * If that changes, a change is needed here too. | ||
694 | */ | ||
695 | binder_dec_node(node, 0, 1); | ||
696 | } | ||
697 | |||
698 | static void binder_put_node(struct binder_node *node) | ||
699 | { | ||
700 | binder_dec_node_tmpref(node); | ||
701 | } | ||
651 | 702 | ||
652 | static struct binder_ref *binder_get_ref(struct binder_proc *proc, | 703 | static struct binder_ref *binder_get_ref(struct binder_proc *proc, |
653 | u32 desc, bool need_strong_ref) | 704 | u32 desc, bool need_strong_ref) |
@@ -888,6 +939,11 @@ static struct binder_node *binder_get_node_from_ref( | |||
888 | if (!ref) | 939 | if (!ref) |
889 | goto err_no_ref; | 940 | goto err_no_ref; |
890 | node = ref->node; | 941 | node = ref->node; |
942 | /* | ||
943 | * Take an implicit reference on the node to ensure | ||
944 | * it stays alive until the call to binder_put_node() | ||
945 | */ | ||
946 | binder_inc_node_tmpref(node); | ||
891 | if (rdata) | 947 | if (rdata) |
892 | *rdata = ref->data; | 948 | *rdata = ref->data; |
893 | 949 | ||
@@ -1348,6 +1404,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, | |||
1348 | node->debug_id, (u64)node->ptr); | 1404 | node->debug_id, (u64)node->ptr); |
1349 | binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, | 1405 | binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, |
1350 | 0); | 1406 | 0); |
1407 | binder_put_node(node); | ||
1351 | } break; | 1408 | } break; |
1352 | case BINDER_TYPE_HANDLE: | 1409 | case BINDER_TYPE_HANDLE: |
1353 | case BINDER_TYPE_WEAK_HANDLE: { | 1410 | case BINDER_TYPE_WEAK_HANDLE: { |
@@ -1441,7 +1498,7 @@ static int binder_translate_binder(struct flat_binder_object *fp, | |||
1441 | struct binder_proc *proc = thread->proc; | 1498 | struct binder_proc *proc = thread->proc; |
1442 | struct binder_proc *target_proc = t->to_proc; | 1499 | struct binder_proc *target_proc = t->to_proc; |
1443 | struct binder_ref_data rdata; | 1500 | struct binder_ref_data rdata; |
1444 | int ret; | 1501 | int ret = 0; |
1445 | 1502 | ||
1446 | node = binder_get_node(proc, fp->binder); | 1503 | node = binder_get_node(proc, fp->binder); |
1447 | if (!node) { | 1504 | if (!node) { |
@@ -1457,16 +1514,19 @@ static int binder_translate_binder(struct flat_binder_object *fp, | |||
1457 | proc->pid, thread->pid, (u64)fp->binder, | 1514 | proc->pid, thread->pid, (u64)fp->binder, |
1458 | node->debug_id, (u64)fp->cookie, | 1515 | node->debug_id, (u64)fp->cookie, |
1459 | (u64)node->cookie); | 1516 | (u64)node->cookie); |
1460 | return -EINVAL; | 1517 | ret = -EINVAL; |
1518 | goto done; | ||
1519 | } | ||
1520 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { | ||
1521 | ret = -EPERM; | ||
1522 | goto done; | ||
1461 | } | 1523 | } |
1462 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) | ||
1463 | return -EPERM; | ||
1464 | 1524 | ||
1465 | ret = binder_inc_ref_for_node(target_proc, node, | 1525 | ret = binder_inc_ref_for_node(target_proc, node, |
1466 | fp->hdr.type == BINDER_TYPE_BINDER, | 1526 | fp->hdr.type == BINDER_TYPE_BINDER, |
1467 | &thread->todo, &rdata); | 1527 | &thread->todo, &rdata); |
1468 | if (ret) | 1528 | if (ret) |
1469 | return ret; | 1529 | goto done; |
1470 | 1530 | ||
1471 | if (fp->hdr.type == BINDER_TYPE_BINDER) | 1531 | if (fp->hdr.type == BINDER_TYPE_BINDER) |
1472 | fp->hdr.type = BINDER_TYPE_HANDLE; | 1532 | fp->hdr.type = BINDER_TYPE_HANDLE; |
@@ -1481,7 +1541,9 @@ static int binder_translate_binder(struct flat_binder_object *fp, | |||
1481 | " node %d u%016llx -> ref %d desc %d\n", | 1541 | " node %d u%016llx -> ref %d desc %d\n", |
1482 | node->debug_id, (u64)node->ptr, | 1542 | node->debug_id, (u64)node->ptr, |
1483 | rdata.debug_id, rdata.desc); | 1543 | rdata.debug_id, rdata.desc); |
1484 | return 0; | 1544 | done: |
1545 | binder_put_node(node); | ||
1546 | return ret; | ||
1485 | } | 1547 | } |
1486 | 1548 | ||
1487 | static int binder_translate_handle(struct flat_binder_object *fp, | 1549 | static int binder_translate_handle(struct flat_binder_object *fp, |
@@ -1492,6 +1554,7 @@ static int binder_translate_handle(struct flat_binder_object *fp, | |||
1492 | struct binder_proc *target_proc = t->to_proc; | 1554 | struct binder_proc *target_proc = t->to_proc; |
1493 | struct binder_node *node; | 1555 | struct binder_node *node; |
1494 | struct binder_ref_data src_rdata; | 1556 | struct binder_ref_data src_rdata; |
1557 | int ret = 0; | ||
1495 | 1558 | ||
1496 | node = binder_get_node_from_ref(proc, fp->handle, | 1559 | node = binder_get_node_from_ref(proc, fp->handle, |
1497 | fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); | 1560 | fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); |
@@ -1500,8 +1563,10 @@ static int binder_translate_handle(struct flat_binder_object *fp, | |||
1500 | proc->pid, thread->pid, fp->handle); | 1563 | proc->pid, thread->pid, fp->handle); |
1501 | return -EINVAL; | 1564 | return -EINVAL; |
1502 | } | 1565 | } |
1503 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) | 1566 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { |
1504 | return -EPERM; | 1567 | ret = -EPERM; |
1568 | goto done; | ||
1569 | } | ||
1505 | 1570 | ||
1506 | if (node->proc == target_proc) { | 1571 | if (node->proc == target_proc) { |
1507 | if (fp->hdr.type == BINDER_TYPE_HANDLE) | 1572 | if (fp->hdr.type == BINDER_TYPE_HANDLE) |
@@ -1526,7 +1591,7 @@ static int binder_translate_handle(struct flat_binder_object *fp, | |||
1526 | fp->hdr.type == BINDER_TYPE_HANDLE, | 1591 | fp->hdr.type == BINDER_TYPE_HANDLE, |
1527 | NULL, &dest_rdata); | 1592 | NULL, &dest_rdata); |
1528 | if (ret) | 1593 | if (ret) |
1529 | return ret; | 1594 | goto done; |
1530 | 1595 | ||
1531 | fp->binder = 0; | 1596 | fp->binder = 0; |
1532 | fp->handle = dest_rdata.desc; | 1597 | fp->handle = dest_rdata.desc; |
@@ -1539,7 +1604,9 @@ static int binder_translate_handle(struct flat_binder_object *fp, | |||
1539 | dest_rdata.debug_id, dest_rdata.desc, | 1604 | dest_rdata.debug_id, dest_rdata.desc, |
1540 | node->debug_id); | 1605 | node->debug_id); |
1541 | } | 1606 | } |
1542 | return 0; | 1607 | done: |
1608 | binder_put_node(node); | ||
1609 | return ret; | ||
1543 | } | 1610 | } |
1544 | 1611 | ||
1545 | static int binder_translate_fd(int fd, | 1612 | static int binder_translate_fd(int fd, |
@@ -2381,6 +2448,7 @@ static int binder_thread_write(struct binder_proc *proc, | |||
2381 | "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", | 2448 | "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", |
2382 | (u64)node_ptr, node->debug_id, | 2449 | (u64)node_ptr, node->debug_id, |
2383 | (u64)cookie, (u64)node->cookie); | 2450 | (u64)cookie, (u64)node->cookie); |
2451 | binder_put_node(node); | ||
2384 | break; | 2452 | break; |
2385 | } | 2453 | } |
2386 | if (cmd == BC_ACQUIRE_DONE) { | 2454 | if (cmd == BC_ACQUIRE_DONE) { |
@@ -2388,6 +2456,7 @@ static int binder_thread_write(struct binder_proc *proc, | |||
2388 | binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", | 2456 | binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", |
2389 | proc->pid, thread->pid, | 2457 | proc->pid, thread->pid, |
2390 | node->debug_id); | 2458 | node->debug_id); |
2459 | binder_put_node(node); | ||
2391 | break; | 2460 | break; |
2392 | } | 2461 | } |
2393 | node->pending_strong_ref = 0; | 2462 | node->pending_strong_ref = 0; |
@@ -2396,16 +2465,19 @@ static int binder_thread_write(struct binder_proc *proc, | |||
2396 | binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", | 2465 | binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", |
2397 | proc->pid, thread->pid, | 2466 | proc->pid, thread->pid, |
2398 | node->debug_id); | 2467 | node->debug_id); |
2468 | binder_put_node(node); | ||
2399 | break; | 2469 | break; |
2400 | } | 2470 | } |
2401 | node->pending_weak_ref = 0; | 2471 | node->pending_weak_ref = 0; |
2402 | } | 2472 | } |
2403 | binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); | 2473 | binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); |
2404 | binder_debug(BINDER_DEBUG_USER_REFS, | 2474 | binder_debug(BINDER_DEBUG_USER_REFS, |
2405 | "%d:%d %s node %d ls %d lw %d\n", | 2475 | "%d:%d %s node %d ls %d lw %d tr %d\n", |
2406 | proc->pid, thread->pid, | 2476 | proc->pid, thread->pid, |
2407 | cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", | 2477 | cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", |
2408 | node->debug_id, node->local_strong_refs, node->local_weak_refs); | 2478 | node->debug_id, node->local_strong_refs, |
2479 | node->local_weak_refs, node->tmp_refs); | ||
2480 | binder_put_node(node); | ||
2409 | break; | 2481 | break; |
2410 | } | 2482 | } |
2411 | case BC_ATTEMPT_ACQUIRE: | 2483 | case BC_ATTEMPT_ACQUIRE: |
@@ -2845,7 +2917,8 @@ retry: | |||
2845 | strong = node->internal_strong_refs || | 2917 | strong = node->internal_strong_refs || |
2846 | node->local_strong_refs; | 2918 | node->local_strong_refs; |
2847 | weak = !hlist_empty(&node->refs) || | 2919 | weak = !hlist_empty(&node->refs) || |
2848 | node->local_weak_refs || strong; | 2920 | node->local_weak_refs || |
2921 | node->tmp_refs || strong; | ||
2849 | has_strong_ref = node->has_strong_ref; | 2922 | has_strong_ref = node->has_strong_ref; |
2850 | has_weak_ref = node->has_weak_ref; | 2923 | has_weak_ref = node->has_weak_ref; |
2851 | 2924 | ||
@@ -3357,6 +3430,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) | |||
3357 | new_node->has_strong_ref = 1; | 3430 | new_node->has_strong_ref = 1; |
3358 | new_node->has_weak_ref = 1; | 3431 | new_node->has_weak_ref = 1; |
3359 | context->binder_context_mgr_node = new_node; | 3432 | context->binder_context_mgr_node = new_node; |
3433 | binder_put_node(new_node); | ||
3360 | out: | 3434 | out: |
3361 | mutex_unlock(&context->context_mgr_node_lock); | 3435 | mutex_unlock(&context->context_mgr_node_lock); |
3362 | return ret; | 3436 | return ret; |
@@ -3615,8 +3689,11 @@ static int binder_node_release(struct binder_node *node, int refs) | |||
3615 | 3689 | ||
3616 | list_del_init(&node->work.entry); | 3690 | list_del_init(&node->work.entry); |
3617 | binder_release_work(&node->async_todo); | 3691 | binder_release_work(&node->async_todo); |
3618 | 3692 | /* | |
3619 | if (hlist_empty(&node->refs)) { | 3693 | * The caller must have taken a temporary ref on the node, |
3694 | */ | ||
3695 | BUG_ON(!node->tmp_refs); | ||
3696 | if (hlist_empty(&node->refs) && node->tmp_refs == 1) { | ||
3620 | kfree(node); | 3697 | kfree(node); |
3621 | binder_stats_deleted(BINDER_STAT_NODE); | 3698 | binder_stats_deleted(BINDER_STAT_NODE); |
3622 | 3699 | ||
@@ -3651,6 +3728,7 @@ static int binder_node_release(struct binder_node *node, int refs) | |||
3651 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | 3728 | binder_debug(BINDER_DEBUG_DEAD_BINDER, |
3652 | "node %d now dead, refs %d, death %d\n", | 3729 | "node %d now dead, refs %d, death %d\n", |
3653 | node->debug_id, refs, death); | 3730 | node->debug_id, refs, death); |
3731 | binder_put_node(node); | ||
3654 | 3732 | ||
3655 | return refs; | 3733 | return refs; |
3656 | } | 3734 | } |
@@ -3700,6 +3778,12 @@ static void binder_deferred_release(struct binder_proc *proc) | |||
3700 | 3778 | ||
3701 | node = rb_entry(n, struct binder_node, rb_node); | 3779 | node = rb_entry(n, struct binder_node, rb_node); |
3702 | nodes++; | 3780 | nodes++; |
3781 | /* | ||
3782 | * take a temporary ref on the node before | ||
3783 | * calling binder_node_release() which will either | ||
3784 | * kfree() the node or call binder_put_node() | ||
3785 | */ | ||
3786 | binder_inc_node_tmpref(node); | ||
3703 | rb_erase(&node->rb_node, &proc->nodes); | 3787 | rb_erase(&node->rb_node, &proc->nodes); |
3704 | incoming_refs = binder_node_release(node, incoming_refs); | 3788 | incoming_refs = binder_node_release(node, incoming_refs); |
3705 | } | 3789 | } |
@@ -3895,11 +3979,11 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) | |||
3895 | hlist_for_each_entry(ref, &node->refs, node_entry) | 3979 | hlist_for_each_entry(ref, &node->refs, node_entry) |
3896 | count++; | 3980 | count++; |
3897 | 3981 | ||
3898 | seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", | 3982 | seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d", |
3899 | node->debug_id, (u64)node->ptr, (u64)node->cookie, | 3983 | node->debug_id, (u64)node->ptr, (u64)node->cookie, |
3900 | node->has_strong_ref, node->has_weak_ref, | 3984 | node->has_strong_ref, node->has_weak_ref, |
3901 | node->local_strong_refs, node->local_weak_refs, | 3985 | node->local_strong_refs, node->local_weak_refs, |
3902 | node->internal_strong_refs, count); | 3986 | node->internal_strong_refs, count, node->tmp_refs); |
3903 | if (count) { | 3987 | if (count) { |
3904 | seq_puts(m, " proc"); | 3988 | seq_puts(m, " proc"); |
3905 | hlist_for_each_entry(ref, &node->refs, node_entry) | 3989 | hlist_for_each_entry(ref, &node->refs, node_entry) |