Import of kernel-6.12.0-211.40.1.el10_2

This commit is contained in:
almalinux-bot-kernel 2026-08-03 05:18:50 +00:00
parent 4c4ddb2cb6
commit a435f44323
25 changed files with 500 additions and 399 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 2
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 211.39.1
RHEL_RELEASE = 211.40.1
#
# RHEL_REBASE_NUM

View File

@ -134,27 +134,69 @@ EXPORT_SYMBOL(crypto_krb5_how_much_data);
* Find the offset and size of the data in a secure message so that this
* information can be used in the metadata buffer which will get added to the
* digest by crypto_krb5_verify_mic().
*
* Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
* the mode is unsupported.
*/
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t *_offset, size_t *_len)
int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t *_offset, size_t *_len)
{
switch (mode) {
case KRB5_CHECKSUM_MODE:
if (*_len < krb5->cksum_len)
return -EBADMSG;
*_offset += krb5->cksum_len;
*_len -= krb5->cksum_len;
return;
return 0;
case KRB5_ENCRYPT_MODE:
if (*_len < krb5->conf_len + krb5->cksum_len)
return -EBADMSG;
*_offset += krb5->conf_len;
*_len -= krb5->conf_len + krb5->cksum_len;
return;
return 0;
default:
WARN_ON_ONCE(1);
return;
return -EINVAL;
}
}
EXPORT_SYMBOL(crypto_krb5_where_is_the_data);
/**
* crypto_krb5_check_data_len - Check a message is big enough
* @krb5: The encoding to use.
* @mode: Mode of operation.
* @len: The length of the secure blob.
* @min_content: Minimum length of the content inside the blob.
*
* Check that a message is large enough to hold whatever bits the encryption
* type wants to glue on (nonce, checksum) plus a minimum amount of content.
*
* Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
* the mode is unsupported.
*/
int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t len, size_t min_content)
{
switch (mode) {
case KRB5_CHECKSUM_MODE:
if (len < krb5->cksum_len ||
len - krb5->cksum_len < min_content)
return -EBADMSG;
return 0;
case KRB5_ENCRYPT_MODE:
if (len < krb5->conf_len + krb5->cksum_len ||
len - (krb5->conf_len + krb5->cksum_len) < min_content)
return -EBADMSG;
return 0;
default:
WARN_ON_ONCE(1);
return -EINVAL;
}
}
EXPORT_SYMBOL(crypto_krb5_check_data_len);
/*
* Prepare the encryption with derived key data.
*/

View File

@ -4066,8 +4066,8 @@ void domain_remove_dev_pasid(struct iommu_domain *domain,
if (!domain)
return;
/* Identity domain has no meta data for pasid. */
if (domain->type == IOMMU_DOMAIN_IDENTITY)
/* Identity domain and blocked domain have no meta data for pasid. */
if (domain->type == IOMMU_DOMAIN_IDENTITY || domain->type == IOMMU_DOMAIN_BLOCKED)
return;
dmar_domain = to_dmar_domain(domain);
@ -4081,12 +4081,13 @@ void domain_remove_dev_pasid(struct iommu_domain *domain,
}
spin_unlock_irqrestore(&dmar_domain->lock, flags);
if (WARN_ON_ONCE(!dev_pasid))
return;
cache_tag_unassign_domain(dmar_domain, dev, pasid);
domain_detach_iommu(dmar_domain, iommu);
if (!WARN_ON_ONCE(!dev_pasid)) {
intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
kfree(dev_pasid);
}
intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
kfree(dev_pasid);
}
static int blocking_domain_set_dev_pasid(struct iommu_domain *domain,

View File

@ -121,9 +121,12 @@ size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t *_buffer_size, size_t *_offset);
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t *_offset, size_t *_len);
int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t *_offset, size_t *_len);
int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
enum krb5_crypto_mode mode,
size_t len, size_t min_content);
struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
const struct krb5_buffer *TK,
u32 usage, gfp_t gfp);

View File

@ -37,6 +37,7 @@
EM(rxkad_abort_1_short_encdata, "rxkad1-short-encdata") \
EM(rxkad_abort_1_short_header, "rxkad1-short-hdr") \
EM(rxkad_abort_2_short_check, "rxkad2-short-check") \
EM(rxkad_abort_2_crypto_unaligned, "rxkad2-crypto-unaligned") \
EM(rxkad_abort_2_short_data, "rxkad2-short-data") \
EM(rxkad_abort_2_short_header, "rxkad2-short-hdr") \
EM(rxkad_abort_2_short_len, "rxkad2-short-len") \
@ -70,6 +71,7 @@
EM(rxkad_abort_resp_unknown_tkt, "rxkad-resp-unknown-tkt") \
EM(rxkad_abort_resp_version, "rxkad-resp-version") \
/* RxGK security errors */ \
EM(rxgk_abort_1_short_header, "rxgk1-short-hdr") \
EM(rxgk_abort_1_verify_mic_eproto, "rxgk1-vfy-mic-eproto") \
EM(rxgk_abort_2_decrypt_eproto, "rxgk2-dec-eproto") \
EM(rxgk_abort_2_short_data, "rxgk2-short-data") \

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.40.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -202,11 +202,12 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if ((p && (p->flags & BR_PROXYARP)) ||
(f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) ||
br_is_neigh_suppress_enabled(f->dst, vid)) {
(dst && (dst->flags & BR_PROXYARP_WIFI)) ||
br_is_neigh_suppress_enabled(dst, vid)) {
if (!vid)
br_arp_send(br, p, skb->dev, sip, tip,
sha, n->ha, sha, 0, 0);
@ -466,9 +467,10 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if (br_is_neigh_suppress_enabled(f->dst, vid)) {
if (br_is_neigh_suppress_enabled(dst, vid)) {
if (vid != 0)
br_nd_send(br, p, skb, n,
skb->vlan_proto,

View File

@ -236,6 +236,7 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
const unsigned char *addr,
__u16 vid)
{
const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct net_device *dev = NULL;
struct net_bridge *br;
@ -248,8 +249,11 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
br = netdev_priv(br_dev);
rcu_read_lock();
f = br_fdb_find_rcu(br, addr, vid);
if (f && f->dst)
dev = f->dst->dev;
if (f) {
dst = READ_ONCE(f->dst);
if (dst)
dev = dst->dev;
}
rcu_read_unlock();
return dev;
@ -346,7 +350,7 @@ static void fdb_delete_local(struct net_bridge *br,
vg = nbp_vlan_group(op);
if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
(!vid || br_vlan_find(vg, vid))) {
f->dst = op;
WRITE_ONCE(f->dst, op);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@ -357,7 +361,7 @@ static void fdb_delete_local(struct net_bridge *br,
/* Maybe bridge device has same hw addr? */
if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
(!vid || (v && br_vlan_should_use(v)))) {
f->dst = NULL;
WRITE_ONCE(f->dst, NULL);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@ -922,6 +926,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long maxnum, unsigned long skip)
{
const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct __fdb_entry *fe = buf;
unsigned long delta;
@ -938,7 +943,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
continue;
/* ignore pseudo entry for local MAC address */
if (!f->dst)
dst = READ_ONCE(f->dst);
if (!dst)
continue;
if (skip) {
@ -950,8 +956,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
/* due to ABI compat need to split into hi/lo */
fe->port_no = f->dst->port_no;
fe->port_hi = f->dst->port_no >> 8;
fe->port_no = dst->port_no;
fe->port_hi = dst->port_no >> 8;
fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
if (!test_bit(BR_FDB_STATIC, &f->flags)) {
@ -1076,9 +1082,11 @@ int br_fdb_dump(struct sk_buff *skb,
rcu_read_lock();
hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
if (*idx < cb->args[2])
goto skip;
if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
if (filter_dev && (!dst || dst->dev != filter_dev)) {
if (filter_dev != dev)
goto skip;
/* !f->dst is a special case for bridge
@ -1086,10 +1094,10 @@ int br_fdb_dump(struct sk_buff *skb,
* Therefore need a little more filtering
* we only want to dump the !f->dst case
*/
if (f->dst)
if (dst)
goto skip;
}
if (!filter_dev && f->dst)
if (!filter_dev && dst)
goto skip;
err = fdb_fill_info(skb, br, f,

View File

@ -901,7 +901,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
struct net *net = dev_net_rcu(skb->dev);
struct net_device *dev = icmp6_dev(skb);
struct inet6_dev *idev = __in6_dev_get(dev);
const struct in6_addr *saddr, *daddr;
struct icmp6hdr *hdr;
u8 type;
@ -932,12 +931,10 @@ static int icmpv6_rcv(struct sk_buff *skb)
__ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS);
saddr = &ipv6_hdr(skb)->saddr;
daddr = &ipv6_hdr(skb)->daddr;
if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
saddr, daddr);
&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr);
goto csum_error;
}
@ -1020,7 +1017,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
break;
net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
saddr, daddr);
&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr);
/*
* error of unknown type.

View File

@ -213,8 +213,6 @@ struct rxrpc_skb_priv {
struct {
u16 offset; /* Offset of data */
u16 len; /* Length of data */
u8 flags;
#define RXRPC_RX_VERIFIED 0x01
};
struct {
rxrpc_seq_t first_ack; /* First packet in acks table */
@ -309,15 +307,16 @@ struct rxrpc_security {
struct sk_buff *challenge);
/* verify a response */
int (*verify_response)(struct rxrpc_connection *,
struct sk_buff *);
int (*verify_response)(struct rxrpc_connection *conn,
struct sk_buff *response_skb,
void *response, unsigned int len);
/* clear connection security */
void (*clear)(struct rxrpc_connection *);
/* Default ticket -> key decoder */
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);
};
@ -774,6 +773,11 @@ struct rxrpc_call {
struct sk_buff_head recvmsg_queue; /* Queue of packets ready for recvmsg() */
struct sk_buff_head rx_queue; /* Queue of packets for this call to receive */
struct sk_buff_head rx_oos_queue; /* Queue of out of sequence packets */
void *rx_dec_buffer; /* Decryption buffer */
unsigned short rx_dec_bsize; /* rx_dec_buffer size */
unsigned short rx_dec_offset; /* Decrypted packet data offset */
unsigned short rx_dec_len; /* Decrypted packet data len */
rxrpc_seq_t rx_dec_seq; /* Packet in decryption buffer */
rxrpc_seq_t rx_highest_seq; /* Higest sequence number received */
rxrpc_seq_t rx_consumed; /* Highest packet consumed */

View File

@ -332,25 +332,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)
saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK;
if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
sp->hdr.securityIndex != 0 &&
skb_cloned(skb)) {
/* Unshare the packet so that it can be
* modified by in-place decryption.
*/
struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb) {
rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
rxrpc_input_call_packet(call, nskb);
rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx);
} else {
/* OOM - Drop the packet. */
rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
}
} else {
rxrpc_input_call_packet(call, skb);
}
rxrpc_input_call_packet(call, skb);
rxrpc_free_skb(skb, rxrpc_skb_put_call_rx);
did_receive = true;
}

View File

@ -152,6 +152,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
spin_lock_init(&call->notify_lock);
refcount_set(&call->ref, 1);
call->debug_id = debug_id;
call->rx_pkt_offset = USHRT_MAX;
call->tx_total_len = -1;
call->tx_jumbo_max = 1;
call->next_rx_timo = 20 * HZ;
@ -553,6 +554,7 @@ static void rxrpc_cleanup_rx_buffers(struct rxrpc_call *call)
rxrpc_purge_queue(&call->recvmsg_queue);
rxrpc_purge_queue(&call->rx_queue);
rxrpc_purge_queue(&call->rx_oos_queue);
kfree(call->rx_dec_buffer);
}
/*

View File

@ -240,6 +240,28 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
rxrpc_notify_socket(call);
}
static int rxrpc_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
unsigned int len = skb->len - sizeof(struct rxrpc_wire_header);
void *buffer;
int ret;
buffer = kmalloc(len, GFP_NOFS);
if (!buffer)
return -ENOMEM;
ret = skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), buffer, len);
if (ret < 0)
goto out;
ret = conn->security->verify_response(conn, skb, buffer, len);
out:
kfree(buffer);
return ret;
}
/*
* connection-level Rx packet processor
*/
@ -247,6 +269,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
bool secured = false;
int ret;
if (conn->state == RXRPC_CONN_ABORTED)
@ -262,7 +285,14 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
case RXRPC_PACKET_TYPE_RESPONSE:
ret = conn->security->verify_response(conn, skb);
spin_lock_irq(&conn->state_lock);
if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
spin_unlock_irq(&conn->state_lock);
return 0;
}
spin_unlock_irq(&conn->state_lock);
ret = rxrpc_verify_response(conn, skb);
if (ret < 0)
return ret;
@ -272,11 +302,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
spin_lock_irq(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE;
secured = true;
}
spin_unlock_irq(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE) {
if (secured) {
/* Offload call state flipping to the I/O thread. As
* we've already received the packet, put it on the
* front of the queue.

View File

@ -963,23 +963,34 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call,
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_txqueue *tq = call->tx_queue;
unsigned long extracted = ~0UL;
unsigned int nr = 0;
unsigned int nr = 0, nsack;
rxrpc_seq_t seq = call->acks_hard_ack + 1;
rxrpc_seq_t lowest_nak = seq + sp->ack.nr_acks;
u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket);
u8 sack[256] __aligned(sizeof(unsigned long));
u8 *acks = sack;
_enter("%x,%x,%u", tq->qbase, seq, sp->ack.nr_acks);
while (after(seq, tq->qbase + RXRPC_NR_TXQUEUE - 1))
tq = tq->next;
/* Extract an individual SACK table. A normal SACK table is up to 255
* bytes with 1 ACK flag per byte, but an extended SACK table can be up
* to 256 bytes with up to 8 ACK/NACK flags per byte. The ACK flags go
* across all bit 0's then all bit 1's, then all bit 2's, ...
*/
memset(sack, 0, sizeof(sack));
nsack = umin(sp->ack.nr_acks, 256);
if (skb_copy_bits(skb,
sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket),
sack, nsack) < 0)
return;
for (unsigned int i = 0; i < sp->ack.nr_acks; i++) {
/* Decant ACKs until we hit a txqueue boundary. */
if ((i & 255) == 0)
acks = sack;
shiftr_adv_rotr(acks, extracted);
if (i == 256) {
acks -= i;
i = 0;
}
seq++;
nr++;
if ((seq & RXRPC_TXQ_MASK) != 0)
@ -1117,9 +1128,6 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
skb_copy_bits(skb, ioffset, &trailer, sizeof(trailer)) < 0)
return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_trailer);
if (nr_acks > 0)
skb_condense(skb);
call->acks_latest_ts = ktime_get_real();
call->acks_hard_ack = hard_ack;
call->acks_prev_seq = prev_pkt;

View File

@ -32,9 +32,6 @@ static int none_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
static int none_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
sp->flags |= RXRPC_RX_VERIFIED;
return 0;
}
@ -57,9 +54,10 @@ static int none_sendmsg_respond_to_challenge(struct sk_buff *challenge,
}
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);
}

View File

@ -147,15 +147,52 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
}
/*
* Decrypt and verify a DATA packet.
* Decrypt and verify a DATA packet. The content of the packet is pulled out
* into a flat buffer rather than decrypting in place in the skbuff. This also
* has the advantage of aligning the buffer correctly for the crypto routines.
*
* We keep track of the sequence number of the packet currently decrypted into
* the buffer in ->rx_dec_seq. If MSG_PEEK is used and steps onto a new
* packet, subsequent recvmsg() calls will have to go back and re-decrypt the
* current packet.
*/
static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
int ret;
if (sp->flags & RXRPC_RX_VERIFIED)
return 0;
return call->security->verify_packet(call, skb);
if (sp->len > call->rx_dec_bsize || !call->rx_dec_buffer) {
/* Make sure we can hold a 1412-byte jumbo subpacket and make
* sure that the buffer size is aligned to a crypto blocksize.
*/
size_t size = clamp(round_up(sp->len, 32), 2048, 65535);
void *buffer = krealloc(call->rx_dec_buffer, size, GFP_NOFS);
if (!buffer)
return -ENOMEM;
call->rx_dec_buffer = buffer;
call->rx_dec_bsize = size;
}
ret = -EFAULT;
if (skb_copy_bits(skb, sp->offset, call->rx_dec_buffer, sp->len) < 0)
goto err;
call->rx_dec_offset = 0;
call->rx_dec_len = sp->len;
call->rx_dec_seq = sp->hdr.seq;
ret = call->security->verify_packet(call, skb);
if (ret < 0)
goto err;
return 0;
err:
kfree(call->rx_dec_buffer);
call->rx_dec_buffer = NULL;
call->rx_dec_bsize = 0;
call->rx_dec_offset = 0;
call->rx_dec_len = 0;
return ret;
}
/*
@ -283,16 +320,21 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (msg)
sock_recv_timestamp(msg, sock->sk, skb);
if (rx_pkt_offset == 0) {
if (call->rx_dec_seq != sp->hdr.seq ||
!call->rx_dec_buffer) {
ret2 = rxrpc_verify_data(call, skb);
trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,
sp->offset, sp->len, ret2);
call->rx_dec_offset,
call->rx_dec_len, ret2);
if (ret2 < 0) {
ret = ret2;
goto out;
}
rx_pkt_offset = sp->offset;
rx_pkt_len = sp->len;
}
if (rx_pkt_offset == USHRT_MAX) {
rx_pkt_offset = call->rx_dec_offset;
rx_pkt_len = call->rx_dec_len;
} else {
trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq,
rx_pkt_offset, rx_pkt_len, 0);
@ -304,10 +346,10 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (copy > remain)
copy = remain;
if (copy > 0) {
ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
copy);
if (ret2 < 0) {
ret = ret2;
ret2 = copy_to_iter(call->rx_dec_buffer + rx_pkt_offset,
copy, iter);
if (ret2 != copy) {
ret = -EFAULT;
goto out;
}
@ -328,7 +370,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
/* The whole packet has been transferred. */
if (sp->hdr.flags & RXRPC_LAST_PACKET)
ret = 1;
rx_pkt_offset = 0;
rx_pkt_offset = USHRT_MAX;
rx_pkt_len = 0;
skb = skb_peek_next(skb, &call->recvmsg_queue);

View File

