aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/android/binder.c29
-rw-r--r--drivers/android/binder_alloc.c113
-rw-r--r--drivers/android/binder_alloc.h8
3 files changed, 143 insertions, 7 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 01f80cbd2741..5ddb2a4d893e 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3078,8 +3078,12 @@ static void binder_transaction(struct binder_proc *proc,
3078 ALIGN(tr->data_size, sizeof(void *))); 3078 ALIGN(tr->data_size, sizeof(void *)));
3079 offp = off_start; 3079 offp = off_start;
3080 3080
3081 if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) 3081 if (binder_alloc_copy_user_to_buffer(
3082 tr->data.ptr.buffer, tr->data_size)) { 3082 &target_proc->alloc,
3083 t->buffer, 0,
3084 (const void __user *)
3085 (uintptr_t)tr->data.ptr.buffer,
3086 tr->data_size)) {
3083 binder_user_error("%d:%d got transaction with invalid data ptr\n", 3087 binder_user_error("%d:%d got transaction with invalid data ptr\n",
3084 proc->pid, thread->pid); 3088 proc->pid, thread->pid);
3085 return_error = BR_FAILED_REPLY; 3089 return_error = BR_FAILED_REPLY;
@@ -3087,8 +3091,13 @@ static void binder_transaction(struct binder_proc *proc,
3087 return_error_line = __LINE__; 3091 return_error_line = __LINE__;
3088 goto err_copy_data_failed; 3092 goto err_copy_data_failed;
3089 } 3093 }
3090 if (copy_from_user(offp, (const void __user *)(uintptr_t) 3094 if (binder_alloc_copy_user_to_buffer(
3091 tr->data.ptr.offsets, tr->offsets_size)) { 3095 &target_proc->alloc,
3096 t->buffer,
3097 ALIGN(tr->data_size, sizeof(void *)),
3098 (const void __user *)
3099 (uintptr_t)tr->data.ptr.offsets,
3100 tr->offsets_size)) {
3092 binder_user_error("%d:%d got transaction with invalid offsets ptr\n", 3101 binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
3093 proc->pid, thread->pid); 3102 proc->pid, thread->pid);
3094 return_error = BR_FAILED_REPLY; 3103 return_error = BR_FAILED_REPLY;
@@ -3217,6 +3226,8 @@ static void binder_transaction(struct binder_proc *proc,
3217 struct binder_buffer_object *bp = 3226 struct binder_buffer_object *bp =
3218 to_binder_buffer_object(hdr); 3227 to_binder_buffer_object(hdr);
3219 size_t buf_left = sg_buf_end - sg_bufp; 3228 size_t buf_left = sg_buf_end - sg_bufp;
3229 binder_size_t sg_buf_offset = (uintptr_t)sg_bufp -
3230 (uintptr_t)t->buffer->data;
3220 3231
3221 if (bp->length > buf_left) { 3232 if (bp->length > buf_left) {
3222 binder_user_error("%d:%d got transaction with too large buffer\n", 3233 binder_user_error("%d:%d got transaction with too large buffer\n",
@@ -3226,9 +3237,13 @@ static void binder_transaction(struct binder_proc *proc,
3226 return_error_line = __LINE__; 3237 return_error_line = __LINE__;
3227 goto err_bad_offset; 3238 goto err_bad_offset;
3228 } 3239 }
3229 if (copy_from_user(sg_bufp, 3240 if (binder_alloc_copy_user_to_buffer(
3230 (const void __user *)(uintptr_t) 3241 &target_proc->alloc,
3231 bp->buffer, bp->length)) { 3242 t->buffer,
3243 sg_buf_offset,
3244 (const void __user *)
3245 (uintptr_t)bp->buffer,
3246 bp->length)) {
3232 binder_user_error("%d:%d got transaction with invalid offsets ptr\n", 3247 binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
3233 proc->pid, thread->pid); 3248 proc->pid, thread->pid);
3234 return_error_param = -EFAULT; 3249 return_error_param = -EFAULT;
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 022cd80e80cc..94c0d85c4e75 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -29,6 +29,8 @@
29#include <linux/list_lru.h> 29#include <linux/list_lru.h>
30#include <linux/ratelimit.h> 30#include <linux/ratelimit.h>
31#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
32#include <linux/uaccess.h>
33#include <linux/highmem.h>
32#include "binder_alloc.h" 34#include "binder_alloc.h"
33#include "binder_trace.h" 35#include "binder_trace.h"
34 36
@@ -1053,3 +1055,114 @@ int binder_alloc_shrinker_init(void)
1053 } 1055 }
1054 return ret; 1056 return ret;
1055} 1057}
1058
1059/**
1060 * check_buffer() - verify that buffer/offset is safe to access
1061 * @alloc: binder_alloc for this proc
1062 * @buffer: binder buffer to be accessed
1063 * @offset: offset into @buffer data
1064 * @bytes: bytes to access from offset
1065 *
1066 * Check that the @offset/@bytes are within the size of the given
1067 * @buffer and that the buffer is currently active and not freeable.
1068 * Offsets must also be multiples of sizeof(u32). The kernel is
1069 * allowed to touch the buffer in two cases:
1070 *
1071 * 1) when the buffer is being created:
1072 * (buffer->free == 0 && buffer->allow_user_free == 0)
1073 * 2) when the buffer is being torn down:
1074 * (buffer->free == 0 && buffer->transaction == NULL).
1075 *
1076 * Return: true if the buffer is safe to access
1077 */
1078static inline bool check_buffer(struct binder_alloc *alloc,
1079 struct binder_buffer *buffer,
1080 binder_size_t offset, size_t bytes)
1081{
1082 size_t buffer_size = binder_alloc_buffer_size(alloc, buffer);
1083
1084 return buffer_size >= bytes &&
1085 offset <= buffer_size - bytes &&
1086 IS_ALIGNED(offset, sizeof(u32)) &&
1087 !buffer->free &&
1088 (!buffer->allow_user_free || !buffer->transaction);
1089}
1090
1091/**
1092 * binder_alloc_get_page() - get kernel pointer for given buffer offset
1093 * @alloc: binder_alloc for this proc
1094 * @buffer: binder buffer to be accessed
1095 * @buffer_offset: offset into @buffer data
1096 * @pgoffp: address to copy final page offset to
1097 *
1098 * Lookup the struct page corresponding to the address
1099 * at @buffer_offset into @buffer->data. If @pgoffp is not
1100 * NULL, the byte-offset into the page is written there.
1101 *
1102 * The caller is responsible to ensure that the offset points
1103 * to a valid address within the @buffer and that @buffer is
1104 * not freeable by the user. Since it can't be freed, we are
1105 * guaranteed that the corresponding elements of @alloc->pages[]
1106 * cannot change.
1107 *
1108 * Return: struct page
1109 */
1110static struct page *binder_alloc_get_page(struct binder_alloc *alloc,
1111 struct binder_buffer *buffer,
1112 binder_size_t buffer_offset,
1113 pgoff_t *pgoffp)
1114{
1115 binder_size_t buffer_space_offset = buffer_offset +
1116 (buffer->data - alloc->buffer);
1117 pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK;
1118 size_t index = buffer_space_offset >> PAGE_SHIFT;
1119 struct binder_lru_page *lru_page;
1120
1121 lru_page = &alloc->pages[index];
1122 *pgoffp = pgoff;
1123 return lru_page->page_ptr;
1124}
1125
1126/**
1127 * binder_alloc_copy_user_to_buffer() - copy src user to tgt user
1128 * @alloc: binder_alloc for this proc
1129 * @buffer: binder buffer to be accessed
1130 * @buffer_offset: offset into @buffer data
1131 * @from: userspace pointer to source buffer
1132 * @bytes: bytes to copy
1133 *
1134 * Copy bytes from source userspace to target buffer.
1135 *
1136 * Return: bytes remaining to be copied
1137 */
1138unsigned long
1139binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
1140 struct binder_buffer *buffer,
1141 binder_size_t buffer_offset,
1142 const void __user *from,
1143 size_t bytes)
1144{
1145 if (!check_buffer(alloc, buffer, buffer_offset, bytes))
1146 return bytes;
1147
1148 while (bytes) {
1149 unsigned long size;
1150 unsigned long ret;
1151 struct page *page;
1152 pgoff_t pgoff;
1153 void *kptr;
1154
1155 page = binder_alloc_get_page(alloc, buffer,
1156 buffer_offset, &pgoff);
1157 size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
1158 kptr = kmap(page) + pgoff;
1159 ret = copy_from_user(kptr, from, size);
1160 kunmap(page);
1161 if (ret)
1162 return bytes - size + ret;
1163 bytes -= size;
1164 from += size;
1165 buffer_offset += size;
1166 }
1167 return 0;
1168}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index c0aadbbf7f19..995155f31dbd 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -22,6 +22,7 @@
22#include <linux/vmalloc.h> 22#include <linux/vmalloc.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/list_lru.h> 24#include <linux/list_lru.h>
25#include <uapi/linux/android/binder.h>
25 26
26extern struct list_lru binder_alloc_lru; 27extern struct list_lru binder_alloc_lru;
27struct binder_transaction; 28struct binder_transaction;
@@ -183,5 +184,12 @@ binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc)
183 return alloc->user_buffer_offset; 184 return alloc->user_buffer_offset;
184} 185}
185 186
187unsigned long
188binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
189 struct binder_buffer *buffer,
190 binder_size_t buffer_offset,
191 const void __user *from,
192 size_t bytes);
193
186#endif /* _LINUX_BINDER_ALLOC_H */ 194#endif /* _LINUX_BINDER_ALLOC_H */
187 195