rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer

This improves the fix for CVE-2026-43500.

Fix the verification of RESPONSE packets to avoid the problem of
overwriting a RESPONSE packet sent via splice to a local address by
extracting the contents of the UDP packet into a kmalloc'd linear buffer
rather than decrypting the data in place in the sk_buff (which may corrupt
the original buffer).

Fixes: 24481a7f57 ("rxrpc: Fix conn-level packet handling to unshare RESPONSE packets")
Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Closes: https://lore.kernel.org/r/afKV2zGR6rrelPC7@v4bel/
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: Jiayuan Chen <jiayuan.chen@linux.dev>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
Tested-by: Marc Dionne <marc.dionne@auristor.com>
Link: https://patch.msgid.link/20260515230516.2718212-4-dhowells@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
master
David Howells 2026-05-16 00:05:15 +01:00 committed by Jakub Kicinski
parent d2bc90cf6c
commit 8bfab4b6ff
7 changed files with 82 additions and 225 deletions

View File

@ -307,15 +307,16 @@ struct rxrpc_security {
struct sk_buff *challenge); struct sk_buff *challenge);
/* verify a response */ /* verify a response */
int (*verify_response)(struct rxrpc_connection *, int (*verify_response)(struct rxrpc_connection *conn,
struct sk_buff *); struct sk_buff *response_skb,
void *response, unsigned int len);
/* clear connection security */ /* clear connection security */
void (*clear)(struct rxrpc_connection *); void (*clear)(struct rxrpc_connection *);
/* Default ticket -> key decoder */ /* Default ticket -> key decoder */
int (*default_decode_ticket)(struct rxrpc_connection *conn, struct sk_buff *skb, int (*default_decode_ticket)(struct rxrpc_connection *conn, struct sk_buff *skb,
unsigned int ticket_offset, unsigned int ticket_len, void *ticket, unsigned int ticket_len,
struct key **_key); struct key **_key);
}; };

View File

@ -243,28 +243,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
static int rxrpc_verify_response(struct rxrpc_connection *conn, static int rxrpc_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb) struct sk_buff *skb)
{ {
unsigned int len = skb->len - sizeof(struct rxrpc_wire_header);
void *buffer;
int ret; int ret;
if (skb_cloned(skb) || skb_has_frag_list(skb) || buffer = kmalloc(len, GFP_NOFS);
skb_has_shared_frag(skb)) { if (!buffer)
/* Copy the packet if shared so that we can do in-place return -ENOMEM;
* decryption.
*/
struct sk_buff *nskb = skb_copy(skb, GFP_NOFS);
if (nskb) { ret = skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), buffer, len);
rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); if (ret < 0)
ret = conn->security->verify_response(conn, nskb); goto out;
rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy);
} else {
/* OOM - Drop the packet. */
rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
ret = -ENOMEM;
}
} else {
ret = conn->security->verify_response(conn, skb);
}
ret = conn->security->verify_response(conn, skb, buffer, len);
out:
kfree(buffer);
return ret; return ret;
} }

View File

@ -54,9 +54,10 @@ static int none_sendmsg_respond_to_challenge(struct sk_buff *challenge,
} }
static int none_verify_response(struct rxrpc_connection *conn, static int none_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb) struct sk_buff *response_skb,
void *response, unsigned int len)
{ {
return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO, return rxrpc_abort_conn(conn, response_skb, RX_PROTOCOL_ERROR, -EPROTO,
rxrpc_eproto_rxnull_response); rxrpc_eproto_rxnull_response);
} }

View File

