diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2013-05-20 13:35:15 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2013-05-28 12:47:57 -0400 |
commit | 6390460af8a672754dd6743f326515e98f52b2a7 (patch) | |
tree | 34acc07818dc1412d7d390025b4bf303b56530cf /net/9p | |
parent | c1be5a5b1b355d40e6cf79cc979eb66dafa24ad1 (diff) |
net/9p: Handle error in zero copy request correctly for 9p2000.u
For zero copy request, error will be encoded in the user space buffer.
So copy the error code correctly using copy_from_user. Here we use the
extra bytes we allocate for zero copy request. If total error details
are more than P9_ZC_HDR_SZ - 7 bytes, we return -EFAULT. The patch also
avoid a memory allocation in the error path.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'net/9p')
-rw-r--r-- | net/9p/client.c | 55 |
1 files changed, 18 insertions, 37 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 8eb75425e6e6..addc116cecf0 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -562,36 +562,19 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | |||
562 | 562 | ||
563 | if (!p9_is_proto_dotl(c)) { | 563 | if (!p9_is_proto_dotl(c)) { |
564 | /* Error is reported in string format */ | 564 | /* Error is reported in string format */ |
565 | uint16_t len; | 565 | int len; |
566 | /* 7 = header size for RERROR, 2 is the size of string len; */ | 566 | /* 7 = header size for RERROR; */ |
567 | int inline_len = in_hdrlen - (7 + 2); | 567 | int inline_len = in_hdrlen - 7; |
568 | 568 | ||
569 | /* Read the size of error string */ | 569 | len = req->rc->size - req->rc->offset; |
570 | err = p9pdu_readf(req->rc, c->proto_version, "w", &len); | 570 | if (len > (P9_ZC_HDR_SZ - 7)) { |
571 | if (err) | 571 | err = -EFAULT; |
572 | goto out_err; | ||
573 | |||
574 | ename = kmalloc(len + 1, GFP_NOFS); | ||
575 | if (!ename) { | ||
576 | err = -ENOMEM; | ||
577 | goto out_err; | 572 | goto out_err; |
578 | } | 573 | } |
579 | if (len <= inline_len) { | ||
580 | /* We have error in protocol buffer itself */ | ||
581 | if (pdu_read(req->rc, ename, len)) { | ||
582 | err = -EFAULT; | ||
583 | goto out_free; | ||
584 | 574 | ||
585 | } | 575 | ename = &req->rc->sdata[req->rc->offset]; |
586 | } else { | 576 | if (len > inline_len) { |
587 | /* | 577 | /* We have error in external buffer */ |
588 | * Part of the data is in user space buffer. | ||
589 | */ | ||
590 | if (pdu_read(req->rc, ename, inline_len)) { | ||
591 | err = -EFAULT; | ||
592 | goto out_free; | ||
593 | |||
594 | } | ||
595 | if (kern_buf) { | 578 | if (kern_buf) { |
596 | memcpy(ename + inline_len, uidata, | 579 | memcpy(ename + inline_len, uidata, |
597 | len - inline_len); | 580 | len - inline_len); |
@@ -600,19 +583,19 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | |||
600 | uidata, len - inline_len); | 583 | uidata, len - inline_len); |
601 | if (err) { | 584 | if (err) { |
602 | err = -EFAULT; | 585 | err = -EFAULT; |
603 | goto out_free; | 586 | goto out_err; |
604 | } | 587 | } |
605 | } | 588 | } |
606 | } | 589 | } |
607 | ename[len] = 0; | 590 | ename = NULL; |
608 | if (p9_is_proto_dotu(c)) { | 591 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", |
609 | /* For dotu we also have error code */ | 592 | &ename, &ecode); |
610 | err = p9pdu_readf(req->rc, | 593 | if (err) |
611 | c->proto_version, "d", &ecode); | 594 | goto out_err; |
612 | if (err) | 595 | |
613 | goto out_free; | 596 | if (p9_is_proto_dotu(c)) |
614 | err = -ecode; | 597 | err = -ecode; |
615 | } | 598 | |
616 | if (!err || !IS_ERR_VALUE(err)) { | 599 | if (!err || !IS_ERR_VALUE(err)) { |
617 | err = p9_errstr2errno(ename, strlen(ename)); | 600 | err = p9_errstr2errno(ename, strlen(ename)); |
618 | 601 | ||
@@ -628,8 +611,6 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | |||
628 | } | 611 | } |
629 | return err; | 612 | return err; |
630 | 613 | ||
631 | out_free: | ||
632 | kfree(ename); | ||
633 | out_err: | 614 | out_err: |
634 | p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); | 615 | p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); |
635 | return err; | 616 | return err; |