@ -473,15 +473,20 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call,
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxgk_header *hdr;
struct krb5_buffer metadata;
unsigned int offset = sp->offset, len = sp->len;
unsigned int len = call->rx_dec_len;
size_t data_offset = 0, data_len = len;
void *data = call->rx_dec_buffer, *p = data;
u32 ac = 0;
int ret = -ENOMEM;
_enter("");
crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
&data_offset, &data_len);
if (crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
&data_offset, &data_len) < 0) {
ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
rxgk_abort_1_short_header);
goto put_gk;
}
hdr = kzalloc(sizeof(*hdr), GFP_NOFS);
if (!hdr)
@ -496,16 +501,15 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call,
metadata.len = sizeof(*hdr);
metadata.data = hdr;
ret = rxgk_verify_mic_skb(gk->krb5, gk->rx_Kc, &metadata,
skb, &offset, &len, &ac);
ret = rxgk_verify_mic(gk->krb5, gk->rx_Kc, &metadata, &p, &len, &ac);
kfree(hdr);
if (ret < 0) {
if (ret != -ENOMEM)
rxrpc_abort_eproto(call, skb, ac,
rxgk_abort_1_verify_mic_eproto);
} else {
sp->offset = offset;
sp->len = len;
call->rx_dec_offset = p - data;
call->rx_dec_len = len;
}
put_gk:
@ -522,49 +526,53 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxgk_header hdr;
unsigned int offset = sp->offset, len = sp->len;
struct rxgk_header *hdr;
unsigned int offset = 0, len = call->rx_dec_len;
void *data = call->rx_dec_buffer, *p = data;
int ret;
u32 ac = 0;
_enter("");
ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac);
if (crypto_krb5_check_data_len(gk->krb5, KRB5_ENCRYPT_MODE,
len, sizeof(*hdr)) < 0) {
ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
rxgk_abort_2_short_header);
goto error;
}
ret = rxgk_decrypt(gk->krb5, gk->rx_enc, &p, &len, &ac);
if (ret < 0) {
if (ret != -ENOMEM)
rxrpc_abort_eproto(call, skb, ac, rxgk_abort_2_decrypt_eproto);
goto error;
}
offset = p - data;
if (len < sizeof(hdr)) {
if (len < sizeof(*hdr)) {
ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
rxgk_abort_2_short_header);
goto error;
}
/* Extract the header from the skb */
ret = skb_copy_bits(skb, offset, &hdr, sizeof(hdr));
if (ret < 0) {
ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
rxgk_abort_2_short_encdata);
goto error;
}
offset += sizeof(hdr);
len -= sizeof(hdr);
hdr = data + offset;
offset += sizeof(*hdr);
len -= sizeof(*hdr);
if (ntohl(hdr.epoch) != call->conn->proto.epoch ||
ntohl(hdr.cid) != call->cid ||
ntohl(hdr.call_number) != call->call_id ||
ntohl(hdr.seq) != sp->hdr.seq ||
ntohl(hdr.sec_index) != call->security_ix ||
ntohl(hdr.data_len) > len) {
if (ntohl(hdr->epoch) != call->conn->proto.epoch ||
ntohl(hdr->cid) != call->cid ||
ntohl(hdr->call_number) != call->call_id ||
ntohl(hdr->seq) != sp->hdr.seq ||
ntohl(hdr->sec_index) != call->security_ix ||
ntohl(hdr->data_len) > len) {
ret = rxrpc_abort_eproto(call, skb, RXGK_SEALEDINCON,
rxgk_abort_2_short_data);
goto error;
}
sp->offset = offset;
sp->len = ntohl(hdr.data_len);
call->rx_dec_offset = offset;
call->rx_dec_len = ntohl(hdr->data_len);
ret = 0;
error:
rxgk_put(gk);
@ -1076,15 +1084,19 @@ static int rxgk_sendmsg_respond_to_challenge(struct sk_buff *challenge,
* unsigned int call_numbers<>;
* };
*/
static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
const struct krb5_enctype *krb5,
struct sk_buff *skb,
__be32 *p, __be32 *end)
static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
const struct krb5_enctype *krb5,
struct sk_buff *skb,
void *auth, unsigned int auth_len)
{
__be32 *p = auth, *end = auth + auth_len;
u32 app_len, call_count, level, epoch, cid, i;
_enter("");
if ((end - p) * sizeof(__be32) < 24)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_short_auth);
if (memcmp(p, conn->rxgk.nonce, 20) != 0)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_bad_nonce);
@ -1098,7 +1110,7 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
p += xdr_round_up(app_len) / sizeof(__be32);
if (end - p < 4)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_short_applen);
rxgk_abort_resp_short_auth);
level = ntohl(*p++);
epoch = ntohl(*p++);
@ -1140,37 +1152,6 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
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.
*
@ -1181,50 +1162,47 @@ error:
* };
*/
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;
struct rxrpc_key_token *token;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxgk_response rhdr;
struct rxgk_response *rhdr;
struct rxgk_context *gk;
struct key *key = NULL;
unsigned int offset = sizeof(struct rxrpc_wire_header);
unsigned int len = skb->len - sizeof(struct rxrpc_wire_header);
unsigned int token_offset, token_len;
unsigned int auth_offset, auth_len;
unsigned int resp_token_len, auth_len;
void *resp_token, *auth;
__be32 xauth_len;
int ret, ec;
_enter("{%d}", conn->debug_id);
/* 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;
if (skb_copy_bits(skb, offset, &rhdr, sizeof(rhdr)) < 0)
goto short_packet;
offset += sizeof(rhdr);
len -= sizeof(rhdr);
trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, resp_token_len);
token_offset = offset;
token_len = ntohl(rhdr.token_len);
if (xdr_round_up(token_len) + sizeof(__be32) > len)
goto short_packet;
buffer += xdr_round_up(resp_token_len);
len -= xdr_round_up(resp_token_len);
trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_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);
xauth_len = *(__be32 *)buffer;
buffer += sizeof(xauth_len);
len -= sizeof(xauth_len);
auth_offset = offset;
auth = buffer;
auth_len = ntohl(xauth_len);
if (auth_len < len)
if (auth_len > len)
goto short_packet;
if (auth_len & 3)
goto inconsistent;
@ -1237,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
* 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)
goto out;
@ -1251,7 +1229,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
*/
token = key->payload.data[0];
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);
if (IS_ERR(gk)) {
@ -1261,24 +1239,26 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
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. */
ret = rxgk_decrypt_skb(krb5, gk->resp_enc, skb,
&auth_offset, &auth_len, &ec);
ret = rxgk_decrypt(krb5, gk->resp_enc, &auth, &auth_len, &ec);
if (ret < 0) {
rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret,
rxgk_abort_resp_auth_dec);
goto out;
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)
goto out;
goto out_gk;
conn->key = key;
key = NULL;
ret = 0;
out_gk:
rxgk_put(gk);
out:
key_put(key);
_leave(" = %d", ret);

View File

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

View File

@ -34,16 +34,17 @@ struct rxgk_context {
};
#define xdr_round_up(x) (round_up((x), sizeof(__be32)))
#define xdr_round_down(x) (round_down((x), sizeof(__be32)))
#define xdr_object_len(x) (4 + xdr_round_up(x))
/*
* rxgk_app.c
*/
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);
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);
/*
@ -61,31 +62,30 @@ int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
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
* Apply decryption and checksumming functions a flat data buffer. The data
* point 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)
static inline int rxgk_decrypt(const struct krb5_enctype *krb5,
struct crypto_aead *aead,
void **_data, unsigned int *_len,
int *_error_code)
{
struct scatterlist sg[16];
struct scatterlist sg[1];
size_t offset = 0, len = *_len;
int nr_sg, ret;
int 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;
sg_init_one(sg, *_data, len);
ret = crypto_krb5_decrypt(krb5, aead, sg, nr_sg,
&offset, &len);
ret = crypto_krb5_decrypt(krb5, aead, sg, 1, &offset, &len);
switch (ret) {
case 0:
*_offset += offset;
if (offset & 3) {
*_error_code = RXGK_INCONSISTENCY;
ret = -EPROTO;
break;
}
*_data += offset;
*_len = len;
break;
case -EBADMSG: /* Checksum mismatch. */
@ -105,31 +105,26 @@ int rxgk_decrypt_skb(const struct krb5_enctype *krb5,
}
/*
* Check the MIC on a region of an skbuff. The offset and length are updated
* to reflect the actual content of the secure region.
* Check the MIC on a flat buffer. The data pointer 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)
int rxgk_verify_mic(const struct krb5_enctype *krb5,
struct crypto_shash *shash,
const struct krb5_buffer *metadata,
void **_data, unsigned int *_len,
u32 *_error_code)
{
struct scatterlist sg[16];
struct scatterlist sg[1];
size_t offset = 0, len = *_len;
int nr_sg, ret;
int 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;
sg_init_one(sg, *_data, len);
ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, nr_sg,
&offset, &len);
ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, 1, &offset, &len);
switch (ret) {
case 0:
*_offset += offset;
*_data += offset;
*_len = len;
break;
case -EBADMSG: /* Checksum mismatch */

View File

@ -197,6 +197,7 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
struct rxrpc_crypt iv;
__be32 *tmpbuf;
size_t tmpsize = 4 * sizeof(__be32);
int ret;
_enter("");
@ -225,13 +226,13 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_free(req);
memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
kfree(tmpbuf);
_leave(" = 0");
return 0;
_leave(" = %d", ret);
return ret;
}
/*
@ -264,6 +265,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
struct scatterlist sg;
size_t pad;
u16 check;
int ret;
_enter("");
@ -286,11 +288,11 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
_leave(" = 0");
return 0;
_leave(" = %d", ret);
return ret;
}
/*
@ -345,7 +347,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
union {
__be32 buf[2];
} crypto __aligned(8);
u32 x, y;
u32 x, y = 0;
int ret;
_enter("{%d{%x}},{#%u},%u,",
@ -376,8 +378,10 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
if (ret < 0)
goto out;
y = ntohl(crypto.buf[1]);
y = (y >> 16) & 0xffff;
@ -413,6 +417,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
memset(p + txb->pkt_len, 0, gap);
}
out:
skcipher_request_free(req);
_leave(" = %d [set %x]", ret, y);
return ret;
@ -425,27 +430,25 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
rxrpc_seq_t seq,
struct skcipher_request *req)
{
struct rxkad_level1_hdr sechdr;
struct rxkad_level1_hdr *sechdr;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_crypt iv;
struct scatterlist sg[16];
u32 data_size, buf;
struct scatterlist sg[1];
void *data = call->rx_dec_buffer;
u32 len = sp->len, data_size, buf;
u16 check;
int ret;
_enter("");
if (sp->len < 8)
if (len < 8)
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_1_short_header);
/* Decrypt the skbuff in-place. TODO: We really want to decrypt
* directly into the target buffer.
*/
sg_init_table(sg, ARRAY_SIZE(sg));
ret = skb_to_sgvec(skb, sg, sp->offset, 8);
if (unlikely(ret < 0))
return ret;
sg_init_one(sg, data, len);
/* start the decryption afresh */
memset(&iv, 0, sizeof(iv));
@ -453,17 +456,17 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (ret < 0)
return ret;
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
rxkad_abort_1_short_encdata);
sp->offset += sizeof(sechdr);
sp->len -= sizeof(sechdr);
sechdr = data;
call->rx_dec_offset = sizeof(*sechdr);
len -= sizeof(*sechdr);
buf = ntohl(sechdr.data_size);
buf = ntohl(sechdr->data_size);
data_size = buf & 0xffff;
check = buf >> 16;
@ -472,10 +475,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
if (check != 0)
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_1_short_check);
if (data_size > sp->len)
if (data_size > len)
return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
rxkad_abort_1_short_data);
sp->len = data_size;
call->rx_dec_len = data_size;
_leave(" = 0 [dlen=%x]", data_size);
return 0;
@ -489,40 +492,28 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
struct skcipher_request *req)
{
const struct rxrpc_key_token *token;
struct rxkad_level2_hdr sechdr;
struct rxkad_level2_hdr *sechdr;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_crypt iv;
struct scatterlist _sg[4], *sg;
u32 data_size, buf;
struct scatterlist sg[1];
void *data = call->rx_dec_buffer;
u32 len = sp->len, data_size, buf;
u16 check;
int nsg, ret;
int ret;
_enter(",{%d}", sp->len);
_enter(",{%d}", len);
if (sp->len < 8)
if (len < 8)
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_2_short_header);
/* Decrypt the skbuff in-place. TODO: We really want to decrypt
* directly into the target buffer.
*/
sg = _sg;
nsg = skb_shinfo(skb)->nr_frags + 1;
if (nsg <= 4) {
nsg = 4;
} else {
sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
if (!sg)
return -ENOMEM;
}
/* Don't let the crypto algo see a misaligned length. */
len = round_down(len, 8);
sg_init_table(sg, nsg);
ret = skb_to_sgvec(skb, sg, sp->offset, sp->len);
if (unlikely(ret < 0)) {
if (sg != _sg)
kfree(sg);
return ret;
}
/* Decrypt in place in the call's decryption buffer. TODO: We really
* want to decrypt directly into the target buffer.
*/
sg_init_one(sg, data, len);
/* decrypt from the session key */
token = call->conn->key->payload.data[0];
@ -530,20 +521,22 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sp->len, iv.x);
crypto_skcipher_decrypt(req);
skcipher_request_set_crypt(req, sg, sg, len, iv.x);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (sg != _sg)
kfree(sg);
if (ret < 0) {
if (ret == -ENOMEM)
return ret;
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_2_crypto_unaligned);
}
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
rxkad_abort_2_short_len);
sp->offset += sizeof(sechdr);
sp->len -= sizeof(sechdr);
sechdr = data;
call->rx_dec_offset = sizeof(*sechdr);
len -= sizeof(*sechdr);
buf = ntohl(sechdr.data_size);
buf = ntohl(sechdr->data_size);
data_size = buf & 0xffff;
check = buf >> 16;
@ -553,17 +546,18 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_2_short_check);
if (data_size > sp->len)
if (data_size > len)
return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
rxkad_abort_2_short_data);
sp->len = data_size;
call->rx_dec_len = data_size;
_leave(" = 0 [dlen=%x]", data_size);
return 0;
}
/*
* Verify the security on a received packet and the subpackets therein.
* Verify the security on a received (sub)packet. If the packet needs
* modifying (e.g. decrypting), it must be copied.
*/
static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
{
@ -602,8 +596,10 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
if (ret < 0)
goto out;
y = ntohl(crypto.buf[1]);
cksum = (y >> 16) & 0xffff;
@ -966,7 +962,6 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
*_expiry = 0;
ASSERT(server_key->payload.data[0] != NULL);
ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
@ -1073,21 +1068,23 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
/*
* decrypt the response packet
*/
static void rxkad_decrypt_response(struct rxrpc_connection *conn,
struct rxkad_response *resp,
const struct rxrpc_crypt *session_key)
static int rxkad_decrypt_response(struct rxrpc_connection *conn,
struct rxkad_response *resp,
const struct rxrpc_crypt *session_key)
{
struct skcipher_request *req = rxkad_ci_req;
struct scatterlist sg[1];
struct rxrpc_crypt iv;
int ret;
_enter(",,%08x%08x",
ntohl(session_key->n[0]), ntohl(session_key->n[1]));
mutex_lock(&rxkad_ci_mutex);
if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
sizeof(*session_key)) < 0)
BUG();
ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
sizeof(*session_key));
if (ret < 0)
goto unlock;
memcpy(&iv, session_key, sizeof(iv));
@ -1096,19 +1093,22 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, rxkad_ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
unlock:
mutex_unlock(&rxkad_ci_mutex);
_leave("");
return ret;
}
/*
* verify a response
*/
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 rxrpc_skb_priv *sp = rxrpc_skb(skb);
@ -1138,16 +1138,11 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
}
}
ret = -ENOMEM;
response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
if (!response)
goto temporary_error;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
response, sizeof(*response)) < 0) {
rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short);
goto protocol_error;
response = buffer;
if (len < sizeof(*response)) {
ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short);
goto error;
}
version = ntohl(response->version);
@ -1156,61 +1151,61 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
trace_rxrpc_rx_response(conn, sp->hdr.serial, version, kvno, ticket_len);
buffer += sizeof(*response);
len -= sizeof(*response);
if (version != RXKAD_VERSION) {
rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
rxkad_abort_resp_version);
goto protocol_error;
ret = rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
rxkad_abort_resp_version);
goto error;
}
if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN) {
rxrpc_abort_conn(conn, skb, RXKADTICKETLEN, -EPROTO,
rxkad_abort_resp_tkt_len);
goto protocol_error;
ret = rxrpc_abort_conn(conn, skb, RXKADTICKETLEN, -EPROTO,
rxkad_abort_resp_tkt_len);
goto error;
}
if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5) {
rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, -EPROTO,
rxkad_abort_resp_unknown_tkt);
goto protocol_error;
ret = rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, -EPROTO,
rxkad_abort_resp_unknown_tkt);
goto error;
}
/* extract the kerberos ticket and decrypt and decode it */
ret = -ENOMEM;
ticket = kmalloc(ticket_len, GFP_NOFS);
if (!ticket)
goto temporary_error_free_resp;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response),
ticket, ticket_len) < 0) {
rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short_tkt);
goto protocol_error;
ticket = buffer;
if (ticket_len > len) {
ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
rxkad_abort_resp_short_tkt);
goto error;
}
ret = rxkad_decrypt_ticket(conn, server_key, skb, ticket, ticket_len,
&session_key, &expiry);
if (ret < 0)
goto temporary_error_free_ticket;
goto error;
/* use the session key from inside the ticket to decrypt the
* response */
rxkad_decrypt_response(conn, response, &session_key);
ret = rxkad_decrypt_response(conn, response, &session_key);
if (ret < 0)
goto error;
if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
ntohl(response->encrypted.cid) != conn->proto.cid ||
ntohl(response->encrypted.securityIndex) != conn->security_ix) {
rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_param);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_param);
goto error;
}
csum = response->encrypted.checksum;
response->encrypted.checksum = 0;
rxkad_calc_response_checksum(response);
if (response->encrypted.checksum != csum) {
rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_checksum);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_checksum);
goto error;
}
for (i = 0; i < RXRPC_MAXCALLS; i++) {
@ -1218,38 +1213,38 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
u32 counter = READ_ONCE(conn->channels[i].call_counter);
if (call_id > INT_MAX) {
rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_callid);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_bad_callid);
goto error;
}
if (call_id < counter) {
rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_call_ctr);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_call_ctr);
goto error;
}
if (call_id > counter) {
if (conn->channels[i].call) {
rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_call_state);
goto protocol_error_free;
goto error;
}
conn->channels[i].call_counter = call_id;
}
}
if (ntohl(response->encrypted.inc_nonce) != conn->rxkad.nonce + 1) {
rxrpc_abort_conn(conn, skb, RXKADOUTOFSEQUENCE, -EPROTO,
rxkad_abort_resp_ooseq);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADOUTOFSEQUENCE, -EPROTO,
rxkad_abort_resp_ooseq);
goto error;
}
level = ntohl(response->encrypted.level);
if (level > RXRPC_SECURITY_ENCRYPT) {
rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EPROTO,
rxkad_abort_resp_level);
goto protocol_error_free;
ret = rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EPROTO,
rxkad_abort_resp_level);
goto error;
}
conn->security_level = level;
@ -1257,31 +1252,10 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
* this the connection security can be handled in exactly the same way
* as for a client connection */
ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
if (ret < 0)
goto temporary_error_free_ticket;
kfree(ticket);
kfree(response);
_leave(" = 0");
return 0;
protocol_error_free:
kfree(ticket);
protocol_error:
kfree(response);
key_put(server_key);
return -EPROTO;
temporary_error_free_ticket:
kfree(ticket);
temporary_error_free_resp:
kfree(response);
temporary_error:
/* Ignore the response packet if we got a temporary error such as
* ENOMEM. We just want to send the challenge again. Note that we
* also come out this way if the ticket decryption fails.
*/
error:
key_put(server_key);
_leave(" = %d", ret);
return ret;
}

View File

@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (fragid == LAST_FRAGMENT) {
TIPC_SKB_CB(head)->validated = 0;
if (unlikely(!tipc_msg_validate(&head)))
/* If the reassembled skb has been freed in
* tipc_msg_validate() because of an invalid truesize,
* then head will point to a newly allocated reassembled
* skb, while *headbuf points to freed reassembled skb.
* In such cases, correct *headbuf for freeing the newly
* allocated reassembled skb later.
*/
if (unlikely(!tipc_msg_validate(&head))) {
if (head != *headbuf)
*headbuf = head;
goto err;
}
*buf = head;
TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL;

View File

@ -1,3 +1,27 @@
* Mon Jul 27 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.40.1.el10_2]
- ipv6: fix possible UAF in icmpv6_rcv() (CKI Backport Bot) [RHEL-192215] {CVE-2026-53006}
- tipc: fix double-free in tipc_buf_append() (CKI Backport Bot) [RHEL-192181] {CVE-2026-52993}
- iommu/vt-d: Avoid NULL pointer dereference or refcount corruption (Eder Zulian) [RHEL-190344] {CVE-2026-53281}
- iommu/vt-d: Fix oops due to out of scope access (Eder Zulian) [RHEL-190344]
- net: bridge: use a stable FDB dst snapshot in RCU readers (Mohammad Heib) [RHEL-179338] {CVE-2026-46086}
- rxrpc: rxrpc_verify_data ensure rx_dec_buffer alloc (Marc Dionne) [RHEL-178254]
- rxrpc: Fix the ACK parser to extract the SACK table for parsing (Marc Dionne) [RHEL-178254]
- rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer (Marc Dionne) [RHEL-178254]
- rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg (Marc Dionne) [RHEL-178254]
- crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks (Marc Dionne) [RHEL-178254]
- rxrpc: fix oversized RESPONSE authenticator length check (Marc Dionne) [RHEL-178254] {CVE-2026-31635}
- rxrpc: Fix integer overflow in rxgk_verify_response() (Marc Dionne) [RHEL-178254] {CVE-2026-31633}
- rxrpc: Fix leak of rxgk context in rxgk_verify_response() (Marc Dionne) [RHEL-178254] {CVE-2026-31632}
- rxrpc: Fix buffer overread in rxgk_do_verify_authenticator() (Marc Dionne) [RHEL-178254] {CVE-2026-31631}
- rxgk: Fix potential integer overflow in length check (Marc Dionne) [RHEL-178254]
- rxrpc: Fix rxkad crypto unalignment handling (Marc Dionne) [RHEL-178254]
- rxrpc: Fix memory leaks in rxkad_verify_response() (Marc Dionne) [RHEL-178254]
- rxrpc: Fix missing error checks for rxkad encryption/decryption failure (Marc Dionne) [RHEL-178254]
- rxrpc: Also unshare DATA/RESPONSE packets when paged frags are present (Marc Dionne) [RHEL-178254] {CVE-2026-43500}
- rxrpc: Fix conn-level packet handling to unshare RESPONSE packets (Marc Dionne) [RHEL-178254]
- rxrpc: only handle RESPONSE during service challenge (Marc Dionne) [RHEL-178254] {CVE-2026-31676}
Resolves: RHEL-178254, RHEL-179338, RHEL-190344, RHEL-192181, RHEL-192215
* Thu Jul 23 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.39.1.el10_2]
- futex: Drop CLONE_THREAD requirement for private default hash alloc (Audra Mitchell) [RHEL-193518] {CVE-2026-52973}
- net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels (Antoine Tenart) [RHEL-179299] {CVE-2026-46099}

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.40.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.39.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.40.1.el10.x86_64,mailto:security@almalinux.org