Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 457b9a6f09f0 ("Staging: android: add binder driver")
Reviewed-by: Martijn Coenen <maco@android.com>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Todd Kjos <tkjos@google.com>
Link: https://lore.kernel.org/r/20211130185152.437403-3-tkjos@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Todd Kjos and committed by
Greg Kroah-Hartman
6d98eb95 fe6b1869

+70 -24
+70 -24
drivers/android/binder.c
··· 1608 1608 /** 1609 1609 * binder_get_object() - gets object and checks for valid metadata 1610 1610 * @proc: binder_proc owning the buffer 1611 + * @u: sender's user pointer to base of buffer 1611 1612 * @buffer: binder_buffer that we're parsing. 1612 1613 * @offset: offset in the @buffer at which to validate an object. 1613 1614 * @object: struct binder_object to read into 1614 1615 * 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 1616 1621 * size of that object. Otherwise, it returns zero. The object 1617 1622 * is read into the struct binder_object pointed to by @object. 1618 1623 */ 1619 1624 static size_t binder_get_object(struct binder_proc *proc, 1625 + const void __user *u, 1620 1626 struct binder_buffer *buffer, 1621 1627 unsigned long offset, 1622 1628 struct binder_object *object) ··· 1632 1626 size_t object_size = 0; 1633 1627 1634 1628 read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset); 1635 - if (offset > buffer->data_size || read_size < sizeof(*hdr) || 1636 - binder_alloc_copy_from_buffer(&proc->alloc, object, buffer, 1637 - offset, read_size)) 1629 + if (offset > buffer->data_size || read_size < sizeof(*hdr)) 1638 1630 return 0; 1631 + if (u) { 1632 + if (copy_from_user(object, u + offset, read_size)) 1633 + return 0; 1634 + } else { 1635 + if (binder_alloc_copy_from_buffer(&proc->alloc, object, buffer, 1636 + offset, read_size)) 1637 + return 0; 1638 + } 1639 1639 1640 1640 /* Ok, now see if we read a complete object. */ 1641 1641 hdr = &object->hdr; ··· 1714 1702 b, buffer_offset, 1715 1703 sizeof(object_offset))) 1716 1704 return NULL; 1717 - object_size = binder_get_object(proc, b, object_offset, object); 1705 + object_size = binder_get_object(proc, NULL, b, object_offset, object); 1718 1706 if (!object_size || object->hdr.type != BINDER_TYPE_PTR) 1719 1707 return NULL; 1720 1708 if (object_offsetp) ··· 1779 1767 unsigned long buffer_offset; 1780 1768 struct binder_object last_object; 1781 1769 struct binder_buffer_object *last_bbo; 1782 - size_t object_size = binder_get_object(proc, b, last_obj_offset, 1770 + size_t object_size = binder_get_object(proc, NULL, b, 1771 + last_obj_offset, 1783 1772 &last_object); 1784 1773 if (object_size != sizeof(*last_bbo)) 1785 1774 return false; ··· 1895 1882 if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset, 1896 1883 buffer, buffer_offset, 1897 1884 sizeof(object_offset))) 1898 - object_size = binder_get_object(proc, buffer, 1885 + object_size = binder_get_object(proc, NULL, buffer, 1899 1886 object_offset, &object); 1900 1887 if (object_size == 0) { 1901 1888 pr_err("transaction release %d bad object at offset %lld, size %zd\n", ··· 2468 2455 binder_size_t off_start_offset, off_end_offset; 2469 2456 binder_size_t off_min; 2470 2457 binder_size_t sg_buf_offset, sg_buf_end_offset; 2458 + binder_size_t user_offset = 0; 2471 2459 struct binder_proc *target_proc = NULL; 2472 2460 struct binder_thread *target_thread = NULL; 2473 2461 struct binder_node *target_node = NULL; ··· 2483 2469 int t_debug_id = atomic_inc_return(&binder_last_id); 2484 2470 char *secctx = NULL; 2485 2471 u32 secctx_sz = 0; 2472 + const void __user *user_buffer = (const void __user *) 2473 + (uintptr_t)tr->data.ptr.buffer; 2486 2474 2487 2475 e = binder_transaction_log_add(&binder_transaction_log); 2488 2476 e->debug_id = t_debug_id; ··· 2798 2782 2799 2783 if (binder_alloc_copy_user_to_buffer( 2800 2784 &target_proc->alloc, 2801 - t->buffer, 0, 2802 - (const void __user *) 2803 - (uintptr_t)tr->data.ptr.buffer, 2804 - tr->data_size)) { 2805 - binder_user_error("%d:%d got transaction with invalid data ptr\n", 2806 - proc->pid, thread->pid); 2807 - return_error = BR_FAILED_REPLY; 2808 - return_error_param = -EFAULT; 2809 - return_error_line = __LINE__; 2810 - goto err_copy_data_failed; 2811 - } 2812 - if (binder_alloc_copy_user_to_buffer( 2813 - &target_proc->alloc, 2814 2785 t->buffer, 2815 2786 ALIGN(tr->data_size, sizeof(void *)), 2816 2787 (const void __user *) ··· 2840 2837 size_t object_size; 2841 2838 struct binder_object object; 2842 2839 binder_size_t object_offset; 2840 + binder_size_t copy_size; 2843 2841 2844 2842 if (binder_alloc_copy_from_buffer(&target_proc->alloc, 2845 2843 &object_offset, ··· 2852 2848 return_error_line = __LINE__; 2853 2849 goto err_bad_offset; 2854 2850 } 2855 - object_size = binder_get_object(target_proc, t->buffer, 2856 - object_offset, &object); 2851 + 2852 + /* 2853 + * Copy the source user buffer up to the next object 2854 + * that will be processed. 2855 + */ 2856 + copy_size = object_offset - user_offset; 2857 + if (copy_size && (user_offset > object_offset || 2858 + binder_alloc_copy_user_to_buffer( 2859 + &target_proc->alloc, 2860 + t->buffer, user_offset, 2861 + user_buffer + user_offset, 2862 + copy_size))) { 2863 + binder_user_error("%d:%d got transaction with invalid data ptr\n", 2864 + proc->pid, thread->pid); 2865 + return_error = BR_FAILED_REPLY; 2866 + return_error_param = -EFAULT; 2867 + return_error_line = __LINE__; 2868 + goto err_copy_data_failed; 2869 + } 2870 + object_size = binder_get_object(target_proc, user_buffer, 2871 + t->buffer, object_offset, &object); 2857 2872 if (object_size == 0 || object_offset < off_min) { 2858 2873 binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n", 2859 2874 proc->pid, thread->pid, ··· 2884 2861 return_error_line = __LINE__; 2885 2862 goto err_bad_offset; 2886 2863 } 2864 + /* 2865 + * Set offset to the next buffer fragment to be 2866 + * copied 2867 + */ 2868 + user_offset = object_offset + object_size; 2887 2869 2888 2870 hdr = &object.hdr; 2889 2871 off_min = object_offset + object_size; ··· 2984 2956 } 2985 2957 ret = binder_translate_fd_array(fda, parent, t, thread, 2986 2958 in_reply_to); 2987 - if (ret < 0) { 2959 + if (!ret) 2960 + ret = binder_alloc_copy_to_buffer(&target_proc->alloc, 2961 + t->buffer, 2962 + object_offset, 2963 + fda, sizeof(*fda)); 2964 + if (ret) { 2988 2965 return_error = BR_FAILED_REPLY; 2989 - return_error_param = ret; 2966 + return_error_param = ret > 0 ? -EINVAL : ret; 2990 2967 return_error_line = __LINE__; 2991 2968 goto err_translate_failed; 2992 2969 } ··· 3060 3027 return_error_line = __LINE__; 3061 3028 goto err_bad_object_type; 3062 3029 } 3030 + } 3031 + /* Done processing objects, copy the rest of the buffer */ 3032 + if (binder_alloc_copy_user_to_buffer( 3033 + &target_proc->alloc, 3034 + t->buffer, user_offset, 3035 + user_buffer + user_offset, 3036 + tr->data_size - user_offset)) { 3037 + binder_user_error("%d:%d got transaction with invalid data ptr\n", 3038 + proc->pid, thread->pid); 3039 + return_error = BR_FAILED_REPLY; 3040 + return_error_param = -EFAULT; 3041 + return_error_line = __LINE__; 3042 + goto err_copy_data_failed; 3063 3043 } 3064 3044 if (t->buffer->oneway_spam_suspect) 3065 3045 tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT;