From e75c7e961b0904a4d8eaae33169dc498c75c7b9b Mon Sep 17 00:00:00 2001 From: "Justin M. Forbes" Date: Tue, 19 May 2026 11:26:49 -0600 Subject: [PATCH] kernel-7.0.9-104 * Tue May 19 2026 Justin M. Forbes [7.0.9-4] - rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer (David Howells) - rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg (David Howells) - crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks (David Howells) Resolves: Signed-off-by: Justin M. Forbes --- Makefile.rhelver | 2 +- Patchlist.changelog | 9 + kernel.changelog | 6 + kernel.spec | 9 +- patch-7.0-redhat.patch | 1234 +++++++++++++++++++++++++++++++++++++++- sources | 2 +- 6 files changed, 1257 insertions(+), 5 deletions(-) diff --git a/Makefile.rhelver b/Makefile.rhelver index dbdb99ad3..f8a4a2cb0 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 99 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 3 +RHEL_RELEASE = 4 # # RHEL_REBASE_NUM diff --git a/Patchlist.changelog b/Patchlist.changelog index e6d92af44..7dc4ecdd8 100644 --- a/Patchlist.changelog +++ b/Patchlist.changelog @@ -1,3 +1,12 @@ +https://gitlab.com/cki-project/kernel-ark/-/commit/9e9264cdf81ef84b11b2d0411744a8e3c2ca31f2 + 9e9264cdf81ef84b11b2d0411744a8e3c2ca31f2 rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer + +https://gitlab.com/cki-project/kernel-ark/-/commit/83a16fe8bd1bf21c0431394d24dcd25fb7e084c4 + 83a16fe8bd1bf21c0431394d24dcd25fb7e084c4 rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg + +https://gitlab.com/cki-project/kernel-ark/-/commit/6de6ce80c64131967af4bbb4edc04c1fab23713c + 6de6ce80c64131967af4bbb4edc04c1fab23713c crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks + https://gitlab.com/cki-project/kernel-ark/-/commit/649b9ca38bcee431bb562ad4710aadf21345914c 649b9ca38bcee431bb562ad4710aadf21345914c net: gro: don't copy frags between mixed zcopy skbs diff --git a/kernel.changelog b/kernel.changelog index d00c5a827..c72d3d62b 100644 --- a/kernel.changelog +++ b/kernel.changelog @@ -1,3 +1,9 @@ +* Tue May 19 2026 Justin M. Forbes [7.0.9-4] +- rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer (David Howells) +- rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg (David Howells) +- crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks (David Howells) +Resolves: + * Tue May 19 2026 Justin M. Forbes [7.0.9-3] - net: gro: don't copy frags between mixed zcopy skbs (Sabrina Dubroca) Resolves: diff --git a/kernel.spec b/kernel.spec index 343734791..81b2681ed 100644 --- a/kernel.spec +++ b/kernel.spec @@ -190,13 +190,13 @@ Summary: The Linux kernel %define specrpmversion 7.0.9 %define specversion 7.0.9 %define patchversion 7.0 -%define pkgrelease 103 +%define pkgrelease 104 %define kversion 7 %define tarfile_release 7.0.9 # This is needed to do merge window version magic %define patchlevel 0 # This allows pkg_release to have configurable %%{?dist} tag -%define specrelease 103%{?buildid}%{?dist} +%define specrelease 104%{?buildid}%{?dist} # This defines the kabi tarball version %define kabiversion 7.0.9 @@ -4825,6 +4825,11 @@ fi\ # # %changelog +* Tue May 19 2026 Justin M. Forbes [7.0.9-4] +- rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer (David Howells) +- rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg (David Howells) +- crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks (David Howells) + * Tue May 19 2026 Justin M. Forbes [7.0.9-3] - net: gro: don't copy frags between mixed zcopy skbs (Sabrina Dubroca) diff --git a/patch-7.0-redhat.patch b/patch-7.0-redhat.patch index 72402f698..8664ed0b5 100644 --- a/patch-7.0-redhat.patch +++ b/patch-7.0-redhat.patch @@ -1,6 +1,7 @@ Documentation/admin-guide/media/amdisp4-1.rst | 63 ++ Documentation/admin-guide/media/amdisp4.dot | 6 + Documentation/admin-guide/media/v4l-drivers.rst | 1 + + Documentation/crypto/krb5.rst | 17 +- MAINTAINERS | 25 + Makefile | 30 + arch/arm/Kconfig | 4 +- @@ -17,6 +18,7 @@ arch/s390/kernel/ipl.c | 5 + arch/s390/kernel/setup.c | 4 + arch/x86/kernel/setup.c | 22 +- + crypto/krb5/krb5_api.c | 54 +- crypto/sig.c | 3 +- crypto/testmgr.c | 2 +- drivers/acpi/apei/hest.c | 8 + @@ -59,15 +61,27 @@ drivers/net/ethernet/cadence/macb_main.c | 736 ++++++++------ drivers/pci/quirks.c | 24 + drivers/usb/core/hub.c | 7 + + include/crypto/krb5.h | 9 +- include/linux/efi.h | 22 +- include/linux/lsm_hook_defs.h | 1 + include/linux/mfd/bcm2835-pm.h | 7 + include/linux/rmi.h | 1 + include/linux/security.h | 9 + + include/trace/events/rxrpc.h | 1 + kernel/module/signing.c | 9 +- net/core/gro.c | 7 + net/core/skbuff.c | 9 +- net/ipv4/tcp_output.c | 1 + + net/rxrpc/ar-internal.h | 14 +- + net/rxrpc/call_event.c | 22 +- + net/rxrpc/call_object.c | 2 + + net/rxrpc/conn_event.c | 32 +- + net/rxrpc/insecure.c | 8 +- + net/rxrpc/recvmsg.c | 76 +- + net/rxrpc/rxgk.c | 160 ++- + net/rxrpc/rxgk_app.c | 46 +- + net/rxrpc/rxgk_common.h | 66 +- + net/rxrpc/rxkad.c | 115 +-- net/sched/act_pedit.c | 72 +- scripts/Makefile.lib | 3 + scripts/tags.sh | 2 + @@ -76,7 +90,7 @@ security/lockdown/lockdown.c | 11 + tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/prog_tests/ksyms_btf.c | 31 - - 78 files changed, 5468 insertions(+), 566 deletions(-) + 92 files changed, 5784 insertions(+), 872 deletions(-) diff --git a/Documentation/admin-guide/media/amdisp4-1.rst b/Documentation/admin-guide/media/amdisp4-1.rst new file mode 100644 @@ -171,6 +185,37 @@ index 393f83e8dc4d..0fb88449fffd 100644 bttv c3-isp cafe_ccic +diff --git a/Documentation/crypto/krb5.rst b/Documentation/crypto/krb5.rst +index beffa0133446..f62e07ac6811 100644 +--- a/Documentation/crypto/krb5.rst ++++ b/Documentation/crypto/krb5.rst +@@ -158,13 +158,22 @@ returned. + When a message has been received, the location and size of the data with the + message can be determined by calling:: + +- 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); + + The caller provides the offset and length of the message to the function, which + then alters those values to indicate the region containing the data (plus any +-padding). It is up to the caller to determine how much padding there is. ++padding). It is up to the caller to determine how much padding there is. The ++function returns an error if the length is too small or if the mode is ++unsupported. An additional function:: ++ ++ int crypto_krb5_check_data_len(const struct krb5_enctype *krb5, ++ enum krb5_crypto_mode mode, ++ size_t len, size_t min_content); ++ ++is provided to just do a basic check that the decrypted/verified message would ++have a sufficient minimum payload. + + Preparation Functions + --------------------- diff --git a/MAINTAINERS b/MAINTAINERS index d1cc0e12fe1f..985c66951475 100644 --- a/MAINTAINERS @@ -815,6 +860,86 @@ index eebcc9db1a1b..779aca6969df 100644 reserve_initrd(); +diff --git a/crypto/krb5/krb5_api.c b/crypto/krb5/krb5_api.c +index 23026d4206c8..c7ea40f900a7 100644 +--- a/crypto/krb5/krb5_api.c ++++ b/crypto/krb5/krb5_api.c +@@ -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. + */ diff --git a/crypto/sig.c b/crypto/sig.c index beba745b6405..fd41f6d3abf9 100644 --- a/crypto/sig.c @@ -7329,6 +7454,26 @@ index 24960ba9caa9..32597cdb72ef 100644 /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ usb_lock_device(hdev); +diff --git a/include/crypto/krb5.h b/include/crypto/krb5.h +index 71dd38f59be1..aac3ecf88467 100644 +--- a/include/crypto/krb5.h ++++ b/include/crypto/krb5.h +@@ -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); diff --git a/include/linux/efi.h b/include/linux/efi.h index 664898d09ff5..34f476d02181 100644 --- a/include/linux/efi.h @@ -7462,6 +7607,18 @@ index 8d2d4856934e..d6b1aec4340f 100644 +#endif /* CONFIG_SECURITY_LOCKDOWN_LSM */ + #endif /* ! __LINUX_SECURITY_H */ +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 573f2df3a2c9..704a10de6670 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -71,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") \ diff --git a/kernel/module/signing.c b/kernel/module/signing.c index a2ff4242e623..f0d2be1ee4f1 100644 --- a/kernel/module/signing.c @@ -7574,6 +7731,1081 @@ index 326b58ff1118..691fc76c5508 100644 if (lastfrag && skb_frag_page(fragfrom) == skb_frag_page(lastfrag) && skb_frag_off(fragfrom) == skb_frag_off(lastfrag) + +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 27c2aa2dd023..98f2165159d7 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -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 */ +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index 2b19b252225e..fec59d9338b9 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -332,27 +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) || +- skb_has_frag_list(skb) || +- skb_has_shared_frag(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; + } +diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c +index f035f486c139..fcb9d38bb521 100644 +--- a/net/rxrpc/call_object.c ++++ b/net/rxrpc/call_object.c +@@ -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); + } + + /* +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index 442414d90ba1..c96ca615b787 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -243,28 +243,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *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; + +- if (skb_cloned(skb) || skb_has_frag_list(skb) || +- skb_has_shared_frag(skb)) { +- /* Copy the packet if shared so that we can do in-place +- * decryption. +- */ +- struct sk_buff *nskb = skb_copy(skb, GFP_NOFS); +- +- if (nskb) { +- rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); +- ret = conn->security->verify_response(conn, nskb); +- rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy); +- } else { +- /* OOM - Drop the packet. */ +- rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); +- ret = -ENOMEM; +- } +- } else { +- ret = conn->security->verify_response(conn, skb); +- } ++ 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; + } + +diff --git a/net/rxrpc/insecure.c b/net/rxrpc/insecure.c +index 0a260df45d25..0b39046bdc61 100644 +--- a/net/rxrpc/insecure.c ++++ b/net/rxrpc/insecure.c +@@ -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); + } + +diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c +index e1f7513a46db..0802f12cbbfc 100644 +--- a/net/rxrpc/recvmsg.c ++++ b/net/rxrpc/recvmsg.c +@@ -147,15 +147,55 @@ 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. Unfortunately, this means that a MSG_PEEK of ++ * more than one byte may cause a later packet to be decrypted into the buffer, ++ * requiring the original to be re-decrypted when recvmsg() is called again. + */ + 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) ++ if (call->rx_dec_seq == sp->hdr.seq && call->rx_dec_buffer) + return 0; +- return call->security->verify_packet(call, skb); ++ ++ if (sp->len > call->rx_dec_bsize) { ++ /* 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 = max(round_up(sp->len, 32), 2048); ++ 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 +323,19 @@ 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 (rx_pkt_offset == USHRT_MAX) { + 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; ++ sp = rxrpc_skb(skb); ++ seq = sp->hdr.seq; ++ 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 +347,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,13 +371,18 @@ 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; + ++ /* Terminate the receive here for MSG_PEEK otherwise we'd have ++ * to replace the contents of ->rx_dec_buffer. ++ */ ++ if (unlikely(flags & MSG_PEEK)) ++ break; ++ + skb = skb_peek_next(skb, &call->recvmsg_queue); + +- if (!(flags & MSG_PEEK)) +- rxrpc_rotate_rx_window(call); ++ rxrpc_rotate_rx_window(call); + + if (!rx->app_ops && + !skb_queue_empty_lockless(&rx->recvmsg_oobq)) { +diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c +index 0d5e654da918..a1ee102abae1 100644 +--- a/net/rxrpc/rxgk.c ++++ b/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_obj(*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); +- +- 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) { ++ 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) { + 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,11 +1084,12 @@ 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(""); +@@ -1143,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. + * +@@ -1184,49 +1162,45 @@ static int rxgk_verify_authenticator(struct rxrpc_connection *conn, + * }; + */ + static int rxgk_verify_response(struct rxrpc_connection *conn, +- struct sk_buff *skb) ++ struct sk_buff *skb, ++ void *buffer, unsigned int len) + { + const struct krb5_enctype *krb5; + 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; +- +- if (skb_copy_bits(skb, offset, &rhdr, sizeof(rhdr)) < 0) +- goto short_packet; +- offset += sizeof(rhdr); +- len -= sizeof(rhdr); +- +- token_offset = offset; +- token_len = ntohl(rhdr.token_len); +- if (token_len > len || +- xdr_round_up(token_len) + sizeof(__be32) > len) ++ 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; + +- trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_len); ++ trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, resp_token_len); + +- offset += xdr_round_up(token_len); +- len -= xdr_round_up(token_len); ++ buffer += xdr_round_up(resp_token_len); ++ len -= xdr_round_up(resp_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) + goto short_packet; +@@ -1241,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; + +@@ -1255,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)) { +@@ -1265,18 +1239,18 @@ 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_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_gk; + +diff --git a/net/rxrpc/rxgk_app.c b/net/rxrpc/rxgk_app.c +index 0ef2a29eb695..200a30064fae 100644 +--- a/net/rxrpc/rxgk_app.c ++++ b/net/rxrpc/rxgk_app.c +@@ -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 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb, + * [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 (ticket_len > xdr_round_down(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) { +@@ -248,7 +240,7 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, + return ret; + } + +- 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; +diff --git a/net/rxrpc/rxgk_common.h b/net/rxrpc/rxgk_common.h +index 1e257d7ab8ec..3deed5863f5a 100644 +--- a/net/rxrpc/rxgk_common.h ++++ b/net/rxrpc/rxgk_common.h +@@ -41,10 +41,10 @@ struct rxgk_context { + * 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); + + /* +@@ -62,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. */ +@@ -106,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 */ +diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c +index cba7935977f0..e970bf3ae78a 100644 +--- a/net/rxrpc/rxkad.c ++++ b/net/rxrpc/rxkad.c +@@ -430,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)); +@@ -464,13 +462,11 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, + 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; +@@ -479,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; +@@ -496,43 +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); + + /* Don't let the crypto algo see a misaligned length. */ +- sp->len = round_down(sp->len, 8); ++ len = round_down(len, 8); + +- /* Decrypt the skbuff in-place. TODO: We really want to decrypt +- * directly into the target buffer. ++ /* Decrypt in place in the call's decryption buffer. 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_objs(*sg, nsg, GFP_NOIO); +- if (!sg) +- return -ENOMEM; +- } +- +- 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; +- } ++ sg_init_one(sg, data, len); + + /* decrypt from the session key */ + token = call->conn->key->payload.data[0]; +@@ -540,11 +521,9 @@ 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); ++ 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; +@@ -553,13 +532,11 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, + } + + /* 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; +@@ -569,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) + { +@@ -985,7 +963,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)); + +@@ -1134,14 +1111,15 @@ static int rxkad_decrypt_response(struct rxrpc_connection *conn, + * 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); + struct rxrpc_crypt session_key; + struct key *server_key; + time64_t expiry; +- void *ticket = NULL; ++ void *ticket; + u32 version, kvno, ticket_len, level; + __be32 csum; + int ret, i; +@@ -1164,13 +1142,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, + } + } + +- ret = -ENOMEM; +- response = kzalloc_obj(struct rxkad_response, GFP_NOFS); +- if (!response) +- goto error; +- +- if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), +- response, sizeof(*response)) < 0) { ++ response = buffer; ++ if (len < sizeof(*response)) { + ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO, + rxkad_abort_resp_short); + goto error; +@@ -1182,6 +1155,9 @@ 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) { + ret = rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO, + rxkad_abort_resp_version); +@@ -1201,13 +1177,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, + } + + /* extract the kerberos ticket and decrypt and decode it */ +- ret = -ENOMEM; +- ticket = kmalloc(ticket_len, GFP_NOFS); +- if (!ticket) +- goto error; +- +- if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response), +- ticket, ticket_len) < 0) { ++ ticket = buffer; ++ if (ticket_len >= len) { + ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO, + rxkad_abort_resp_short_tkt); + goto error; +@@ -1287,8 +1258,6 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, + ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno); + + error: +- kfree(ticket); +- kfree(response); + key_put(server_key); + _leave(" = %d", ret); + return ret; diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index bc20f08a2789..1aa95c34ad87 100644 --- a/net/sched/act_pedit.c diff --git a/sources b/sources index a78ebd04d..7f99aeafa 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ SHA512 (linux-7.0.9.tar.xz) = 40a5553bcccd34216c4925a2e1e19abea1dbb5e33b4aa1608024f96615ba05b0bb3d063d038891f828fc2dd5c8500030a8336a7db83ef0bf1a5e082d7fb92334 -SHA512 (kernel-abi-stablelists-7.0.9.tar.xz) = f75bd45228d1bd57732aaf593517eccaa26b3e5350208bb074850282e36441cefb165a948a3a205018ac12bca984c2ad2e78b6ed5b9b4e79dd72d38e9bc1d5cd +SHA512 (kernel-abi-stablelists-7.0.9.tar.xz) = 677e8f637e8d84a03b16799e976f5cba61c50403bfe83b6d27adbb2faca239a2cd90b9cf7a530f5b375aaf0b158a060fd28c79beb3ef22f7399985ea6eec74da SHA512 (kernel-kabi-dw-7.0.9.tar.xz) = 9bb7d49af2456c7b09e7336a6fb6e78b2924dcb9006d3df6c1dd13033bf54ff2caf3f32de145caba3c81e14513b53e282253898fadefd2361441ea96370fe9e9