SUNRPC: Decode most of RPC header with xdr_stream
authorChuck Lever <chuck.lever@oracle.com>
Mon, 2 Jan 2023 17:07:52 +0000 (12:07 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 20 Feb 2023 14:20:21 +0000 (09:20 -0500)
Done as part of hardening the server-side RPC header decoding path.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
net/sunrpc/svc.c

index c3c80d2..2cc8049 100644 (file)
@@ -1231,17 +1231,13 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        const struct svc_procedure *procp = NULL;
        struct svc_serv         *serv = rqstp->rq_server;
        struct svc_process_info process;
-       __be32                  *statp;
-       u32                     vers;
+       __be32                  *p, *statp;
        __be32                  rpc_stat;
        int                     auth_res, rc;
        __be32                  *reply_statp;
 
        rpc_stat = rpc_success;
 
-       if (argv->iov_len < 6*4)
-               goto err_short_len;
-
        /* Will be turned off by GSS integrity and privacy services */
        set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
        /* Will be turned off only when NFSv4 Sessions are used */
@@ -1253,15 +1249,18 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        svc_putnl(resv, RPC_REPLY);
        reply_statp = resv->iov_base + resv->iov_len;
 
-       vers = svc_getnl(argv);
-       if (vers != 2)          /* RPC version number */
+       svcxdr_init_decode(rqstp);
+       p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 4);
+       if (unlikely(!p))
+               goto err_short_len;
+       if (*p++ != cpu_to_be32(RPC_VERSION))
                goto err_bad_rpc;
 
        svc_putnl(resv, 0);             /* ACCEPT */
 
-       rqstp->rq_prog = svc_getnl(argv);       /* program number */
-       rqstp->rq_vers = svc_getnl(argv);       /* version number */
-       rqstp->rq_proc = svc_getnl(argv);       /* procedure number */
+       rqstp->rq_prog = be32_to_cpup(p++);
+       rqstp->rq_vers = be32_to_cpup(p++);
+       rqstp->rq_proc = be32_to_cpup(p);
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next)
                if (rqstp->rq_prog == progp->pg_prog)
@@ -1272,7 +1271,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
         * We do this before anything else in order to get a decent
         * auth verifier.
         */
-       svcxdr_init_decode(rqstp);
        auth_res = svc_authenticate(rqstp);
        /* Also give the program a chance to reject this call: */
        if (auth_res == SVC_OK && progp)