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, lockd 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 NLM LOCK operation in it, and lockd 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 NLM 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 an RPC Call message.
At the least, it can result in a short or empty NLM result.
So, let's teach lockd to look for such shenanigans and reject any
Call where the incoming RPC frame has content remaining in the
receive buffer after lockd has decoded the Call arguments.
Signed-off-by: Chuck Lever <[email protected]>
---
fs/lockd/svc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 59ef8a1f843f..80b3f1a006f6 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -694,9 +694,12 @@ module_exit(exit_nlm);
static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{
const struct svc_procedure *procp = rqstp->rq_procinfo;
+ struct xdr_stream *xdr = &rqstp->rq_arg_stream;
svcxdr_init_decode(rqstp);
- if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream))
+ if (!procp->pc_decode(rqstp, xdr))
+ goto out_decode_err;
+ if (xdr_stream_remaining(xdr))
goto out_decode_err;
*statp = procp->pc_func(rqstp);