Commit def95c73567dfacb22900cd0c4f01caff39e4c9e

Authored by Martijn Coenen
Committed by Greg Kroah-Hartman
1 parent 7980240b6d

binder: Add support for file-descriptor arrays

This patch introduces a new binder_fd_array object,
that allows us to support one or more file descriptors
embedded in a buffer that is scatter-gathered.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Martijn Coenen <maco@google.com>
Cc: Arve Hjønnevåg <arve@android.com>
Cc: Amit Pundir <amit.pundir@linaro.org>
Cc: Serban Constantinescu <serban.constantinescu@arm.com>
Cc: Dmitry Shmidt <dimitrysh@google.com>
Cc: Rom Lemarchand <romlem@google.com>
Cc: Android Kernel Team <kernel-team@android.com>
Signed-off-by: Martijn Coenen <maco@google.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 2 changed files with 165 additions and 0 deletions Side-by-side Diff

drivers/android/binder.c
... ... @@ -155,6 +155,9 @@
155 155 #define to_binder_buffer_object(hdr) \
156 156 container_of(hdr, struct binder_buffer_object, hdr)
157 157  
  158 +#define to_binder_fd_array_object(hdr) \
  159 + container_of(hdr, struct binder_fd_array_object, hdr)
  160 +
158 161 enum binder_stat_types {
159 162 BINDER_STAT_PROC,
160 163 BINDER_STAT_THREAD,
... ... @@ -1310,6 +1313,9 @@
1310 1313 case BINDER_TYPE_PTR:
1311 1314 object_size = sizeof(struct binder_buffer_object);
1312 1315 break;
  1316 + case BINDER_TYPE_FDA:
  1317 + object_size = sizeof(struct binder_fd_array_object);
  1318 + break;
1313 1319 default:
1314 1320 return 0;
1315 1321 }
... ... @@ -1503,6 +1509,47 @@
1503 1509 * transaction buffer gets freed
1504 1510 */
1505 1511 break;
  1512 + case BINDER_TYPE_FDA: {
  1513 + struct binder_fd_array_object *fda;
  1514 + struct binder_buffer_object *parent;
  1515 + uintptr_t parent_buffer;
  1516 + u32 *fd_array;
  1517 + size_t fd_index;
  1518 + binder_size_t fd_buf_size;
  1519 +
  1520 + fda = to_binder_fd_array_object(hdr);
  1521 + parent = binder_validate_ptr(buffer, fda->parent,
  1522 + off_start,
  1523 + offp - off_start);
  1524 + if (!parent) {
  1525 + pr_err("transaction release %d bad parent offset",
  1526 + debug_id);
  1527 + continue;
  1528 + }
  1529 + /*
  1530 + * Since the parent was already fixed up, convert it
  1531 + * back to kernel address space to access it
  1532 + */
  1533 + parent_buffer = parent->buffer -
  1534 + proc->user_buffer_offset;
  1535 +
  1536 + fd_buf_size = sizeof(u32) * fda->num_fds;
  1537 + if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
  1538 + pr_err("transaction release %d invalid number of fds (%lld)\n",
  1539 + debug_id, (u64)fda->num_fds);
  1540 + continue;
  1541 + }
  1542 + if (fd_buf_size > parent->length ||
  1543 + fda->parent_offset > parent->length - fd_buf_size) {
  1544 + /* No space for all file descriptors here. */
  1545 + pr_err("transaction release %d not enough space for %lld fds in buffer\n",
  1546 + debug_id, (u64)fda->num_fds);
  1547 + continue;
  1548 + }
  1549 + fd_array = (u32 *)(parent_buffer + fda->parent_offset);
  1550 + for (fd_index = 0; fd_index < fda->num_fds; fd_index++)
  1551 + task_close_fd(proc, fd_array[fd_index]);
  1552 + } break;
1506 1553 default:
1507 1554 pr_err("transaction release %d bad object type %x\n",
1508 1555 debug_id, hdr->type);
... ... @@ -1672,6 +1719,63 @@
1672 1719 return ret;
1673 1720 }
1674 1721  
  1722 +static int binder_translate_fd_array(struct binder_fd_array_object *fda,
  1723 + struct binder_buffer_object *parent,
  1724 + struct binder_transaction *t,
  1725 + struct binder_thread *thread,
  1726 + struct binder_transaction *in_reply_to)
  1727 +{
  1728 + binder_size_t fdi, fd_buf_size, num_installed_fds;
  1729 + int target_fd;
  1730 + uintptr_t parent_buffer;
  1731 + u32 *fd_array;
  1732 + struct binder_proc *proc = thread->proc;
  1733 + struct binder_proc *target_proc = t->to_proc;
  1734 +
  1735 + fd_buf_size = sizeof(u32) * fda->num_fds;
  1736 + if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
  1737 + binder_user_error("%d:%d got transaction with invalid number of fds (%lld)\n",
  1738 + proc->pid, thread->pid, (u64)fda->num_fds);
  1739 + return -EINVAL;
  1740 + }
  1741 + if (fd_buf_size > parent->length ||
  1742 + fda->parent_offset > parent->length - fd_buf_size) {
  1743 + /* No space for all file descriptors here. */
  1744 + binder_user_error("%d:%d not enough space to store %lld fds in buffer\n",
  1745 + proc->pid, thread->pid, (u64)fda->num_fds);
  1746 + return -EINVAL;
  1747 + }
  1748 + /*
  1749 + * Since the parent was already fixed up, convert it
  1750 + * back to the kernel address space to access it
  1751 + */
  1752 + parent_buffer = parent->buffer - target_proc->user_buffer_offset;
  1753 + fd_array = (u32 *)(parent_buffer + fda->parent_offset);
  1754 + if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) {
  1755 + binder_user_error("%d:%d parent offset not aligned correctly.\n",
  1756 + proc->pid, thread->pid);
  1757 + return -EINVAL;
  1758 + }
  1759 + for (fdi = 0; fdi < fda->num_fds; fdi++) {
  1760 + target_fd = binder_translate_fd(fd_array[fdi], t, thread,
  1761 + in_reply_to);
  1762 + if (target_fd < 0)
  1763 + goto err_translate_fd_failed;
  1764 + fd_array[fdi] = target_fd;
  1765 + }
  1766 + return 0;
  1767 +
  1768 +err_translate_fd_failed:
  1769 + /*
  1770 + * Failed to allocate fd or security error, free fds
  1771 + * installed so far.
  1772 + */
  1773 + num_installed_fds = fdi;
  1774 + for (fdi = 0; fdi < num_installed_fds; fdi++)
  1775 + task_close_fd(target_proc, fd_array[fdi]);
  1776 + return target_fd;
  1777 +}
  1778 +
