[PATCH v1 3/7] NFSD: Check for junk after RPC Call messages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The current RPC server code allows incoming RPC messages up to about
a megabyte in size. For TCP, this is based on the size value
contained in the RPC record marker.

Currently, NFSD ignores anything in the message that is past the end
of the encoded RPC Call message. A very large RPC message can arrive
with just an NFSv3 LOOKUP operation in it, and NFSD ignores the rest
of the message until the next RPC fragment in the TCP stream.

That ignored data still consumes pages in the svc_rqst's page array,
however. The current arrangement is that each svc_rqst gets about
260 pages, assuming that all supported NFS operations will never
require more than a total of 260 pages to decode a Call message
and construct its corresponding Reply message.

A clever attacker can add garbage at the end of a READ-like request,
which generally has a small Call message and a potentially large
Reply message with a payload . That makes both the Call message and
the Reply message large, and runs the svc_rqst out of pages. At the
very least, this can result in a short or empty READ or READDIR
result.

So, let's teach NFSD to look for such shenanigans and reject any
Call where the incoming RPC frame has content remaining in the
receive buffer after NFSD has decoded all of the Call arguments.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---
 fs/nfsd/nfssvc.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 4bb5baa17040..5face047ce1a 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -1027,6 +1027,7 @@ nfsd(void *vrqstp)
 int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 {
 	const struct svc_procedure *proc = rqstp->rq_procinfo;
+	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 
 	/*
 	 * Give the xdr decoder a chance to change this if it wants
@@ -1035,7 +1036,9 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 	rqstp->rq_cachetype = proc->pc_cachetype;
 
 	svcxdr_init_decode(rqstp);
-	if (!proc->pc_decode(rqstp, &rqstp->rq_arg_stream))
+	if (!proc->pc_decode(rqstp, xdr))
+		goto out_decode_err;
+	if (xdr_stream_remaining(xdr))
 		goto out_decode_err;
 
 	switch (nfsd_cache_lookup(rqstp)) {





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux