SUNRPC: Fix crasher in unwrap_integ_data()
If a zero length is passed to kmalloc() it returns 0x10, which is not a valid address. gss_verify_mic() subsequently crashes when it attempts to dereference that pointer. Instead of allocating this memory on every call based on an untrusted size value, use a piece of dynamically-allocated scratch memory that is always available. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Reviewed-by: Jeff Layton <jlayton@kernel.org>
This commit is contained in:
parent
c65d9df0c4
commit
4dd9daa912
@ -49,11 +49,36 @@
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/sunrpc/svcauth_gss.h>
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
|
||||
#include <trace/events/rpcgss.h>
|
||||
|
||||
#include "gss_rpc_upcall.h"
|
||||
|
||||
/*
|
||||
* Unfortunately there isn't a maximum checksum size exported via the
|
||||
* GSS API. Manufacture one based on GSS mechanisms supported by this
|
||||
* implementation.
|
||||
*/
|
||||
#define GSS_MAX_CKSUMSIZE (GSS_KRB5_TOK_HDR_LEN + GSS_KRB5_MAX_CKSUM_LEN)
|
||||
|
||||
/*
|
||||
* This value may be increased in the future to accommodate other
|
||||
* usage of the scratch buffer.
|
||||
*/
|
||||
#define GSS_SCRATCH_SIZE GSS_MAX_CKSUMSIZE
|
||||
|
||||
struct gss_svc_data {
|
||||
/* decoded gss client cred: */
|
||||
struct rpc_gss_wire_cred clcred;
|
||||
/* save a pointer to the beginning of the encoded verifier,
|
||||
* for use in encryption/checksumming in svcauth_gss_release: */
|
||||
__be32 *verf_start;
|
||||
struct rsc *rsci;
|
||||
|
||||
/* for temporary results */
|
||||
u8 gsd_scratch[GSS_SCRATCH_SIZE];
|
||||
};
|
||||
|
||||
/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
|
||||
* into replies.
|
||||
@ -887,13 +912,11 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
|
||||
static int
|
||||
unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
|
||||
{
|
||||
struct gss_svc_data *gsd = rqstp->rq_auth_data;
|
||||
u32 integ_len, rseqno, maj_stat;
|
||||
int stat = -EINVAL;
|
||||
struct xdr_netobj mic;
|
||||
struct xdr_buf integ_buf;
|
||||
|
||||
mic.data = NULL;
|
||||
|
||||
/* NFS READ normally uses splice to send data in-place. However
|
||||
* the data in cache can change after the reply's MIC is computed
|
||||
* but before the RPC reply is sent. To prevent the client from
|
||||
@ -917,11 +940,9 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
|
||||
/* copy out mic... */
|
||||
if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
|
||||
goto unwrap_failed;
|
||||
if (mic.len > RPC_MAX_AUTH_SIZE)
|
||||
goto unwrap_failed;
|
||||
mic.data = kmalloc(mic.len, GFP_KERNEL);
|
||||
if (!mic.data)
|
||||
if (mic.len > sizeof(gsd->gsd_scratch))
|
||||
goto unwrap_failed;
|
||||
mic.data = gsd->gsd_scratch;
|
||||
if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
|
||||
goto unwrap_failed;
|
||||
maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
|
||||
@ -932,20 +953,17 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
|
||||
goto bad_seqno;
|
||||
/* trim off the mic and padding at the end before returning */
|
||||
xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4);
|
||||
stat = 0;
|
||||
out:
|
||||
kfree(mic.data);
|
||||
return stat;
|
||||
return 0;
|
||||
|
||||
unwrap_failed:
|
||||
trace_rpcgss_svc_unwrap_failed(rqstp);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
bad_seqno:
|
||||
trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
bad_mic:
|
||||
trace_rpcgss_svc_mic(rqstp, maj_stat);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -1023,15 +1041,6 @@ bad_unwrap:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct gss_svc_data {
|
||||
/* decoded gss client cred: */
|
||||
struct rpc_gss_wire_cred clcred;
|
||||
/* save a pointer to the beginning of the encoded verifier,
|
||||
* for use in encryption/checksumming in svcauth_gss_release: */
|
||||
__be32 *verf_start;
|
||||
struct rsc *rsci;
|
||||
};
|
||||
|
||||
static int
|
||||
svcauth_gss_set_client(struct svc_rqst *rqstp)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user