diff options
author | Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> | 2010-05-27 05:58:03 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2010-05-27 06:54:59 -0400 |
commit | 7ad9c9d27048547e96e4e3a13b5780ec6f81bb9f (patch) | |
tree | 0f70562d0f51c086b02953388578bd87040b5067 /drivers/vhost | |
parent | 0f3d9a17469d71ba1bab79c07c8eecb9e26e60af (diff) |
vhost: fix to check the return value of copy_to/from_user() correctly
copy_to/from_user() returns the number of bytes that could not be copied.
So we need to check if it is not zero, and in that case, we should return
the error number -EFAULT rather than directly return the return value from
copy_to/from_user().
Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'drivers/vhost')
-rw-r--r-- | drivers/vhost/vhost.c | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 44f123abb0f4..e36620272715 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c | |||
@@ -320,10 +320,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) | |||
320 | { | 320 | { |
321 | struct vhost_memory mem, *newmem, *oldmem; | 321 | struct vhost_memory mem, *newmem, *oldmem; |
322 | unsigned long size = offsetof(struct vhost_memory, regions); | 322 | unsigned long size = offsetof(struct vhost_memory, regions); |
323 | long r; | 323 | if (copy_from_user(&mem, m, size)) |
324 | r = copy_from_user(&mem, m, size); | 324 | return -EFAULT; |
325 | if (r) | ||
326 | return r; | ||
327 | if (mem.padding) | 325 | if (mem.padding) |
328 | return -EOPNOTSUPP; | 326 | return -EOPNOTSUPP; |
329 | if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS) | 327 | if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS) |
@@ -333,11 +331,10 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) | |||
333 | return -ENOMEM; | 331 | return -ENOMEM; |
334 | 332 | ||
335 | memcpy(newmem, &mem, size); | 333 | memcpy(newmem, &mem, size); |
336 | r = copy_from_user(newmem->regions, m->regions, | 334 | if (copy_from_user(newmem->regions, m->regions, |
337 | mem.nregions * sizeof *m->regions); | 335 | mem.nregions * sizeof *m->regions)) { |
338 | if (r) { | ||
339 | kfree(newmem); | 336 | kfree(newmem); |
340 | return r; | 337 | return -EFAULT; |
341 | } | 338 | } |
342 | 339 | ||
343 | if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) | 340 | if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) |
@@ -389,9 +386,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
389 | r = -EBUSY; | 386 | r = -EBUSY; |
390 | break; | 387 | break; |
391 | } | 388 | } |
392 | r = copy_from_user(&s, argp, sizeof s); | 389 | if (copy_from_user(&s, argp, sizeof s)) { |
393 | if (r < 0) | 390 | r = -EFAULT; |
394 | break; | 391 | break; |
392 | } | ||
395 | if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) { | 393 | if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) { |
396 | r = -EINVAL; | 394 | r = -EINVAL; |
397 | break; | 395 | break; |
@@ -405,9 +403,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
405 | r = -EBUSY; | 403 | r = -EBUSY; |
406 | break; | 404 | break; |
407 | } | 405 | } |
408 | r = copy_from_user(&s, argp, sizeof s); | 406 | if (copy_from_user(&s, argp, sizeof s)) { |
409 | if (r < 0) | 407 | r = -EFAULT; |
410 | break; | 408 | break; |
409 | } | ||
411 | if (s.num > 0xffff) { | 410 | if (s.num > 0xffff) { |
412 | r = -EINVAL; | 411 | r = -EINVAL; |
413 | break; | 412 | break; |
@@ -419,12 +418,14 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
419 | case VHOST_GET_VRING_BASE: | 418 | case VHOST_GET_VRING_BASE: |
420 | s.index = idx; | 419 | s.index = idx; |
421 | s.num = vq->last_avail_idx; | 420 | s.num = vq->last_avail_idx; |
422 | r = copy_to_user(argp, &s, sizeof s); | 421 | if (copy_to_user(argp, &s, sizeof s)) |
422 | r = -EFAULT; | ||
423 | break; | 423 | break; |
424 | case VHOST_SET_VRING_ADDR: | 424 | case VHOST_SET_VRING_ADDR: |
425 | r = copy_from_user(&a, argp, sizeof a); | 425 | if (copy_from_user(&a, argp, sizeof a)) { |
426 | if (r < 0) | 426 | r = -EFAULT; |
427 | break; | 427 | break; |
428 | } | ||
428 | if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) { | 429 | if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) { |
429 | r = -EOPNOTSUPP; | 430 | r = -EOPNOTSUPP; |
430 | break; | 431 | break; |
@@ -477,9 +478,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
477 | vq->used = (void __user *)(unsigned long)a.used_user_addr; | 478 | vq->used = (void __user *)(unsigned long)a.used_user_addr; |
478 | break; | 479 | break; |
479 | case VHOST_SET_VRING_KICK: | 480 | case VHOST_SET_VRING_KICK: |
480 | r = copy_from_user(&f, argp, sizeof f); | 481 | if (copy_from_user(&f, argp, sizeof f)) { |
481 | if (r < 0) | 482 | r = -EFAULT; |
482 | break; | 483 | break; |
484 | } | ||
483 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); | 485 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); |
484 | if (IS_ERR(eventfp)) { | 486 | if (IS_ERR(eventfp)) { |
485 | r = PTR_ERR(eventfp); | 487 | r = PTR_ERR(eventfp); |
@@ -492,9 +494,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
492 | filep = eventfp; | 494 | filep = eventfp; |
493 | break; | 495 | break; |
494 | case VHOST_SET_VRING_CALL: | 496 | case VHOST_SET_VRING_CALL: |
495 | r = copy_from_user(&f, argp, sizeof f); | 497 | if (copy_from_user(&f, argp, sizeof f)) { |
496 | if (r < 0) | 498 | r = -EFAULT; |
497 | break; | 499 | break; |
500 | } | ||
498 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); | 501 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); |
499 | if (IS_ERR(eventfp)) { | 502 | if (IS_ERR(eventfp)) { |
500 | r = PTR_ERR(eventfp); | 503 | r = PTR_ERR(eventfp); |
@@ -510,9 +513,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) | |||
510 | filep = eventfp; | 513 | filep = eventfp; |
511 | break; | 514 | break; |
512 | case VHOST_SET_VRING_ERR: | 515 | case VHOST_SET_VRING_ERR: |
513 | r = copy_from_user(&f, argp, sizeof f); | 516 | if (copy_from_user(&f, argp, sizeof f)) { |
514 | if (r < 0) | 517 | r = -EFAULT; |
515 | break; | 518 | break; |
519 | } | ||
516 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); | 520 | eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); |
517 | if (IS_ERR(eventfp)) { | 521 | if (IS_ERR(eventfp)) { |
518 | r = PTR_ERR(eventfp); | 522 | r = PTR_ERR(eventfp); |
@@ -575,9 +579,10 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg) | |||
575 | r = vhost_set_memory(d, argp); | 579 | r = vhost_set_memory(d, argp); |
576 | break; | 580 | break; |
577 | case VHOST_SET_LOG_BASE: | 581 | case VHOST_SET_LOG_BASE: |
578 | r = copy_from_user(&p, argp, sizeof p); | 582 | if (copy_from_user(&p, argp, sizeof p)) { |
579 | if (r < 0) | 583 | r = -EFAULT; |
580 | break; | 584 | break; |
585 | } | ||
581 | if ((u64)(unsigned long)p != p) { | 586 | if ((u64)(unsigned long)p != p) { |
582 | r = -EFAULT; | 587 | r = -EFAULT; |
583 | break; | 588 | break; |