@ -1084,11 +1084,12 @@ static int rxgk_sendmsg_respond_to_challenge(struct sk_buff *challenge,
* unsigned int call_numbers<>; * unsigned int call_numbers<>;
* }; * };
*/ */
static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn, static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
const struct krb5_enctype *krb5, const struct krb5_enctype *krb5,
struct sk_buff *skb, struct sk_buff *skb,
__be32 *p, __be32 *end) void *auth, unsigned int auth_len)
{ {
__be32 *p = auth, *end = auth + auth_len;
u32 app_len, call_count, level, epoch, cid, i; u32 app_len, call_count, level, epoch, cid, i;
_enter(""); _enter("");
@ -1151,37 +1152,6 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
return 0; return 0;
} }
/*
* Extract the authenticator and verify it.
*/
static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
const struct krb5_enctype *krb5,
struct sk_buff *skb,
unsigned int auth_offset, unsigned int auth_len)
{
void *auth;
__be32 *p;
int ret;
auth = kmalloc(auth_len, GFP_NOFS);
if (!auth)
return -ENOMEM;
ret = skb_copy_bits(skb, auth_offset, auth, auth_len);
if (ret < 0) {
ret = rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_short_auth);
goto error;
}
p = auth;
ret = rxgk_do_verify_authenticator(conn, krb5, skb, p,
p + auth_len / sizeof(*p));
error:
kfree(auth);
return ret;
}
/* /*
* Verify a response. * Verify a response.
* *
@ -1192,49 +1162,45 @@ error:
* }; * };
*/ */
static int rxgk_verify_response(struct rxrpc_connection *conn, static int rxgk_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb) struct sk_buff *skb,
void *buffer, unsigned int len)
{ {
const struct krb5_enctype *krb5; const struct krb5_enctype *krb5;
struct rxrpc_key_token *token; struct rxrpc_key_token *token;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxgk_response rhdr; struct rxgk_response *rhdr;
struct rxgk_context *gk; struct rxgk_context *gk;
struct key *key = NULL; struct key *key = NULL;
unsigned int offset = sizeof(struct rxrpc_wire_header); unsigned int resp_token_len, auth_len;
unsigned int len = skb->len - sizeof(struct rxrpc_wire_header); void *resp_token, *auth;
unsigned int token_offset, token_len;
unsigned int auth_offset, auth_len;
__be32 xauth_len; __be32 xauth_len;
int ret, ec; int ret, ec;
_enter("{%d}", conn->debug_id); _enter("{%d}", conn->debug_id);
/* Parse the RXGK_Response object */ /* Parse the RXGK_Response object */
if (sizeof(rhdr) + sizeof(__be32) > len) if (len < sizeof(*rhdr) + sizeof(__be32))
goto short_packet;
rhdr = buffer;
buffer += sizeof(*rhdr);
len -= sizeof(*rhdr);
resp_token = buffer;
resp_token_len = ntohl(rhdr->token_len);
if (resp_token_len > len ||
xdr_round_up(resp_token_len) + sizeof(__be32) > len)
goto short_packet; goto short_packet;
if (skb_copy_bits(skb, offset, &rhdr, sizeof(rhdr)) < 0) trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, resp_token_len);
goto short_packet;
offset += sizeof(rhdr);
len -= sizeof(rhdr);
token_offset = offset; buffer += xdr_round_up(resp_token_len);
token_len = ntohl(rhdr.token_len); len -= xdr_round_up(resp_token_len);
if (token_len > len ||
xdr_round_up(token_len) + sizeof(__be32) > len)
goto short_packet;
trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_len); xauth_len = *(__be32 *)buffer;
buffer += sizeof(xauth_len);
offset += xdr_round_up(token_len);
len -= xdr_round_up(token_len);
if (skb_copy_bits(skb, offset, &xauth_len, sizeof(xauth_len)) < 0)
goto short_packet;
offset += sizeof(xauth_len);
len -= sizeof(xauth_len); len -= sizeof(xauth_len);
auth_offset = offset; auth = buffer;
auth_len = ntohl(xauth_len); auth_len = ntohl(xauth_len);
if (auth_len > len) if (auth_len > len)
goto short_packet; goto short_packet;
@ -1249,7 +1215,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
* to the app to deal with - which might mean a round trip to * to the app to deal with - which might mean a round trip to
* userspace. * userspace.
*/ */
ret = rxgk_extract_token(conn, skb, token_offset, token_len, &key); ret = rxgk_extract_token(conn, skb, resp_token, resp_token_len, &key);
if (ret < 0) if (ret < 0)
goto out; goto out;
@ -1263,7 +1229,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
*/ */
token = key->payload.data[0]; token = key->payload.data[0];
conn->security_level = token->rxgk->level; conn->security_level = token->rxgk->level;
conn->rxgk.start_time = __be64_to_cpu(rhdr.start_time); conn->rxgk.start_time = __be64_to_cpu(rhdr->start_time);
gk = rxgk_generate_transport_key(conn, token->rxgk, sp->hdr.cksum, GFP_NOFS); gk = rxgk_generate_transport_key(conn, token->rxgk, sp->hdr.cksum, GFP_NOFS);
if (IS_ERR(gk)) { if (IS_ERR(gk)) {
@ -1273,18 +1239,18 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
krb5 = gk->krb5; krb5 = gk->krb5;
trace_rxrpc_rx_response(conn, sp->hdr.serial, krb5->etype, sp->hdr.cksum, token_len); trace_rxrpc_rx_response(conn, sp->hdr.serial, krb5->etype, sp->hdr.cksum,
resp_token_len);
/* Decrypt, parse and verify the authenticator. */ /* Decrypt, parse and verify the authenticator. */
ret = rxgk_decrypt_skb(krb5, gk->resp_enc, skb, ret = rxgk_decrypt(krb5, gk->resp_enc, &auth, &auth_len, &ec);
&auth_offset, &auth_len, &ec);
if (ret < 0) { if (ret < 0) {
rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret, rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret,
rxgk_abort_resp_auth_dec); rxgk_abort_resp_auth_dec);
goto out_gk; goto out_gk;
} }
ret = rxgk_verify_authenticator(conn, krb5, skb, auth_offset, auth_len); ret = rxgk_verify_authenticator(conn, krb5, skb, auth, auth_len);
if (ret < 0) if (ret < 0)
goto out_gk; goto out_gk;

View File

@ -40,7 +40,7 @@
* }; * };
*/ */
int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb, int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
unsigned int ticket_offset, unsigned int ticket_len, void *buffer, unsigned int ticket_len,
struct key **_key) struct key **_key)
{ {
struct rxrpc_key_token *token; struct rxrpc_key_token *token;
@ -49,7 +49,7 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
size_t pre_ticket_len, payload_len; size_t pre_ticket_len, payload_len;
unsigned int klen, enctype; unsigned int klen, enctype;
void *payload, *ticket; void *payload, *ticket;
__be32 *t, *p, *q, tmp[2]; __be32 *t, *p, *q, *tmp;
int ret; int ret;
_enter(""); _enter("");
@ -59,10 +59,7 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
rxgk_abort_resp_short_yfs_tkt); rxgk_abort_resp_short_yfs_tkt);
/* Get the session key length */ /* Get the session key length */
ret = skb_copy_bits(skb, ticket_offset, tmp, sizeof(tmp)); tmp = buffer;
if (ret < 0)
return rxrpc_abort_conn(conn, skb, RXGK_INCONSISTENCY, -EPROTO,
rxgk_abort_resp_short_yfs_klen);
enctype = ntohl(tmp[0]); enctype = ntohl(tmp[0]);
klen = ntohl(tmp[1]); klen = ntohl(tmp[1]);
@ -84,12 +81,7 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
* it. * it.
*/ */
ticket = payload + pre_ticket_len; ticket = payload + pre_ticket_len;
ret = skb_copy_bits(skb, ticket_offset, ticket, ticket_len); memcpy(ticket, buffer, ticket_len);
if (ret < 0) {
ret = rxrpc_abort_conn(conn, skb, RXGK_INCONSISTENCY, -EPROTO,
rxgk_abort_resp_short_yfs_tkt);
goto error;
}
/* Fill out the form header. */ /* Fill out the form header. */
p = payload; p = payload;
@ -131,7 +123,7 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
goto error; goto error;
} }
/* Ticket read in with skb_copy_bits above */ /* Ticket appended above. */
q += xdr_round_up(ticket_len) / 4; q += xdr_round_up(ticket_len) / 4;
if (WARN_ON((unsigned long)q - (unsigned long)payload != payload_len)) { if (WARN_ON((unsigned long)q - (unsigned long)payload != payload_len)) {
ret = -EIO; ret = -EIO;
@ -182,14 +174,15 @@ error:
* [tools.ietf.org/html/draft-wilkinson-afs3-rxgk-afs-08 sec 6.1] * [tools.ietf.org/html/draft-wilkinson-afs3-rxgk-afs-08 sec 6.1]
*/ */
int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
unsigned int token_offset, unsigned int token_len, void *token, unsigned int token_len,
struct key **_key) struct key **_key)
{ {
const struct krb5_enctype *krb5; const struct krb5_enctype *krb5;
const struct krb5_buffer *server_secret; const struct krb5_buffer *server_secret;
struct crypto_aead *token_enc = NULL; struct crypto_aead *token_enc = NULL;
struct key *server_key; struct key *server_key;
unsigned int ticket_offset, ticket_len; unsigned int ticket_len;
void *ticket;
u32 kvno, enctype; u32 kvno, enctype;
int ret, ec = 0; int ret, ec = 0;
@ -197,24 +190,23 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
__be32 kvno; __be32 kvno;
__be32 enctype; __be32 enctype;
__be32 token_len; __be32 token_len;
} container; } *container;
if (token_len < sizeof(container)) if (token_len < sizeof(*container))
goto short_packet; goto short_packet;
/* Decode the RXGK_TokenContainer object. This tells us which server /* Decode the RXGK_TokenContainer object. This tells us which server
* key we should be using. We can then fetch the key, get the secret * key we should be using. We can then fetch the key, get the secret
* and set up the crypto to extract the token. * and set up the crypto to extract the token.
*/ */
if (skb_copy_bits(skb, token_offset, &container, sizeof(container)) < 0) container = token;
goto short_packet; token += sizeof(*container);
kvno = ntohl(container.kvno); kvno = ntohl(container->kvno);
enctype = ntohl(container.enctype); enctype = ntohl(container->enctype);
ticket_len = ntohl(container.token_len); ticket_len = ntohl(container->token_len);
ticket_offset = token_offset + sizeof(container);
if (ticket_len > xdr_round_down(token_len - sizeof(container))) if (ticket_len > xdr_round_down(token_len - sizeof(*container)))
goto short_packet; goto short_packet;
_debug("KVNO %u", kvno); _debug("KVNO %u", kvno);
@ -237,8 +229,8 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
* gain access to K0, from which we can derive the transport key and * gain access to K0, from which we can derive the transport key and
* thence decode the authenticator. * thence decode the authenticator.
*/ */
ret = rxgk_decrypt_skb(krb5, token_enc, skb, ticket = token;
&ticket_offset, &ticket_len, &ec); ret = rxgk_decrypt(krb5, token_enc, &ticket, &ticket_len, &ec);
crypto_free_aead(token_enc); crypto_free_aead(token_enc);
token_enc = NULL; token_enc = NULL;
if (ret < 0) { if (ret < 0) {
@ -248,7 +240,7 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
return ret; return ret;
} }
ret = conn->security->default_decode_ticket(conn, skb, ticket_offset, ret = conn->security->default_decode_ticket(conn, skb, ticket,
ticket_len, _key); ticket_len, _key);
if (ret < 0) if (ret < 0)
goto cant_get_token; goto cant_get_token;

View File

@ -41,10 +41,10 @@ struct rxgk_context {
* rxgk_app.c * rxgk_app.c
*/ */
int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb, int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
unsigned int ticket_offset, unsigned int ticket_len, void *ticket, unsigned int ticket_len,
struct key **_key); struct key **_key);
int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
unsigned int token_offset, unsigned int token_len, void *token, unsigned int token_len,
struct key **_key); struct key **_key);
/* /*
@ -61,50 +61,6 @@ int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
const struct krb5_enctype **_krb5, const struct krb5_enctype **_krb5,
gfp_t gfp); gfp_t gfp);
/*
* Apply decryption and checksumming functions to part of an skbuff. The
* offset and length are updated to reflect the actual content of the encrypted
* region.
*/
static inline
int rxgk_decrypt_skb(const struct krb5_enctype *krb5,
struct crypto_aead *aead,
struct sk_buff *skb,
unsigned int *_offset, unsigned int *_len,
int *_error_code)
{
struct scatterlist sg[16];
size_t offset = 0, len = *_len;
int nr_sg, ret;
sg_init_table(sg, ARRAY_SIZE(sg));
nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
if (unlikely(nr_sg < 0))
return nr_sg;
ret = crypto_krb5_decrypt(krb5, aead, sg, nr_sg,
&offset, &len);
switch (ret) {
case 0:
*_offset += offset;
*_len = len;
break;
case -EBADMSG: /* Checksum mismatch. */
case -EPROTO:
*_error_code = RXGK_SEALEDINCON;
break;
case -EMSGSIZE:
*_error_code = RXGK_PACKETSHORT;
break;
case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
default:
*_error_code = RXGK_INCONSISTENCY;
break;
}
return ret;
}
/* /*
* Apply decryption and checksumming functions a flat data buffer. The data * Apply decryption and checksumming functions a flat data buffer. The data
* point and length are updated to reflect the actual content of the encrypted * point and length are updated to reflect the actual content of the encrypted
@ -148,50 +104,6 @@ static inline int rxgk_decrypt(const struct krb5_enctype *krb5,
return ret; return ret;
} }
/*
* Check the MIC on a region of an skbuff. The offset and length are updated
* to reflect the actual content of the secure region.
*/
static inline
int rxgk_verify_mic_skb(const struct krb5_enctype *krb5,
struct crypto_shash *shash,
const struct krb5_buffer *metadata,
struct sk_buff *skb,
unsigned int *_offset, unsigned int *_len,
u32 *_error_code)
{
struct scatterlist sg[16];
size_t offset = 0, len = *_len;
int nr_sg, ret;
sg_init_table(sg, ARRAY_SIZE(sg));
nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
if (unlikely(nr_sg < 0))
return nr_sg;
ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, nr_sg,
&offset, &len);
switch (ret) {
case 0:
*_offset += offset;
*_len = len;
break;
case -EBADMSG: /* Checksum mismatch */
case -EPROTO:
*_error_code = RXGK_SEALEDINCON;
break;
case -EMSGSIZE:
*_error_code = RXGK_PACKETSHORT;
break;
case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
default:
*_error_code = RXGK_INCONSISTENCY;
break;
}
return ret;
}
/* /*
* Check the MIC on a flat buffer. The data pointer and length are updated to * Check the MIC on a flat buffer. The data pointer and length are updated to
* reflect the actual content of the secure region. * reflect the actual content of the secure region.

View File

@ -963,7 +963,6 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
*_expiry = 0; *_expiry = 0;
ASSERT(server_key->payload.data[0] != NULL); ASSERT(server_key->payload.data[0] != NULL);
ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
memcpy(&iv, &server_key->payload.data[2], sizeof(iv)); memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
@ -1112,14 +1111,15 @@ unlock:
* verify a response * verify a response
*/ */
static int rxkad_verify_response(struct rxrpc_connection *conn, static int rxkad_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb) struct sk_buff *skb,
void *buffer, unsigned int len)
{ {
struct rxkad_response *response; struct rxkad_response *response;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_crypt session_key; struct rxrpc_crypt session_key;
struct key *server_key; struct key *server_key;
time64_t expiry; time64_t expiry;
void *ticket = NULL; void *ticket;
u32 version, kvno, ticket_len, level; u32 version, kvno, ticket_len, level;
__be32 csum; __be32 csum;
int ret, i; int ret, i;
@ -1142,13 +1142,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
} }
} }
ret = -ENOMEM; response = buffer;
response = kzalloc_obj(struct rxkad_response, GFP_NOFS); if (len < sizeof(*response)) {
if (!response)
goto error;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
response, sizeof(*response)) < 0) {
ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO, ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short); rxkad_abort_resp_short);
goto error; goto error;
@ -1160,6 +1155,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
trace_rxrpc_rx_response(conn, sp->hdr.serial, version, kvno, ticket_len); trace_rxrpc_rx_response(conn, sp->hdr.serial, version, kvno, ticket_len);
buffer += sizeof(*response);
len -= sizeof(*response);
if (version != RXKAD_VERSION) { if (version != RXKAD_VERSION) {
ret = rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO, ret = rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
rxkad_abort_resp_version); rxkad_abort_resp_version);
@ -1179,13 +1177,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
} }
/* extract the kerberos ticket and decrypt and decode it */ /* extract the kerberos ticket and decrypt and decode it */
ret = -ENOMEM; ticket = buffer;
ticket = kmalloc(ticket_len, GFP_NOFS); if (ticket_len > len) {
if (!ticket)
goto error;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response),
ticket, ticket_len) < 0) {
ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO, ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short_tkt); rxkad_abort_resp_short_tkt);
goto error; goto error;
@ -1265,8 +1258,6 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno); ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
error: error:
kfree(ticket);
kfree(response);
key_put(server_key); key_put(server_key);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;