diff options
author | Andy Adamson <andros@netapp.com> | 2010-01-14 17:45:04 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-02-10 08:30:56 -0500 |
commit | 31d2b4356b054537c35f4f8a7533e0b4a494dcc6 (patch) | |
tree | 22a46ee42a65ad2f15785337a803305fbd018c14 /fs | |
parent | 72ce2b3c064471fc511a9ca2fb6c38d90d2ab826 (diff) |
nfs41: fix wrong error on callback header xdr overflow
Set NFS4ERR_RESOURCE as CB_COMPOUND status and do not return an op on
decode_op_hdr or encode_op_hdr buffer overflow.
NFS4ERR_RESOURCE is correct for v4.0. Will fix the return for v4.1 along with
all the other NFS4ERR_RESOURCE errors in a later patch.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/callback_xdr.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 8e1a2511c8be..6ae327871b86 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -28,6 +28,9 @@ | |||
28 | 28 | ||
29 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 29 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
30 | 30 | ||
31 | /* Internal error code */ | ||
32 | #define NFS4ERR_RESOURCE_HDR 11050 | ||
33 | |||
31 | typedef __be32 (*callback_process_op_t)(void *, void *); | 34 | typedef __be32 (*callback_process_op_t)(void *, void *); |
32 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); | 35 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); |
33 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); | 36 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); |
@@ -173,7 +176,7 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) | |||
173 | __be32 *p; | 176 | __be32 *p; |
174 | p = read_buf(xdr, 4); | 177 | p = read_buf(xdr, 4); |
175 | if (unlikely(p == NULL)) | 178 | if (unlikely(p == NULL)) |
176 | return htonl(NFS4ERR_RESOURCE); | 179 | return htonl(NFS4ERR_RESOURCE_HDR); |
177 | *op = ntohl(*p); | 180 | *op = ntohl(*p); |
178 | return 0; | 181 | return 0; |
179 | } | 182 | } |
@@ -465,7 +468,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) | |||
465 | 468 | ||
466 | p = xdr_reserve_space(xdr, 8); | 469 | p = xdr_reserve_space(xdr, 8); |
467 | if (unlikely(p == NULL)) | 470 | if (unlikely(p == NULL)) |
468 | return htonl(NFS4ERR_RESOURCE); | 471 | return htonl(NFS4ERR_RESOURCE_HDR); |
469 | *p++ = htonl(op); | 472 | *p++ = htonl(op); |
470 | *p = res; | 473 | *p = res; |
471 | return 0; | 474 | return 0; |
@@ -605,17 +608,15 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
605 | struct xdr_stream *xdr_out, void *resp) | 608 | struct xdr_stream *xdr_out, void *resp) |
606 | { | 609 | { |
607 | struct callback_op *op = &callback_ops[0]; | 610 | struct callback_op *op = &callback_ops[0]; |
608 | unsigned int op_nr = OP_CB_ILLEGAL; | 611 | unsigned int op_nr; |
609 | __be32 status; | 612 | __be32 status; |
610 | long maxlen; | 613 | long maxlen; |
611 | __be32 res; | 614 | __be32 res; |
612 | 615 | ||
613 | dprintk("%s: start\n", __func__); | 616 | dprintk("%s: start\n", __func__); |
614 | status = decode_op_hdr(xdr_in, &op_nr); | 617 | status = decode_op_hdr(xdr_in, &op_nr); |
615 | if (unlikely(status)) { | 618 | if (unlikely(status)) |
616 | status = htonl(NFS4ERR_OP_ILLEGAL); | 619 | return status; |
617 | goto out; | ||
618 | } | ||
619 | 620 | ||
620 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | 621 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", |
621 | __func__, minorversion, nop, op_nr); | 622 | __func__, minorversion, nop, op_nr); |
@@ -624,7 +625,7 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
624 | preprocess_nfs4_op(op_nr, &op); | 625 | preprocess_nfs4_op(op_nr, &op); |
625 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | 626 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) |
626 | op_nr = OP_CB_ILLEGAL; | 627 | op_nr = OP_CB_ILLEGAL; |
627 | out: | 628 | |
628 | maxlen = xdr_out->end - xdr_out->p; | 629 | maxlen = xdr_out->end - xdr_out->p; |
629 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 630 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
630 | if (likely(status == 0 && op->decode_args != NULL)) | 631 | if (likely(status == 0 && op->decode_args != NULL)) |
@@ -635,8 +636,8 @@ out: | |||
635 | status = htonl(NFS4ERR_RESOURCE); | 636 | status = htonl(NFS4ERR_RESOURCE); |
636 | 637 | ||
637 | res = encode_op_hdr(xdr_out, op_nr, status); | 638 | res = encode_op_hdr(xdr_out, op_nr, status); |
638 | if (status == 0) | 639 | if (unlikely(res)) |
639 | status = res; | 640 | return res; |
640 | if (op->encode_res != NULL && status == 0) | 641 | if (op->encode_res != NULL && status == 0) |
641 | status = op->encode_res(rqstp, xdr_out, resp); | 642 | status = op->encode_res(rqstp, xdr_out, resp); |
642 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); | 643 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); |
@@ -677,6 +678,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
677 | nops++; | 678 | nops++; |
678 | } | 679 | } |
679 | 680 | ||
681 | /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return | ||
682 | * resource error in cb_compound status without returning op */ | ||
683 | if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) { | ||
684 | status = htonl(NFS4ERR_RESOURCE); | ||
685 | nops--; | ||
686 | } | ||
687 | |||
680 | *hdr_res.status = status; | 688 | *hdr_res.status = status; |
681 | *hdr_res.nops = htonl(nops); | 689 | *hdr_res.nops = htonl(nops); |
682 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); | 690 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); |