diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-08-20 17:05:21 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-09-13 17:49:44 -0400 |
commit | acb2505d0119033a80c85ac8d02dccae41271667 (patch) | |
tree | 5537954675e9bd923ab1bfe1fea29806e6334ae6 | |
parent | 2e29f50ad5e23db37dde9be71410d95d50241ecd (diff) |
openrisc: fix copy_from_user()
... that should zero on faults. Also remove the <censored> helpful
logics wrt range truncation copied from ppc32. Where it had ever
been needed only in case of copy_from_user() *and* had not been merged
into the mainline until a month after the need had disappeared.
A decade before openrisc went into mainline, I might add...
Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/openrisc/include/asm/uaccess.h | 35 |
1 files changed, 11 insertions, 24 deletions
diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index a6bd07ca3d6c..cbad29b5a131 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h | |||
@@ -273,28 +273,20 @@ __copy_tofrom_user(void *to, const void *from, unsigned long size); | |||
273 | static inline unsigned long | 273 | static inline unsigned long |
274 | copy_from_user(void *to, const void *from, unsigned long n) | 274 | copy_from_user(void *to, const void *from, unsigned long n) |
275 | { | 275 | { |
276 | unsigned long over; | 276 | unsigned long res = n; |
277 | 277 | ||
278 | if (access_ok(VERIFY_READ, from, n)) | 278 | if (likely(access_ok(VERIFY_READ, from, n))) |
279 | return __copy_tofrom_user(to, from, n); | 279 | n = __copy_tofrom_user(to, from, n); |
280 | if ((unsigned long)from < TASK_SIZE) { | 280 | if (unlikely(res)) |
281 | over = (unsigned long)from + n - TASK_SIZE; | 281 | memset(to + (n - res), 0, res); |
282 | return __copy_tofrom_user(to, from, n - over) + over; | 282 | return res; |
283 | } | ||
284 | return n; | ||
285 | } | 283 | } |
286 | 284 | ||
287 | static inline unsigned long | 285 | static inline unsigned long |
288 | copy_to_user(void *to, const void *from, unsigned long n) | 286 | copy_to_user(void *to, const void *from, unsigned long n) |
289 | { | 287 | { |
290 | unsigned long over; | 288 | if (likely(access_ok(VERIFY_WRITE, to, n))) |
291 | 289 | n = __copy_tofrom_user(to, from, n); | |
292 | if (access_ok(VERIFY_WRITE, to, n)) | ||
293 | return __copy_tofrom_user(to, from, n); | ||
294 | if ((unsigned long)to < TASK_SIZE) { | ||
295 | over = (unsigned long)to + n - TASK_SIZE; | ||
296 | return __copy_tofrom_user(to, from, n - over) + over; | ||
297 | } | ||
298 | return n; | 290 | return n; |
299 | } | 291 | } |
300 | 292 | ||
@@ -303,13 +295,8 @@ extern unsigned long __clear_user(void *addr, unsigned long size); | |||
303 | static inline __must_check unsigned long | 295 | static inline __must_check unsigned long |
304 | clear_user(void *addr, unsigned long size) | 296 | clear_user(void *addr, unsigned long size) |
305 | { | 297 | { |
306 | 298 | if (likely(access_ok(VERIFY_WRITE, addr, size))) | |
307 | if (access_ok(VERIFY_WRITE, addr, size)) | 299 | size = __clear_user(addr, size); |
308 | return __clear_user(addr, size); | ||
309 | if ((unsigned long)addr < TASK_SIZE) { | ||
310 | unsigned long over = (unsigned long)addr + size - TASK_SIZE; | ||
311 | return __clear_user(addr, size - over) + over; | ||
312 | } | ||
313 | return size; | 300 | return size; |
314 | } | 301 | } |
315 | 302 | ||