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

[MIPS] RTLX: Handle copy_*_user return values.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+37 -31
+14 -4
arch/mips/kernel/kspd.c
··· 191 191 struct mtsp_syscall_generic generic; 192 192 struct mtsp_syscall_ret ret; 193 193 struct kspd_notifications *n; 194 + unsigned long written; 195 + mm_segment_t old_fs; 194 196 struct timeval tv; 195 197 struct timezone tz; 196 198 int cmd; ··· 203 201 204 202 ret.retval = -1; 205 203 206 - if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall), 0)) { 204 + old_fs = get_fs(); 205 + set_fs(KERNEL_DS); 206 + 207 + if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall))) { 208 + set_fs(old_fs); 207 209 printk(KERN_ERR "Expected request but nothing to read\n"); 208 210 return; 209 211 } ··· 215 209 size = sc.size; 216 210 217 211 if (size) { 218 - if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size, 0)) { 212 + if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size)) { 213 + set_fs(old_fs); 219 214 printk(KERN_ERR "Expected request but nothing to read\n"); 220 215 return; 221 216 } ··· 289 282 if (vpe_getuid(SP_VPE)) 290 283 sp_setfsuidgid( 0, 0); 291 284 292 - if ((rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(struct mtsp_syscall_ret), 0)) 293 - < sizeof(struct mtsp_syscall_ret)) 285 + old_fs = get_fs(); 286 + set_fs(KERNEL_DS); 287 + written = rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(ret)); 288 + set_fs(old_fs); 289 + if (written < sizeof(ret)) 294 290 printk("KSPD: sp_work_handle_request failed to send to SP\n"); 295 291 } 296 292
+21 -25
arch/mips/kernel/rtlx.c
··· 289 289 return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); 290 290 } 291 291 292 - static inline void copy_to(void *dst, void *src, size_t count, int user) 293 - { 294 - if (user) 295 - copy_to_user(dst, src, count); 296 - else 297 - memcpy(dst, src, count); 298 - } 299 - 300 - static inline void copy_from(void *dst, void *src, size_t count, int user) 301 - { 302 - if (user) 303 - copy_from_user(dst, src, count); 304 - else 305 - memcpy(dst, src, count); 306 - } 307 - 308 - ssize_t rtlx_read(int index, void *buff, size_t count, int user) 292 + ssize_t rtlx_read(int index, void __user *buff, size_t count, int user) 309 293 { 310 294 size_t lx_write, fl = 0L; 311 295 struct rtlx_channel *lx; 296 + unsigned long failed; 312 297 313 298 if (rtlx == NULL) 314 299 return -ENOSYS; ··· 312 327 /* then how much from the read pointer onwards */ 313 328 fl = min(count, (size_t)lx->buffer_size - lx->lx_read); 314 329 315 - copy_to(buff, lx->lx_buffer + lx->lx_read, fl, user); 330 + failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl); 331 + if (failed) 332 + goto out; 316 333 317 334 /* and if there is anything left at the beginning of the buffer */ 318 335 if (count - fl) 319 - copy_to(buff + fl, lx->lx_buffer, count - fl, user); 336 + failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl); 337 + 338 + out: 339 + count -= failed; 320 340 321 341 smp_wmb(); 322 342 lx->lx_read = (lx->lx_read + count) % lx->buffer_size; ··· 331 341 return count; 332 342 } 333 343 334 - ssize_t rtlx_write(int index, void *buffer, size_t count, int user) 344 + ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user) 335 345 { 336 346 struct rtlx_channel *rt; 337 347 size_t rt_read; ··· 353 363 /* first bit from write pointer to the end of the buffer, or count */ 354 364 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 355 365 356 - copy_from(rt->rt_buffer + rt->rt_write, buffer, fl, user); 366 + failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl); 367 + if (failed) 368 + goto out; 357 369 358 370 /* if there's any left copy to the beginning of the buffer */ 359 - if (count - fl) 360 - copy_from(rt->rt_buffer, buffer + fl, count - fl, user); 371 + if (count - fl) { 372 + failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl); 373 + } 374 + 375 + out: 376 + count -= cailed; 361 377 362 378 smp_wmb(); 363 379 rt->rt_write = (rt->rt_write + count) % rt->buffer_size; ··· 422 426 return 0; // -EAGAIN makes cat whinge 423 427 } 424 428 425 - return rtlx_read(minor, buffer, count, 1); 429 + return rtlx_read(minor, buffer, count); 426 430 } 427 431 428 432 static ssize_t file_write(struct file *file, const char __user * buffer, ··· 448 452 return ret; 449 453 } 450 454 451 - return rtlx_write(minor, (void *)buffer, count, 1); 455 + return rtlx_write(minor, buffer, count); 452 456 } 453 457 454 458 static const struct file_operations rtlx_fops = {
+2 -2
include/asm-mips/rtlx.h
··· 23 23 24 24 extern int rtlx_open(int index, int can_sleep); 25 25 extern int rtlx_release(int index); 26 - extern ssize_t rtlx_read(int index, void *buff, size_t count, int user); 27 - extern ssize_t rtlx_write(int index, void *buffer, size_t count, int user); 26 + extern ssize_t rtlx_read(int index, void __user *buff, size_t count); 27 + extern ssize_t rtlx_write(int index, const void __user *buffer, size_t count); 28 28 extern unsigned int rtlx_read_poll(int index, int can_sleep); 29 29 extern unsigned int rtlx_write_poll(int index); 30 30