diff options
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-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)); |