1675 1779 static int binder_fixup_parent(struct binder_transaction *t,
1676 1780 struct binder_thread *thread,
1677 1781 struct binder_buffer_object *bp,
... ... @@ -2000,6 +2104,38 @@
2000 2104 fp->pad_binder = 0;
2001 2105 fp->fd = target_fd;
2002 2106 } break;
  2107 + case BINDER_TYPE_FDA: {
  2108 + struct binder_fd_array_object *fda =
  2109 + to_binder_fd_array_object(hdr);
  2110 + struct binder_buffer_object *parent =
  2111 + binder_validate_ptr(t->buffer, fda->parent,
  2112 + off_start,
  2113 + offp - off_start);
  2114 + if (!parent) {
  2115 + binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
  2116 + proc->pid, thread->pid);
  2117 + return_error = BR_FAILED_REPLY;
  2118 + goto err_bad_parent;
  2119 + }
  2120 + if (!binder_validate_fixup(t->buffer, off_start,
  2121 + parent, fda->parent_offset,
  2122 + last_fixup_obj,
  2123 + last_fixup_min_off)) {
  2124 + binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
  2125 + proc->pid, thread->pid);
  2126 + return_error = BR_FAILED_REPLY;
  2127 + goto err_bad_parent;
  2128 + }
  2129 + ret = binder_translate_fd_array(fda, parent, t, thread,
  2130 + in_reply_to);
  2131 + if (ret < 0) {
  2132 + return_error = BR_FAILED_REPLY;
  2133 + goto err_translate_failed;
  2134 + }
  2135 + last_fixup_obj = parent;
  2136 + last_fixup_min_off =
  2137 + fda->parent_offset + sizeof(u32) * fda->num_fds;
  2138 + } break;
2003 2139 case BINDER_TYPE_PTR: {
2004 2140 struct binder_buffer_object *bp =
2005 2141 to_binder_buffer_object(hdr);
... ... @@ -2070,6 +2206,7 @@
2070 2206 err_translate_failed:
2071 2207 err_bad_object_type:
2072 2208 err_bad_offset:
  2209 +err_bad_parent:
2073 2210 err_copy_data_failed:
2074 2211 trace_binder_transaction_failed_buffer_release(t->buffer);
2075 2212 binder_transaction_buffer_release(target_proc, t->buffer, offp);
include/uapi/linux/android/binder.h
... ... @@ -33,6 +33,7 @@
33 33 BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
34 34 BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
35 35 BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
  36 + BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE),
36 37 BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),
37 38 };
38 39  
... ... @@ -127,6 +128,33 @@
127 128  
128 129 enum {
129 130 BINDER_BUFFER_FLAG_HAS_PARENT = 0x01,
  131 +};
  132 +
  133 +/* struct binder_fd_array_object - object describing an array of fds in a buffer
  134 + * @hdr: common header structure
  135 + * @num_fds: number of file descriptors in the buffer
  136 + * @parent: index in offset array to buffer holding the fd array
  137 + * @parent_offset: start offset of fd array in the buffer
  138 + *
  139 + * A binder_fd_array object represents an array of file
  140 + * descriptors embedded in a binder_buffer_object. It is
  141 + * different from a regular binder_buffer_object because it
  142 + * describes a list of file descriptors to fix up, not an opaque
  143 + * blob of memory, and hence the kernel needs to treat it differently.
  144 + *
  145 + * An example of how this would be used is with Android's
  146 + * native_handle_t object, which is a struct with a list of integers
  147 + * and a list of file descriptors. The native_handle_t struct itself
  148 + * will be represented by a struct binder_buffer_objct, whereas the
  149 + * embedded list of file descriptors is represented by a
  150 + * struct binder_fd_array_object with that binder_buffer_object as
  151 + * a parent.
  152 + */
  153 +struct binder_fd_array_object {
  154 + struct binder_object_header hdr;
  155 + binder_size_t num_fds;
  156 + binder_size_t parent;
  157 + binder_size_t parent_offset;
130 158 };
131 159  
132 160 /*