Skip to content

Commit 3e7f011

Browse files
committed
Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND"
I've found that pynfs COMP6 now leaves the connection or lease in a strange state, which causes CLOSE9 to hang indefinitely. I've dug into it a little, but I haven't been able to root-cause it yet. However, I bisected to commit 48aab16 ("NFSD: Remove the cap on number of operations per NFSv4 COMPOUND"). Tianshuo Han also reports a potential vulnerability when decoding an NFSv4 COMPOUND. An attacker can place an arbitrarily large op count in the COMPOUND header, which results in: [ 51.410584] nfsd: vmalloc error: size 1209533382144, exceeds total pages, mode:0xdc0(GFP_KERNEL|__GFP_ZERO), nodemask=(null),cpuset=/,mems_allowed=0 when NFSD attempts to allocate the COMPOUND op array. Let's restore the operation-per-COMPOUND limit, but increased to 200 for now. Reported-by: tianshuo han <hantianshuo233@gmail.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Cc: stable@vger.kernel.org Tested-by: Tianshuo Han <hantianshuo233@gmail.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 29cdfb4 commit 3e7f011

File tree

5 files changed

+20
-3
lines changed

5 files changed

+20
-3
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,10 +2893,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
28932893

28942894
rqstp->rq_lease_breaker = (void **)&cstate->clp;
28952895

2896-
trace_nfsd_compound(rqstp, args->tag, args->taglen, args->opcnt);
2896+
trace_nfsd_compound(rqstp, args->tag, args->taglen, args->client_opcnt);
28972897
while (!status && resp->opcnt < args->opcnt) {
28982898
op = &args->ops[resp->opcnt++];
28992899

2900+
if (unlikely(resp->opcnt == NFSD_MAX_OPS_PER_COMPOUND)) {
2901+
/* If there are still more operations to process,
2902+
* stop here and report NFS4ERR_RESOURCE. */
2903+
if (cstate->minorversion == 0 &&
2904+
args->client_opcnt > resp->opcnt) {
2905+
op->status = nfserr_resource;
2906+
goto encode_op;
2907+
}
2908+
}
2909+
29002910
/*
29012911
* The XDR decode routines may have pre-set op->status;
29022912
* for example, if there is a miscellaneous XDR error
@@ -2973,7 +2983,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
29732983
status = op->status;
29742984
}
29752985

2976-
trace_nfsd_compound_status(args->opcnt, resp->opcnt,
2986+
trace_nfsd_compound_status(args->client_opcnt, resp->opcnt,
29772987
status, nfsd4_op_name(op->opnum));
29782988

29792989
nfsd4_cstate_clear_replay(cstate);

fs/nfsd/nfs4state.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3902,6 +3902,7 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
39023902
ca->headerpadsz = 0;
39033903
ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
39043904
ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
3905+
ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
39053906
ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
39063907
NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
39073908
ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);

fs/nfsd/nfs4xdr.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2488,8 +2488,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
24882488

24892489
if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0)
24902490
return false;
2491-
if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0)
2491+
if (xdr_stream_decode_u32(argp->xdr, &argp->client_opcnt) < 0)
24922492
return false;
2493+
argp->opcnt = min_t(u32, argp->client_opcnt,
2494+
NFSD_MAX_OPS_PER_COMPOUND);
24932495

24942496
if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
24952497
argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops));

fs/nfsd/nfsd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ struct readdir_cd {
5757
__be32 err; /* 0, nfserr, or nfserr_eof */
5858
};
5959

60+
/* Maximum number of operations per session compound */
61+
#define NFSD_MAX_OPS_PER_COMPOUND 200
62+
6063
struct nfsd_genl_rqstp {
6164
struct sockaddr rq_daddr;
6265
struct sockaddr rq_saddr;

fs/nfsd/xdr4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,7 @@ struct nfsd4_compoundargs {
903903
char * tag;
904904
u32 taglen;
905905
u32 minorversion;
906+
u32 client_opcnt;
906907
u32 opcnt;
907908
bool splice_ok;
908909
struct nfsd4_op *ops;

0 commit comments

Comments
 (0)