SUNRPC: The transmitted message must lie in the RPCSEC window of validity
If a message has been encoded using RPCSEC_GSS, the server is maintaining a window of sequence numbers that it considers valid. The client should normally be tracking that window, and needs to verify that the sequence number used by the message being transmitted still lies inside the window of validity. So far, we've been able to assume this condition would be realised automatically, since the client has been encoding the message only after taking the socket lock. Once we change that condition, we will need the explicit check. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
9ee94d3ed6
commit
3021a5bbbf
@ -157,6 +157,7 @@ struct rpc_credops {
|
||||
int (*crkey_timeout)(struct rpc_cred *);
|
||||
bool (*crkey_to_expire)(struct rpc_cred *);
|
||||
char * (*crstringify_acceptor)(struct rpc_cred *);
|
||||
bool (*crneed_reencode)(struct rpc_task *);
|
||||
};
|
||||
|
||||
extern const struct rpc_authops authunix_ops;
|
||||
@ -192,6 +193,7 @@ __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *);
|
||||
__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *);
|
||||
int rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj);
|
||||
int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj);
|
||||
bool rpcauth_xmit_need_reencode(struct rpc_task *task);
|
||||
int rpcauth_refreshcred(struct rpc_task *);
|
||||
void rpcauth_invalcred(struct rpc_task *);
|
||||
int rpcauth_uptodatecred(struct rpc_task *);
|
||||
|
@ -70,6 +70,7 @@ struct gss_cl_ctx {
|
||||
refcount_t count;
|
||||
enum rpc_gss_proc gc_proc;
|
||||
u32 gc_seq;
|
||||
u32 gc_seq_xmit;
|
||||
spinlock_t gc_seq_lock;
|
||||
struct gss_ctx *gc_gss_ctx;
|
||||
struct xdr_netobj gc_wire_ctx;
|
||||
|
@ -817,6 +817,16 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp,
|
||||
return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
|
||||
}
|
||||
|
||||
bool
|
||||
rpcauth_xmit_need_reencode(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_rqstp->rq_cred;
|
||||
|
||||
if (!cred || !cred->cr_ops->crneed_reencode)
|
||||
return false;
|
||||
return cred->cr_ops->crneed_reencode(task);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_refreshcred(struct rpc_task *task)
|
||||
{
|
||||
|
@ -1984,6 +1984,46 @@ gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
|
||||
return decode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
gss_seq_is_newer(u32 new, u32 old)
|
||||
{
|
||||
return (s32)(new - old) > 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
gss_xmit_need_reencode(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_cred *cred = req->rq_cred;
|
||||
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
|
||||
u32 win, seq_xmit;
|
||||
bool ret = true;
|
||||
|
||||
if (!ctx)
|
||||
return true;
|
||||
|
||||
if (gss_seq_is_newer(req->rq_seqno, READ_ONCE(ctx->gc_seq)))
|
||||
goto out;
|
||||
|
||||
seq_xmit = READ_ONCE(ctx->gc_seq_xmit);
|
||||
while (gss_seq_is_newer(req->rq_seqno, seq_xmit)) {
|
||||
u32 tmp = seq_xmit;
|
||||
|
||||
seq_xmit = cmpxchg(&ctx->gc_seq_xmit, tmp, req->rq_seqno);
|
||||
if (seq_xmit == tmp) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
win = ctx->gc_win;
|
||||
if (win > 0)
|
||||
ret = !gss_seq_is_newer(req->rq_seqno, seq_xmit - win);
|
||||
out:
|
||||
gss_put_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_unwrap_resp(struct rpc_task *task,
|
||||
kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
|
||||
@ -2052,6 +2092,7 @@ static const struct rpc_credops gss_credops = {
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.crkey_timeout = gss_key_timeout,
|
||||
.crstringify_acceptor = gss_stringify_acceptor,
|
||||
.crneed_reencode = gss_xmit_need_reencode,
|
||||
};
|
||||
|
||||
static const struct rpc_credops gss_nullops = {
|
||||
|
@ -2184,6 +2184,9 @@ call_status(struct rpc_task *task)
|
||||
/* shutdown or soft timeout */
|
||||
rpc_exit(task, status);
|
||||
break;
|
||||
case -EBADMSG:
|
||||
task->tk_action = call_transmit;
|
||||
break;
|
||||
default:
|
||||
if (clnt->cl_chatty)
|
||||
printk("%s: RPC call returned error %d\n",
|
||||
|
@ -1014,6 +1014,13 @@ void xprt_transmit(struct rpc_task *task)
|
||||
dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
|
||||
|
||||
if (!req->rq_reply_bytes_recvd) {
|
||||
|
||||
/* Verify that our message lies in the RPCSEC_GSS window */
|
||||
if (!req->rq_bytes_sent && rpcauth_xmit_need_reencode(task)) {
|
||||
task->tk_status = -EBADMSG;
|
||||
return;
|
||||
}
|
||||
|
||||
if (list_empty(&req->rq_list) && rpc_reply_expected(task)) {
|
||||
/*
|
||||
* Add to the list only if we're expecting a reply
|
||||
|
Loading…
Reference in New Issue
Block a user