Commit 649a692e authored by Chuck Lever's avatar Chuck Lever

SUNRPC: Convert RPC Reply header encoding to use xdr_stream

The main part of RPC header encoding and the formation of error
responses are now done using the xdr_stream helpers. Bounds checking
before each XDR data item is encoded makes the server's encoding
path safer against accidental buffer overflows.
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent fcef2aff
...@@ -1227,13 +1227,14 @@ EXPORT_SYMBOL_GPL(svc_generic_init_request); ...@@ -1227,13 +1227,14 @@ EXPORT_SYMBOL_GPL(svc_generic_init_request);
static int static int
svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
{ {
struct xdr_stream *xdr = &rqstp->rq_res_stream;
struct svc_program *progp; struct svc_program *progp;
const struct svc_procedure *procp = NULL; const struct svc_procedure *procp = NULL;
struct svc_serv *serv = rqstp->rq_server; struct svc_serv *serv = rqstp->rq_server;
struct svc_process_info process; struct svc_process_info process;
__be32 *p, *statp; __be32 *p, *statp;
int auth_res, rc; int auth_res, rc;
__be32 *reply_statp; unsigned int aoffset;
/* Will be turned off by GSS integrity and privacy services */ /* Will be turned off by GSS integrity and privacy services */
set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
...@@ -1242,9 +1243,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1242,9 +1243,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
clear_bit(RQ_DROPME, &rqstp->rq_flags); clear_bit(RQ_DROPME, &rqstp->rq_flags);
/* Construct the first words of the reply: */ /* Construct the first words of the reply: */
svc_putu32(resv, rqstp->rq_xid); svcxdr_init_encode(rqstp);
svc_putnl(resv, RPC_REPLY); xdr_stream_encode_be32(xdr, rqstp->rq_xid);
reply_statp = resv->iov_base + resv->iov_len; xdr_stream_encode_be32(xdr, rpc_reply);
p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 4); p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 4);
if (unlikely(!p)) if (unlikely(!p))
...@@ -1252,7 +1253,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1252,7 +1253,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
if (*p++ != cpu_to_be32(RPC_VERSION)) if (*p++ != cpu_to_be32(RPC_VERSION))
goto err_bad_rpc; goto err_bad_rpc;
svc_putnl(resv, 0); /* ACCEPT */ xdr_stream_encode_be32(xdr, rpc_msg_accepted);
rqstp->rq_prog = be32_to_cpup(p++); rqstp->rq_prog = be32_to_cpup(p++);
rqstp->rq_vers = be32_to_cpup(p++); rqstp->rq_vers = be32_to_cpup(p++);
...@@ -1262,8 +1263,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1262,8 +1263,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
if (rqstp->rq_prog == progp->pg_prog) if (rqstp->rq_prog == progp->pg_prog)
break; break;
svcxdr_init_encode(rqstp);
/* /*
* Decode auth data, and add verifier to reply buffer. * Decode auth data, and add verifier to reply buffer.
* We do this before anything else in order to get a decent * We do this before anything else in order to get a decent
...@@ -1314,6 +1313,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1314,6 +1313,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
serv->sv_stats->rpccnt++; serv->sv_stats->rpccnt++;
trace_svc_process(rqstp, progp->pg_name); trace_svc_process(rqstp, progp->pg_name);
aoffset = xdr_stream_pos(xdr);
statp = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT); statp = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT);
*statp = rpc_success; *statp = rpc_success;
...@@ -1332,9 +1332,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1332,9 +1332,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
if (rqstp->rq_auth_stat != rpc_auth_ok) if (rqstp->rq_auth_stat != rpc_auth_ok)
goto err_bad_auth; goto err_bad_auth;
/* Check RPC status result */
if (*statp != rpc_success) if (*statp != rpc_success)
resv->iov_len = ((void*)statp) - resv->iov_base + 4; xdr_truncate_encode(xdr, aoffset);
if (procp->pc_encode == NULL) if (procp->pc_encode == NULL)
goto dropit; goto dropit;
...@@ -1364,27 +1363,28 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1364,27 +1363,28 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
err_bad_rpc: err_bad_rpc:
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, 1); /* REJECT */ xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
svc_putnl(resv, 0); /* RPC_MISMATCH */ xdr_stream_encode_u32(xdr, RPC_MISMATCH);
svc_putnl(resv, 2); /* Only RPCv2 supported */ /* Only RPCv2 supported */
svc_putnl(resv, 2); xdr_stream_encode_u32(xdr, RPC_VERSION);
xdr_stream_encode_u32(xdr, RPC_VERSION);
goto sendit; goto sendit;
err_bad_auth: err_bad_auth:
dprintk("svc: authentication failed (%d)\n", dprintk("svc: authentication failed (%d)\n",
be32_to_cpu(rqstp->rq_auth_stat)); be32_to_cpu(rqstp->rq_auth_stat));
serv->sv_stats->rpcbadauth++; serv->sv_stats->rpcbadauth++;
/* Restore write pointer to location of accept status: */ /* Restore write pointer to location of reply status: */
xdr_ressize_check(rqstp, reply_statp); xdr_truncate_encode(xdr, XDR_UNIT * 2);
svc_putnl(resv, 1); /* REJECT */ xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
svc_putnl(resv, 1); /* AUTH_ERROR */ xdr_stream_encode_u32(xdr, RPC_AUTH_ERROR);
svc_putu32(resv, rqstp->rq_auth_stat); /* status */ xdr_stream_encode_be32(xdr, rqstp->rq_auth_stat);
goto sendit; goto sendit;
err_bad_prog: err_bad_prog:
dprintk("svc: unknown program %d\n", rqstp->rq_prog); dprintk("svc: unknown program %d\n", rqstp->rq_prog);
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROG_UNAVAIL); xdr_stream_encode_u32(xdr, RPC_PROG_UNAVAIL);
goto sendit; goto sendit;
err_bad_vers: err_bad_vers:
...@@ -1392,28 +1392,28 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv) ...@@ -1392,28 +1392,28 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *resv)
rqstp->rq_vers, rqstp->rq_prog, progp->pg_name); rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROG_MISMATCH); xdr_stream_encode_u32(xdr, RPC_PROG_MISMATCH);
svc_putnl(resv, process.mismatch.lovers); xdr_stream_encode_u32(xdr, process.mismatch.lovers);
svc_putnl(resv, process.mismatch.hivers); xdr_stream_encode_u32(xdr, process.mismatch.hivers);
goto sendit; goto sendit;
err_bad_proc: err_bad_proc:
svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc); svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROC_UNAVAIL); xdr_stream_encode_u32(xdr, RPC_PROC_UNAVAIL);
goto sendit; goto sendit;
err_garbage_args: err_garbage_args:
svc_printk(rqstp, "failed to decode RPC header\n"); svc_printk(rqstp, "failed to decode RPC header\n");
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_GARBAGE_ARGS); xdr_stream_encode_u32(xdr, RPC_GARBAGE_ARGS);
goto sendit; goto sendit;
err_system_err: err_system_err:
serv->sv_stats->rpcbadfmt++; serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_SYSTEM_ERR); xdr_stream_encode_u32(xdr, RPC_SYSTEM_ERR);
goto sendit; goto sendit;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment