diff options
-rw-r--r-- | drivers/android/binder.c | 29 | ||||
-rw-r--r-- | drivers/android/binder_alloc.c | 113 | ||||
-rw-r--r-- | drivers/android/binder_alloc.h | 8 |
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 | */ | ||
1078 | static 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 | */ | ||
1110 | static 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 | */ | ||
1138 | unsigned long | ||
1139 | binder_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 | ||
26 | extern struct list_lru binder_alloc_lru; | 27 | extern struct list_lru binder_alloc_lru; |
27 | struct binder_transaction; | 28 | struct 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 | ||
187 | unsigned long | ||
188 | binder_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 | ||