Import of kernel-6.12.0-211.40.1.el10_2
This commit is contained in:
parent
4c4ddb2cb6
commit
a435f44323
@ -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
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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") \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
172
net/rxrpc/rxgk.c
172
net/rxrpc/rxgk.c
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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
|
||||
|
||||
2
uki.sbat
2
uki.sbat
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user