Commit 42140718 authored by Chuck Lever's avatar Chuck Lever

SUNRPC: Convert unwrap_priv_data() to use xdr_stream

Done as part of hardening the server-side RPC header decoding path.
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent f4a59e82
...@@ -188,7 +188,6 @@ xdr_adjust_iovec(struct kvec *iov, __be32 *p) ...@@ -188,7 +188,6 @@ xdr_adjust_iovec(struct kvec *iov, __be32 *p)
/* /*
* XDR buffer helper functions * XDR buffer helper functions
*/ */
extern void xdr_shift_buf(struct xdr_buf *, size_t);
extern void xdr_buf_from_iov(const struct kvec *, struct xdr_buf *); extern void xdr_buf_from_iov(const struct kvec *, struct xdr_buf *);
extern int xdr_buf_subsegment(const struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int); extern int xdr_buf_subsegment(const struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int);
extern void xdr_buf_trim(struct xdr_buf *, unsigned int); extern void xdr_buf_trim(struct xdr_buf *, unsigned int);
......
...@@ -982,17 +982,6 @@ total_buf_len(struct xdr_buf *buf) ...@@ -982,17 +982,6 @@ total_buf_len(struct xdr_buf *buf)
return buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len; return buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len;
} }
static void
fix_priv_head(struct xdr_buf *buf, int pad)
{
if (buf->page_len == 0) {
/* We need to adjust head and buf->len in tandem in this
* case to make svc_defer() work--it finds the original
* buffer start using buf->len - buf->head[0].iov_len. */
buf->head[0].iov_len -= pad;
}
}
/* /*
* RFC 2203, Section 5.3.2.3 * RFC 2203, Section 5.3.2.3
* *
...@@ -1005,49 +994,37 @@ fix_priv_head(struct xdr_buf *buf, int pad) ...@@ -1005,49 +994,37 @@ fix_priv_head(struct xdr_buf *buf, int pad)
* proc_req_arg_t arg; * proc_req_arg_t arg;
* }; * };
*/ */
static int static noinline_for_stack int
svcauth_gss_unwrap_priv(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, svcauth_gss_unwrap_priv(struct svc_rqst *rqstp, u32 seq, struct gss_ctx *ctx)
struct gss_ctx *ctx)
{ {
u32 len, seq_num, maj_stat; struct xdr_stream *xdr = &rqstp->rq_arg_stream;
int pad, remaining_len, offset; u32 len, maj_stat, seq_num, offset;
struct xdr_buf *buf = xdr->buf;
unsigned int saved_len;
clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
len = svc_getnl(&buf->head[0]); if (xdr_stream_decode_u32(xdr, &len) < 0)
goto unwrap_failed;
if (rqstp->rq_deferred) { if (rqstp->rq_deferred) {
/* Already decrypted last time through! The sequence number /* Already decrypted last time through! The sequence number
* check at out_seq is unnecessary but harmless: */ * check at out_seq is unnecessary but harmless: */
goto out_seq; goto out_seq;
} }
/* buf->len is the number of bytes from the original start of the if (len > xdr_stream_remaining(xdr))
* request to the end, where head[0].iov_len is just the bytes
* not yet read from the head, so these two values are different: */
remaining_len = total_buf_len(buf);
if (len > remaining_len)
goto unwrap_failed; goto unwrap_failed;
pad = remaining_len - len; offset = xdr_stream_pos(xdr);
buf->len -= pad;
fix_priv_head(buf, pad); saved_len = buf->len;
maj_stat = gss_unwrap(ctx, offset, offset + len, buf);
maj_stat = gss_unwrap(ctx, 0, len, buf);
pad = len - buf->len;
/* The upper layers assume the buffer is aligned on 4-byte boundaries.
* In the krb5p case, at least, the data ends up offset, so we need to
* move it around. */
/* XXX: This is very inefficient. It would be better to either do
* this while we encrypt, or maybe in the receive code, if we can peak
* ahead and work out the service and mechanism there. */
offset = xdr_pad_size(buf->head[0].iov_len);
if (offset) {
buf->buflen = RPCSVC_MAXPAYLOAD;
xdr_shift_buf(buf, offset);
fix_priv_head(buf, pad);
}
if (maj_stat != GSS_S_COMPLETE) if (maj_stat != GSS_S_COMPLETE)
goto bad_unwrap; goto bad_unwrap;
xdr->nwords -= XDR_QUADLEN(saved_len - buf->len);
out_seq: out_seq:
seq_num = svc_getnl(&buf->head[0]); /* gss_unwrap() decrypted the sequence number. */
if (xdr_stream_decode_u32(xdr, &seq_num) < 0)
goto unwrap_failed;
if (seq_num != seq) if (seq_num != seq)
goto bad_seqno; goto bad_seqno;
return 0; return 0;
...@@ -1689,11 +1666,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp) ...@@ -1689,11 +1666,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp)
/* placeholders for length and seq. number: */ /* placeholders for length and seq. number: */
svc_putnl(resv, 0); svc_putnl(resv, 0);
svc_putnl(resv, 0); svc_putnl(resv, 0);
if (svcauth_gss_unwrap_priv(rqstp, &rqstp->rq_arg, svcxdr_init_decode(rqstp);
gc->gc_seq, rsci->mechctx)) if (svcauth_gss_unwrap_priv(rqstp, gc->gc_seq,
rsci->mechctx))
goto garbage_args; goto garbage_args;
rqstp->rq_auth_slack = RPC_MAX_AUTH_SIZE * 2; rqstp->rq_auth_slack = RPC_MAX_AUTH_SIZE * 2;
svcxdr_init_decode(rqstp);
break; break;
default: default:
goto auth_err; goto auth_err;
......
...@@ -863,13 +863,6 @@ static unsigned int xdr_shrink_pagelen(struct xdr_buf *buf, unsigned int len) ...@@ -863,13 +863,6 @@ static unsigned int xdr_shrink_pagelen(struct xdr_buf *buf, unsigned int len)
return shift; return shift;
} }
void
xdr_shift_buf(struct xdr_buf *buf, size_t len)
{
xdr_shrink_bufhead(buf, buf->head->iov_len - len);
}
EXPORT_SYMBOL_GPL(xdr_shift_buf);
/** /**
* xdr_stream_pos - Return the current offset from the start of the xdr_stream * xdr_stream_pos - Return the current offset from the start of the xdr_stream
* @xdr: pointer to struct xdr_stream * @xdr: pointer to struct xdr_stream
......
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