diff options
Diffstat (limited to 'arch/s390/lib')
-rw-r--r-- | arch/s390/lib/uaccess_mvcos.c | 26 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_pt.c | 129 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_std.c | 48 |
3 files changed, 124 insertions, 79 deletions
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index 2443ae476e33..1829742bf479 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c | |||
@@ -162,19 +162,19 @@ static size_t clear_user_mvcos(size_t size, void __user *to) | |||
162 | 162 | ||
163 | static size_t strnlen_user_mvcos(size_t count, const char __user *src) | 163 | static size_t strnlen_user_mvcos(size_t count, const char __user *src) |
164 | { | 164 | { |
165 | size_t done, len, offset, len_str; | ||
165 | char buf[256]; | 166 | char buf[256]; |
166 | int rc; | ||
167 | size_t done, len, len_str; | ||
168 | 167 | ||
169 | done = 0; | 168 | done = 0; |
170 | do { | 169 | do { |
171 | len = min(count - done, (size_t) 256); | 170 | offset = (size_t)src & ~PAGE_MASK; |
172 | rc = uaccess.copy_from_user(len, src + done, buf); | 171 | len = min(256UL, PAGE_SIZE - offset); |
173 | if (unlikely(rc == len)) | 172 | len = min(count - done, len); |
173 | if (copy_from_user_mvcos(len, src, buf)) | ||
174 | return 0; | 174 | return 0; |
175 | len -= rc; | ||
176 | len_str = strnlen(buf, len); | 175 | len_str = strnlen(buf, len); |
177 | done += len_str; | 176 | done += len_str; |
177 | src += len_str; | ||
178 | } while ((len_str == len) && (done < count)); | 178 | } while ((len_str == len) && (done < count)); |
179 | return done + 1; | 179 | return done + 1; |
180 | } | 180 | } |
@@ -182,18 +182,20 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src) | |||
182 | static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, | 182 | static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, |
183 | char *dst) | 183 | char *dst) |
184 | { | 184 | { |
185 | int rc; | 185 | size_t done, len, offset, len_str; |
186 | size_t done, len, len_str; | ||
187 | 186 | ||
187 | if (unlikely(!count)) | ||
188 | return 0; | ||
188 | done = 0; | 189 | done = 0; |
189 | do { | 190 | do { |
190 | len = min(count - done, (size_t) 4096); | 191 | offset = (size_t)src & ~PAGE_MASK; |
191 | rc = uaccess.copy_from_user(len, src + done, dst); | 192 | len = min(count - done, PAGE_SIZE - offset); |
192 | if (unlikely(rc == len)) | 193 | if (copy_from_user_mvcos(len, src, dst)) |
193 | return -EFAULT; | 194 | return -EFAULT; |
194 | len -= rc; | ||
195 | len_str = strnlen(dst, len); | 195 | len_str = strnlen(dst, len); |
196 | done += len_str; | 196 | done += len_str; |
197 | src += len_str; | ||
198 | dst += len_str; | ||
197 | } while ((len_str == len) && (done < count)); | 199 | } while ((len_str == len) && (done < count)); |
198 | return done; | 200 | return done; |
199 | } | 201 | } |
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index a70ee84c0241..dff631d34b45 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c | |||
@@ -14,6 +14,63 @@ | |||
14 | #include <asm/futex.h> | 14 | #include <asm/futex.h> |
15 | #include "uaccess.h" | 15 | #include "uaccess.h" |
16 | 16 | ||
17 | #ifndef CONFIG_64BIT | ||
18 | #define AHI "ahi" | ||
19 | #define SLR "slr" | ||
20 | #else | ||
21 | #define AHI "aghi" | ||
22 | #define SLR "slgr" | ||
23 | #endif | ||
24 | |||
25 | static size_t strnlen_kernel(size_t count, const char __user *src) | ||
26 | { | ||
27 | register unsigned long reg0 asm("0") = 0UL; | ||
28 | unsigned long tmp1, tmp2; | ||
29 | |||
30 | asm volatile( | ||
31 | " la %2,0(%1)\n" | ||
32 | " la %3,0(%0,%1)\n" | ||
33 | " "SLR" %0,%0\n" | ||
34 | "0: srst %3,%2\n" | ||
35 | " jo 0b\n" | ||
36 | " la %0,1(%3)\n" /* strnlen_kernel results includes \0 */ | ||
37 | " "SLR" %0,%1\n" | ||
38 | "1:\n" | ||
39 | EX_TABLE(0b,1b) | ||
40 | : "+a" (count), "+a" (src), "=a" (tmp1), "=a" (tmp2) | ||
41 | : "d" (reg0) : "cc", "memory"); | ||
42 | return count; | ||
43 | } | ||
44 | |||
45 | static size_t copy_in_kernel(size_t count, void __user *to, | ||
46 | const void __user *from) | ||
47 | { | ||
48 | unsigned long tmp1; | ||
49 | |||
50 | asm volatile( | ||
51 | " "AHI" %0,-1\n" | ||
52 | " jo 5f\n" | ||
53 | " bras %3,3f\n" | ||
54 | "0:"AHI" %0,257\n" | ||
55 | "1: mvc 0(1,%1),0(%2)\n" | ||
56 | " la %1,1(%1)\n" | ||
57 | " la %2,1(%2)\n" | ||
58 | " "AHI" %0,-1\n" | ||
59 | " jnz 1b\n" | ||
60 | " j 5f\n" | ||
61 | "2: mvc 0(256,%1),0(%2)\n" | ||
62 | " la %1,256(%1)\n" | ||
63 | " la %2,256(%2)\n" | ||
64 | "3:"AHI" %0,-256\n" | ||
65 | " jnm 2b\n" | ||
66 | "4: ex %0,1b-0b(%3)\n" | ||
67 | "5:"SLR" %0,%0\n" | ||
68 | "6:\n" | ||
69 | EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b) | ||
70 | : "+a" (count), "+a" (to), "+a" (from), "=a" (tmp1) | ||
71 | : : "cc", "memory"); | ||
72 | return count; | ||
73 | } | ||
17 | 74 | ||
18 | /* | 75 | /* |
19 | * Returns kernel address for user virtual address. If the returned address is | 76 | * Returns kernel address for user virtual address. If the returned address is |
@@ -123,10 +180,8 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to) | |||
123 | { | 180 | { |
124 | size_t rc; | 181 | size_t rc; |
125 | 182 | ||
126 | if (segment_eq(get_fs(), KERNEL_DS)) { | 183 | if (segment_eq(get_fs(), KERNEL_DS)) |
127 | memcpy(to, (void __kernel __force *) from, n); | 184 | return copy_in_kernel(n, (void __user *) to, from); |
128 | return 0; | ||
129 | } | ||
130 | rc = __user_copy_pt((unsigned long) from, to, n, 0); | 185 | rc = __user_copy_pt((unsigned long) from, to, n, 0); |
131 | if (unlikely(rc)) | 186 | if (unlikely(rc)) |
132 | memset(to + n - rc, 0, rc); | 187 | memset(to + n - rc, 0, rc); |
@@ -135,30 +190,28 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to) | |||
135 | 190 | ||
136 | size_t copy_to_user_pt(size_t n, void __user *to, const void *from) | 191 | size_t copy_to_user_pt(size_t n, void __user *to, const void *from) |
137 | { | 192 | { |
138 | if (segment_eq(get_fs(), KERNEL_DS)) { | 193 | if (segment_eq(get_fs(), KERNEL_DS)) |
139 | memcpy((void __kernel __force *) to, from, n); | 194 | return copy_in_kernel(n, to, (void __user *) from); |
140 | return 0; | ||
141 | } | ||
142 | return __user_copy_pt((unsigned long) to, (void *) from, n, 1); | 195 | return __user_copy_pt((unsigned long) to, (void *) from, n, 1); |
143 | } | 196 | } |
144 | 197 | ||
145 | static size_t clear_user_pt(size_t n, void __user *to) | 198 | static size_t clear_user_pt(size_t n, void __user *to) |
146 | { | 199 | { |
200 | void *zpage = &empty_zero_page; | ||
147 | long done, size, ret; | 201 | long done, size, ret; |
148 | 202 | ||
149 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
150 | memset((void __kernel __force *) to, 0, n); | ||
151 | return 0; | ||
152 | } | ||
153 | done = 0; | 203 | done = 0; |
154 | do { | 204 | do { |
155 | if (n - done > PAGE_SIZE) | 205 | if (n - done > PAGE_SIZE) |
156 | size = PAGE_SIZE; | 206 | size = PAGE_SIZE; |
157 | else | 207 | else |
158 | size = n - done; | 208 | size = n - done; |
159 | ret = __user_copy_pt((unsigned long) to + done, | 209 | if (segment_eq(get_fs(), KERNEL_DS)) |
160 | &empty_zero_page, size, 1); | 210 | ret = copy_in_kernel(n, to, (void __user *) zpage); |
211 | else | ||
212 | ret = __user_copy_pt((unsigned long) to, zpage, size, 1); | ||
161 | done += size; | 213 | done += size; |
214 | to += size; | ||
162 | if (ret) | 215 | if (ret) |
163 | return ret + n - done; | 216 | return ret + n - done; |
164 | } while (done < n); | 217 | } while (done < n); |
@@ -172,8 +225,10 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) | |||
172 | unsigned long offset, done, len, kaddr; | 225 | unsigned long offset, done, len, kaddr; |
173 | size_t len_str; | 226 | size_t len_str; |
174 | 227 | ||
228 | if (unlikely(!count)) | ||
229 | return 0; | ||
175 | if (segment_eq(get_fs(), KERNEL_DS)) | 230 | if (segment_eq(get_fs(), KERNEL_DS)) |
176 | return strnlen((const char __kernel __force *) src, count) + 1; | 231 | return strnlen_kernel(count, src); |
177 | done = 0; | 232 | done = 0; |
178 | retry: | 233 | retry: |
179 | spin_lock(&mm->page_table_lock); | 234 | spin_lock(&mm->page_table_lock); |
@@ -200,25 +255,27 @@ fault: | |||
200 | static size_t strncpy_from_user_pt(size_t count, const char __user *src, | 255 | static size_t strncpy_from_user_pt(size_t count, const char __user *src, |
201 | char *dst) | 256 | char *dst) |
202 | { | 257 | { |
203 | size_t n = strnlen_user_pt(count, src); | 258 | size_t done, len, offset, len_str; |
204 | 259 | ||
205 | if (!n) | 260 | if (unlikely(!count)) |
206 | return -EFAULT; | 261 | return 0; |
207 | if (n > count) | 262 | done = 0; |
208 | n = count; | 263 | do { |
209 | if (segment_eq(get_fs(), KERNEL_DS)) { | 264 | offset = (size_t)src & ~PAGE_MASK; |
210 | memcpy(dst, (const char __kernel __force *) src, n); | 265 | len = min(count - done, PAGE_SIZE - offset); |
211 | if (dst[n-1] == '\0') | 266 | if (segment_eq(get_fs(), KERNEL_DS)) { |
212 | return n-1; | 267 | if (copy_in_kernel(len, (void __user *) dst, src)) |
213 | else | 268 | return -EFAULT; |
214 | return n; | 269 | } else { |
215 | } | 270 | if (__user_copy_pt((unsigned long) src, dst, len, 0)) |
216 | if (__user_copy_pt((unsigned long) src, dst, n, 0)) | 271 | return -EFAULT; |
217 | return -EFAULT; | 272 | } |
218 | if (dst[n-1] == '\0') | 273 | len_str = strnlen(dst, len); |
219 | return n-1; | 274 | done += len_str; |
220 | else | 275 | src += len_str; |
221 | return n; | 276 | dst += len_str; |
277 | } while ((len_str == len) && (done < count)); | ||
278 | return done; | ||
222 | } | 279 | } |
223 | 280 | ||
224 | static size_t copy_in_user_pt(size_t n, void __user *to, | 281 | static size_t copy_in_user_pt(size_t n, void __user *to, |
@@ -231,10 +288,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to, | |||
231 | unsigned long kaddr_to, kaddr_from; | 288 | unsigned long kaddr_to, kaddr_from; |
232 | int write_user; | 289 | int write_user; |
233 | 290 | ||
234 | if (segment_eq(get_fs(), KERNEL_DS)) { | 291 | if (segment_eq(get_fs(), KERNEL_DS)) |
235 | memcpy((void __force *) to, (void __force *) from, n); | 292 | return copy_in_kernel(n, to, from); |
236 | return 0; | ||
237 | } | ||
238 | done = 0; | 293 | done = 0; |
239 | retry: | 294 | retry: |
240 | spin_lock(&mm->page_table_lock); | 295 | spin_lock(&mm->page_table_lock); |
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 6fbd06338270..4a75d475b06a 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c | |||
@@ -188,6 +188,8 @@ size_t strnlen_user_std(size_t size, const char __user *src) | |||
188 | register unsigned long reg0 asm("0") = 0UL; | 188 | register unsigned long reg0 asm("0") = 0UL; |
189 | unsigned long tmp1, tmp2; | 189 | unsigned long tmp1, tmp2; |
190 | 190 | ||
191 | if (unlikely(!size)) | ||
192 | return 0; | ||
191 | asm volatile( | 193 | asm volatile( |
192 | " la %2,0(%1)\n" | 194 | " la %2,0(%1)\n" |
193 | " la %3,0(%0,%1)\n" | 195 | " la %3,0(%0,%1)\n" |
@@ -204,38 +206,24 @@ size_t strnlen_user_std(size_t size, const char __user *src) | |||
204 | return size; | 206 | return size; |
205 | } | 207 | } |
206 | 208 | ||
207 | size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) | 209 | size_t strncpy_from_user_std(size_t count, const char __user *src, char *dst) |
208 | { | 210 | { |
209 | register unsigned long reg0 asm("0") = 0UL; | 211 | size_t done, len, offset, len_str; |
210 | unsigned long tmp1, tmp2; | ||
211 | 212 | ||
212 | asm volatile( | 213 | if (unlikely(!count)) |
213 | " la %3,0(%1)\n" | 214 | return 0; |
214 | " la %4,0(%0,%1)\n" | 215 | done = 0; |
215 | " sacf 256\n" | 216 | do { |
216 | "0: srst %4,%3\n" | 217 | offset = (size_t)src & ~PAGE_MASK; |
217 | " jo 0b\n" | 218 | len = min(count - done, PAGE_SIZE - offset); |
218 | " sacf 0\n" | 219 | if (copy_from_user_std(len, src, dst)) |
219 | " la %0,0(%4)\n" | 220 | return -EFAULT; |
220 | " jh 1f\n" /* found \0 in string ? */ | 221 | len_str = strnlen(dst, len); |
221 | " "AHI" %4,1\n" /* include \0 in copy */ | 222 | done += len_str; |
222 | "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ | 223 | src += len_str; |
223 | " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ | 224 | dst += len_str; |
224 | "2: mvcp 0(%4,%2),0(%1),%5\n" | 225 | } while ((len_str == len) && (done < count)); |
225 | " jz 9f\n" | 226 | return done; |
226 | "3:"AHI" %4,-256\n" | ||
227 | " la %1,256(%1)\n" | ||
228 | " la %2,256(%2)\n" | ||
229 | "4: mvcp 0(%4,%2),0(%1),%5\n" | ||
230 | " jnz 3b\n" | ||
231 | " j 9f\n" | ||
232 | "7: sacf 0\n" | ||
233 | "8:"LHI" %0,%6\n" | ||
234 | "9:\n" | ||
235 | EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b) | ||
236 | : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2) | ||
237 | : "d" (reg0), "K" (-EFAULT) : "cc", "memory"); | ||
238 | return size; | ||
239 | } | 227 | } |
240 | 228 | ||
241 | #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ | 229 | #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ |