diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfssvc.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 31e1f9593457..59979f0bbd4b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -747,6 +747,37 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) | |||
747 | return nfserr; | 747 | return nfserr; |
748 | } | 748 | } |
749 | 749 | ||
750 | /* | ||
751 | * A write procedure can have a large argument, and a read procedure can | ||
752 | * have a large reply, but no NFSv2 or NFSv3 procedure has argument and | ||
753 | * reply that can both be larger than a page. The xdr code has taken | ||
754 | * advantage of this assumption to be a sloppy about bounds checking in | ||
755 | * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that | ||
756 | * problem, we enforce these assumptions here: | ||
757 | */ | ||
758 | static bool nfs_request_too_big(struct svc_rqst *rqstp, | ||
759 | struct svc_procedure *proc) | ||
760 | { | ||
761 | /* | ||
762 | * The ACL code has more careful bounds-checking and is not | ||
763 | * susceptible to this problem: | ||
764 | */ | ||
765 | if (rqstp->rq_prog != NFS_PROGRAM) | ||
766 | return false; | ||
767 | /* | ||
768 | * Ditto NFSv4 (which can in theory have argument and reply both | ||
769 | * more than a page): | ||
770 | */ | ||
771 | if (rqstp->rq_vers >= 4) | ||
772 | return false; | ||
773 | /* The reply will be small, we're OK: */ | ||
774 | if (proc->pc_xdrressize > 0 && | ||
775 | proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) | ||
776 | return false; | ||
777 | |||
778 | return rqstp->rq_arg.len > PAGE_SIZE; | ||
779 | } | ||
780 | |||
750 | int | 781 | int |
751 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | 782 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
752 | { | 783 | { |
@@ -759,6 +790,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
759 | rqstp->rq_vers, rqstp->rq_proc); | 790 | rqstp->rq_vers, rqstp->rq_proc); |
760 | proc = rqstp->rq_procinfo; | 791 | proc = rqstp->rq_procinfo; |
761 | 792 | ||
793 | if (nfs_request_too_big(rqstp, proc)) { | ||
794 | dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); | ||
795 | *statp = rpc_garbage_args; | ||
796 | return 1; | ||
797 | } | ||
762 | /* | 798 | /* |
763 | * Give the xdr decoder a chance to change this if it wants | 799 | * Give the xdr decoder a chance to change this if it wants |
764 | * (necessary in the NFSv4.0 compound case) | 800 | * (necessary in the NFSv4.0 compound case) |