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

binder: read pre-translated fds from sender buffer

This patch is to prepare for an up coming patch where we read
pre-translated fds from the sender buffer and translate them before
copying them to the target. It does not change run time.

The patch adds two new parameters to binder_translate_fd_array() to
hold the sender buffer and sender buffer parent. These parameters let
us call copy_from_user() directly from the sender instead of using
binder_alloc_copy_from_buffer() to copy from the target. Also the patch
adds some new alignment checks. Previously the alignment checks would
have been done in a different place, but this lets us print more
useful error messages.

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-4-tkjos@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Todd Kjos and committed by
Greg Kroah-Hartman
656e01f3 6d98eb95

+32 -7
+32 -7
drivers/android/binder.c
··· 2234 2234 } 2235 2235 2236 2236 static int binder_translate_fd_array(struct binder_fd_array_object *fda, 2237 + const void __user *sender_ubuffer, 2237 2238 struct binder_buffer_object *parent, 2239 + struct binder_buffer_object *sender_uparent, 2238 2240 struct binder_transaction *t, 2239 2241 struct binder_thread *thread, 2240 2242 struct binder_transaction *in_reply_to) 2241 2243 { 2242 2244 binder_size_t fdi, fd_buf_size; 2243 2245 binder_size_t fda_offset; 2246 + const void __user *sender_ufda_base; 2244 2247 struct binder_proc *proc = thread->proc; 2245 - struct binder_proc *target_proc = t->to_proc; 2246 2248 2247 2249 fd_buf_size = sizeof(u32) * fda->num_fds; 2248 2250 if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { ··· 2268 2266 */ 2269 2267 fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) + 2270 2268 fda->parent_offset; 2271 - if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32))) { 2269 + sender_ufda_base = (void __user *)sender_uparent->buffer + fda->parent_offset; 2270 + 2271 + if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32)) || 2272 + !IS_ALIGNED((unsigned long)sender_ufda_base, sizeof(u32))) { 2272 2273 binder_user_error("%d:%d parent offset not aligned correctly.\n", 2273 2274 proc->pid, thread->pid); 2274 2275 return -EINVAL; ··· 2280 2275 u32 fd; 2281 2276 int ret; 2282 2277 binder_size_t offset = fda_offset + fdi * sizeof(fd); 2278 + binder_size_t sender_uoffset = fdi * sizeof(fd); 2283 2279 2284 - ret = binder_alloc_copy_from_buffer(&target_proc->alloc, 2285 - &fd, t->buffer, 2286 - offset, sizeof(fd)); 2280 + ret = copy_from_user(&fd, sender_ufda_base + sender_uoffset, sizeof(fd)); 2287 2281 if (!ret) 2288 2282 ret = binder_translate_fd(fd, offset, t, thread, 2289 2283 in_reply_to); ··· 2955 2951 case BINDER_TYPE_FDA: { 2956 2952 struct binder_object ptr_object; 2957 2953 binder_size_t parent_offset; 2954 + struct binder_object user_object; 2955 + size_t user_parent_size; 2958 2956 struct binder_fd_array_object *fda = 2959 2957 to_binder_fd_array_object(hdr); 2960 2958 size_t num_valid = (buffer_offset - off_start_offset) / ··· 2988 2982 return_error_line = __LINE__; 2989 2983 goto err_bad_parent; 2990 2984 } 2991 - ret = binder_translate_fd_array(fda, parent, t, thread, 2992 - in_reply_to); 2985 + /* 2986 + * We need to read the user version of the parent 2987 + * object to get the original user offset 2988 + */ 2989 + user_parent_size = 2990 + binder_get_object(proc, user_buffer, t->buffer, 2991 + parent_offset, &user_object); 2992 + if (user_parent_size != sizeof(user_object.bbo)) { 2993 + binder_user_error("%d:%d invalid ptr object size: %zd vs %zd\n", 2994 + proc->pid, thread->pid, 2995 + user_parent_size, 2996 + sizeof(user_object.bbo)); 2997 + return_error = BR_FAILED_REPLY; 2998 + return_error_param = -EINVAL; 2999 + return_error_line = __LINE__; 3000 + goto err_bad_parent; 3001 + } 3002 + ret = binder_translate_fd_array(fda, user_buffer, 3003 + parent, 3004 + &user_object.bbo, t, 3005 + thread, in_reply_to); 2993 3006 if (!ret) 2994 3007 ret = binder_alloc_copy_to_buffer(&target_proc->alloc, 2995 3008 t->buffer,