From ec9fa7953c4913fdb8ec7a9aea73fb6c0b38e1af Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Wed, 22 Jul 2026 11:45:32 +0000 Subject: [PATCH] Fix 13 more Important CVEs ahead of RHEL; bump to 687.26.3 Backport upstream stable fixes for newly RHEL-Affected Important CVEs (patches 1108-1120), closest-to-5.14 base, verified zero-fuzz full %prep replay: CVE-2026-63886 63887 63888 (iscsi target), 63899 63956 (usb-serial), 63917 (ip6 vti), 63922 63924 (ipv6 exthdrs), 63939 (kvm sev), 63994 (tunnels), 64017 (blk-mq), 64026 (rxrpc), 64030 (mac80211) --- ...i-validate-chap-r-length-before-base.patch | 98 +++++ ...i-bound-iscsi-encode-text-output-app.patch | 207 +++++++++ ...i-fix-crc-overread-and-double-free-i.patch | 126 ++++++ ...ort-fix-memory-corruption-with-small.patch | 47 ++ ...i-use-ip6-tnl-net-in-vti6-changelink.patch | 80 ++++ ...resh-nh-pointer-after-ipv6-hop-jumbo.patch | 42 ++ ...refresh-nh-after-handling-hao-option.patch | 56 +++ ...the-correct-max-length-of-the-in-ghc.patch | 105 +++++ ...ss-m8-fix-memory-corruption-with-sma.patch | 48 ++ ...oad-network-headers-after-skb-cow-in.patch | 88 ++++ ...q-pop-cached-request-if-it-is-usable.patch | 117 +++++ ...decrypt-vs-splice-by-copying-data-to.patch | 409 ++++++++++++++++++ ...unds-check-link-id-in-ieee80211-ml-e.patch | 53 +++ SPECS/kernel.spec | 45 +- 14 files changed, 1519 insertions(+), 2 deletions(-) create mode 100644 SOURCES/1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch create mode 100644 SOURCES/1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch create mode 100644 SOURCES/1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch create mode 100644 SOURCES/1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch create mode 100644 SOURCES/1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch create mode 100644 SOURCES/1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch create mode 100644 SOURCES/1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch create mode 100644 SOURCES/1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch create mode 100644 SOURCES/1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch create mode 100644 SOURCES/1117-tunnels-load-network-headers-after-skb-cow-in.patch create mode 100644 SOURCES/1118-blk-mq-pop-cached-request-if-it-is-usable.patch create mode 100644 SOURCES/1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch create mode 100644 SOURCES/1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch diff --git a/SOURCES/1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch b/SOURCES/1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch new file mode 100644 index 000000000..5e6a42745 --- /dev/null +++ b/SOURCES/1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch @@ -0,0 +1,98 @@ +From 82454e6f21e56ea9a0a9de7d0ff7e1dfb83e34d6 Mon Sep 17 00:00:00 2001 +From: Alexandru Hossu +Date: Thu, 21 May 2026 17:11:21 +0200 +Subject: [PATCH] scsi: target: iscsi: Validate CHAP_R length before base64 + decode + +commit 85db7391310b1304d2dc8ae3b0b12105a9567147 upstream. + +chap_server_compute_hash() allocates client_digest as +kzalloc(chap->digest_size) and then, for BASE64-encoded responses, +passes chap_r directly to chap_base64_decode() without checking whether +the input length could produce more than digest_size bytes of output. + +chap_base64_decode() writes to the destination unconditionally as long +as there is input to consume. With MAX_RESPONSE_LENGTH set to 128 and +the "0b" prefix stripped by extract_param(), up to 127 base64 characters +can reach the decoder. 127 characters decode to 95 bytes. For SHA-256 +(digest_size=32) this overflows client_digest by 63 bytes; for MD5 +(digest_size=16) the overflow is 79 bytes. + +The length check at line 344 fires after the write has already happened. + +The HEX branch in the same switch statement already validates the length +up front. Apply the same approach to the BASE64 branch: strip trailing +base64 padding characters, then reject any input whose data length +exceeds DIV_ROUND_UP(digest_size * 4, 3) before calling the decoder. + +Stripping trailing '=' before the comparison handles both padded and +unpadded encodings. chap_base64_decode() already returns early on '=', +so the full original string is still passed to the decoder unchanged. + +The mutual CHAP path decodes CHAP_C into initiatorchg_binhex, which is +kzalloc(CHAP_CHALLENGE_STR_LEN). extract_param() caps initiatorchg at +CHAP_CHALLENGE_STR_LEN characters, so at most CHAP_CHALLENGE_STR_LEN-1 +base64 characters reach the decoder. The maximum decoded size, +DIV_ROUND_UP((CHAP_CHALLENGE_STR_LEN-1) * 3, 4), is less than +CHAP_CHALLENGE_STR_LEN, so no overflow is possible there. A comment is +added at the call site to document this. + +Fixes: 1e5733883421 ("scsi: target: iscsi: Support base64 in CHAP") +Cc: stable@vger.kernel.org +Signed-off-by: Alexandru Hossu +Reviewed-by: David Disseldorp +Link: https://patch.msgid.link/20260521151121.808477-1-hossu.alexandru@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +CVE: CVE-2026-63886 +[ Backported to AlmaLinux 9 from linux-6.1.y commit 82454e6f21e56ea9a0a9de7d0ff7e1dfb83e34d6 (backport of mainline + 85db7391310b). Not present in linux-5.15.y; 6.1.y is the lowest stable branch + carrying it. Applied to 5.14.0-687.26.1.el9_8 with hunk offsets adjusted; the + change is otherwise identical. ] +Signed-off-by: Andrew Lukoshko + +diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c +index c8a248b..02a4c9a 100644 +--- a/drivers/target/iscsi/iscsi_target_auth.c ++++ b/drivers/target/iscsi/iscsi_target_auth.c +@@ -339,13 +339,22 @@ static int chap_server_compute_hash( + goto out; + } + break; +- case BASE64: ++ case BASE64: { ++ size_t r_len = strlen(chap_r); ++ ++ while (r_len > 0 && chap_r[r_len - 1] == '=') ++ r_len--; ++ if (r_len > DIV_ROUND_UP(chap->digest_size * 4, 3)) { ++ pr_err("Malformed CHAP_R: base64 payload too long\n"); ++ goto out; ++ } + if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) != + chap->digest_size) { + pr_err("Malformed CHAP_R: invalid BASE64\n"); + goto out; + } + break; ++ } + default: + pr_err("Could not find CHAP_R\n"); + goto out; +@@ -472,6 +481,14 @@ static int chap_server_compute_hash( + } + break; + case BASE64: ++ /* ++ * No overflow check needed: initiatorchg_binhex is ++ * CHAP_CHALLENGE_STR_LEN bytes and extract_param() caps ++ * initiatorchg at CHAP_CHALLENGE_STR_LEN characters, so ++ * the decoded output is at most DIV_ROUND_UP( ++ * (CHAP_CHALLENGE_STR_LEN - 1) * 3, 4) bytes, which is ++ * less than CHAP_CHALLENGE_STR_LEN. ++ */ + initiatorchg_len = chap_base64_decode(initiatorchg_binhex, + initiatorchg, + strlen(initiatorchg)); +-- +2.50.1 diff --git a/SOURCES/1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch b/SOURCES/1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch new file mode 100644 index 000000000..8beef89b7 --- /dev/null +++ b/SOURCES/1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch @@ -0,0 +1,207 @@ +From b19382dfc6e7dee6d3859ba44b6ca29e97a51627 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 5 Jun 2026 16:34:05 -0400 +Subject: [PATCH] scsi: target: iscsi: Bound iscsi_encode_text_output() appends + to rsp_buf + +[ Upstream commit bf33e01f88388c43e285492a63e539df6ffed64c ] + +iscsi_encode_text_output() concatenates "key=value\0" records into +login->rsp_buf, an 8192-byte kzalloc(MAX_KEY_VALUE_PAIRS) buffer +allocated in iscsit_alloc_login_setup_buffer(). The three sprintf() call +sites in this function (lines 1398, 1411, 1424 in v7.1-rc2) never check +the remaining buffer capacity: + + *length += sprintf(output_buf, "%s=%s", er->key, er->value); + *length += 1; + output_buf = textbuf + *length; + +The 8192-byte ceiling at iscsi_target_check_login_request() bounds the +*input* Login PDU payload, but a single PDU can carry up to 2048 minimal +four-byte "a=b\0" pairs, each unknown key expanding to a 16-byte +"a=NotUnderstood\0" output record via iscsi_add_notunderstood_response(). +2048 * 16 = 32 KiB of output into an 8 KiB buffer, producing a ~24 KiB +heap overrun in the kmalloc-8k slab. + +The fix introduces a static iscsi_encode_text_record() helper that uses +snprintf() with a per-call bounds check against the remaining buffer, +and threads a u32 textbuf_size parameter through +iscsi_encode_text_output(). Both call sites in +iscsi_target_handle_csg_zero() (PHASE_SECURITY) and +iscsi_target_handle_csg_one() (PHASE_OPERATIONAL) pass +MAX_KEY_VALUE_PAIRS. On overflow the encoder logs the condition, calls +iscsi_release_extra_responses() to drop queued records, and returns -1; +both caller sites now emit ISCSI_STATUS_CLS_INITIATOR_ERR / +ISCSI_LOGIN_STATUS_INIT_ERR via iscsit_tx_login_rsp() before returning, +so the initiator sees an explicit failed-login response rather than a +silent connection drop. (Prior to this patch only the PHASE_OPERATIONAL +caller did that; the PHASE_SECURITY caller is converted to the same +shape.) + +Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +CVE: CVE-2026-63887 +[ Backported to AlmaLinux 9 from linux-5.15.y commit b19382dfc6e7dee6d3859ba44b6ca29e97a51627 (backport of mainline + bf33e01f8838). Applied to 5.14.0-687.26.1.el9_8 with hunk offsets adjusted for + the el9 tree; the change is otherwise identical. ] +Signed-off-by: Andrew Lukoshko + +diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c +index 108e253..a1fb869 100644 +--- a/drivers/target/iscsi/iscsi_target_nego.c ++++ b/drivers/target/iscsi/iscsi_target_nego.c +@@ -899,10 +899,14 @@ static int iscsi_target_handle_csg_zero( + SENDER_TARGET, + login->rsp_buf, + &login->rsp_length, ++ MAX_KEY_VALUE_PAIRS, + conn->param_list, + conn->tpg->tpg_attrib.login_keys_workaround); +- if (ret < 0) ++ if (ret < 0) { ++ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, ++ ISCSI_LOGIN_STATUS_INIT_ERR); + return -1; ++ } + + if (!iscsi_check_negotiated_keys(conn->param_list)) { + bool auth_required = iscsi_conn_auth_required(conn); +@@ -986,6 +990,7 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo + SENDER_TARGET, + login->rsp_buf, + &login->rsp_length, ++ MAX_KEY_VALUE_PAIRS, + conn->param_list, + conn->tpg->tpg_attrib.login_keys_workaround); + if (ret < 0) { +diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c +index 5b90c22..5e15c2e 100644 +--- a/drivers/target/iscsi/iscsi_target_parameters.c ++++ b/drivers/target/iscsi/iscsi_target_parameters.c +@@ -1419,19 +1419,42 @@ free_buffer: + return -1; + } + ++/* ++ * Append "key=value" plus a trailing NUL into @textbuf at *@length. ++ * Returns 0 on success and advances *@length, or -EMSGSIZE if the ++ * record (including the NUL) would not fit in the remaining buffer. ++ */ ++static int iscsi_encode_text_record(char *textbuf, u32 *length, ++ u32 textbuf_size, ++ const char *key, const char *value) ++{ ++ int n; ++ u32 avail; ++ ++ if (*length >= textbuf_size) ++ return -EMSGSIZE; ++ ++ avail = textbuf_size - *length; ++ n = snprintf(textbuf + *length, avail, "%s=%s", key, value); ++ if (n < 0 || (u32)n + 1 > avail) ++ return -EMSGSIZE; ++ ++ *length += n + 1; ++ return 0; ++} ++ + int iscsi_encode_text_output( + u8 phase, + u8 sender, + char *textbuf, + u32 *length, ++ u32 textbuf_size, + struct iscsi_param_list *param_list, + bool keys_workaround) + { +- char *output_buf = NULL; + struct iscsi_extra_response *er; + struct iscsi_param *param; +- +- output_buf = textbuf + *length; ++ int ret; + + if (iscsi_enforce_integrity_rules(phase, param_list) < 0) + return -1; +@@ -1443,10 +1466,12 @@ int iscsi_encode_text_output( + !IS_PSTATE_RESPONSE_SENT(param) && + !IS_PSTATE_REPLY_OPTIONAL(param) && + (param->phase & phase)) { +- *length += sprintf(output_buf, "%s=%s", +- param->name, param->value); +- *length += 1; +- output_buf = textbuf + *length; ++ ret = iscsi_encode_text_record(textbuf, length, ++ textbuf_size, ++ param->name, ++ param->value); ++ if (ret < 0) ++ goto err_overflow; + SET_PSTATE_RESPONSE_SENT(param); + pr_debug("Sending key: %s=%s\n", + param->name, param->value); +@@ -1456,10 +1481,12 @@ int iscsi_encode_text_output( + !IS_PSTATE_ACCEPTOR(param) && + !IS_PSTATE_PROPOSER(param) && + (param->phase & phase)) { +- *length += sprintf(output_buf, "%s=%s", +- param->name, param->value); +- *length += 1; +- output_buf = textbuf + *length; ++ ret = iscsi_encode_text_record(textbuf, length, ++ textbuf_size, ++ param->name, ++ param->value); ++ if (ret < 0) ++ goto err_overflow; + SET_PSTATE_PROPOSER(param); + iscsi_check_proposer_for_optional_reply(param, + keys_workaround); +@@ -1469,14 +1496,21 @@ int iscsi_encode_text_output( + } + + list_for_each_entry(er, ¶m_list->extra_response_list, er_list) { +- *length += sprintf(output_buf, "%s=%s", er->key, er->value); +- *length += 1; +- output_buf = textbuf + *length; ++ ret = iscsi_encode_text_record(textbuf, length, textbuf_size, ++ er->key, er->value); ++ if (ret < 0) ++ goto err_overflow; + pr_debug("Sending key: %s=%s\n", er->key, er->value); + } + iscsi_release_extra_responses(param_list); + + return 0; ++ ++err_overflow: ++ pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n", ++ textbuf_size); ++ iscsi_release_extra_responses(param_list); ++ return -1; + } + + int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list) +diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h +index 00fbbeb..d6cbe5d 100644 +--- a/drivers/target/iscsi/iscsi_target_parameters.h ++++ b/drivers/target/iscsi/iscsi_target_parameters.h +@@ -46,7 +46,7 @@ extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_ + extern int iscsi_extract_key_value(char *, char **, char **); + extern int iscsi_update_param_value(struct iscsi_param *, char *); + extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsit_conn *); +-extern int iscsi_encode_text_output(u8, u8, char *, u32 *, ++extern int iscsi_encode_text_output(u8, u8, char *, u32 *, u32, + struct iscsi_param_list *, bool); + extern int iscsi_check_negotiated_keys(struct iscsi_param_list *); + extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *, +-- +2.50.1 diff --git a/SOURCES/1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch b/SOURCES/1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch new file mode 100644 index 000000000..7948ffb20 --- /dev/null +++ b/SOURCES/1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch @@ -0,0 +1,126 @@ +From badf178b76b0690851df00f4ca9cf2eb8eb0f963 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sat, 6 Jun 2026 08:49:28 -0400 +Subject: [PATCH] scsi: target: iscsi: Fix CRC overread and double-free in + iscsit_handle_text_cmd() + +[ Upstream commit 778c2ab142c625a8a8afa570e0f9b7873f445d99 ] + +Two latent bugs in the Text-phase handler, both present since the +original LIO integration in commit e48354ce078c ("iscsi-target: Add +iSCSI fabric support for target v4.1"): + +1) DataDigest CRC buffer overread (4 bytes past text_in). + + text_in is kzalloc()'d at ALIGN(payload_length, 4). rx_size is then + incremented by ISCSI_CRC_LEN to make room for the received DataDigest + in the iovec, but the same (now-bumped) rx_size is passed as the + buffer length to iscsit_crc_buf(): + + if (conn->conn_ops->DataDigest) { + ... + rx_size += ISCSI_CRC_LEN; + } + ... + if (conn->conn_ops->DataDigest) { + data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL); + + iscsit_crc_buf() walks rx_size bytes of text_in with crc32c(), so + when DataDigest is negotiated it reads 4 bytes past the end of the + text_in allocation. KASAN reproduces this directly on the unpatched + mainline tree as slab-out-of-bounds in crc32c() called from the Text + PDU path. The OOB bytes feed crc32c() and are then compared against + the initiator-supplied checksum, so the value does not flow back to + the attacker, but the kernel does read past the buffer on every Text + PDU with DataDigest=CRC32C. + + Fix by passing the actual padded payload length + (ALIGN(payload_length, 4)) that was used for the kzalloc(). + +2) Stale cmd->text_in_ptr re-free (double-free) on ERL>0 bad DataDigest + drop. + + On DataDigest mismatch with ErrorRecoveryLevel > 0 the handler + silently drops the PDU and lets the initiator plug the CmdSN gap: + + kfree(text_in); + return 0; + + cmd->text_in_ptr still points at the freed buffer. The next Text + Request on the same ITT re-enters iscsit_setup_text_cmd(), which + unconditionally does + + kfree(cmd->text_in_ptr); + cmd->text_in_ptr = NULL; + + freeing the same pointer a second time. Session teardown via + iscsit_release_cmd() has the same shape and hits the same double-free + if the connection is dropped before a second Text Request arrives. + + On an unmodified mainline tree the bug-1 CRC overread fires first on + the initial valid Text Request and perturbs the subsequent state, so + #4 was isolated by building a kernel with only the bug-1 hunk of this + patch applied plus temporary printk() observability around the three + relevant kfree() sites. The observability prints are not part of + this patch. On that build, a three-PDU Text Request sequence after + login produces two back-to-back splats: + + BUG: KASAN: double-free in iscsit_setup_text_cmd+0x?? + BUG: KASAN: double-free in iscsit_release_cmd+0x?? + + showing the same pointer freed in the ERL>0 drop path and again in + iscsit_setup_text_cmd() (next Text Request on the same ITT) and once + more in iscsit_release_cmd() (session teardown). On distro kernels + with CONFIG_SLAB_FREELIST_HARDENED=y (default) the double-free + becomes a remote kernel BUG(); on non-hardened kernels it corrupts + the slab freelist. + + Fix by clearing cmd->text_in_ptr after the kfree() in the ERL>0 drop + path. With both hunks applied #4 is directly observable on the stock + tree without observability printks; fixing bug-1 alone would mask #4 + less, not more, so the hunks are submitted together. + +Both fixes are one-liners. The Text PDU state machine is unchanged and +the wire protocol is unaffected. + +Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +CVE: CVE-2026-63888 +[ Backported to AlmaLinux 9 from linux-5.15.y commit badf178b76b0690851df00f4ca9cf2eb8eb0f963 (backport of mainline + 778c2ab142c6). Applied to 5.14.0-687.26.1.el9_8 with hunk offsets adjusted; the + change is otherwise identical. ] +Signed-off-by: Andrew Lukoshko + +diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c +index 8afe335..796aeda 100644 +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -2329,8 +2329,9 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd, + + if (conn->conn_ops->DataDigest) { + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, +- text_in, rx_size, 0, NULL, +- &data_crc); ++ text_in, ++ ALIGN(payload_length, 4), ++ 0, NULL, &data_crc); + + if (checksum != data_crc) { + pr_err("Text data CRC32C DataDigest" +@@ -2350,6 +2351,7 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd, + " Command CmdSN: 0x%08x due to" + " DataCRC error.\n", hdr->cmdsn); + kfree(text_in); ++ cmd->text_in_ptr = NULL; + return 0; + } + } else { +-- +2.50.1 diff --git a/SOURCES/1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch b/SOURCES/1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch new file mode 100644 index 000000000..1f575f92f --- /dev/null +++ b/SOURCES/1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch @@ -0,0 +1,47 @@ +From 2f3661eb2446e1ef593da45e01a3b21a906768ec Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 22 May 2026 16:19:50 +0200 +Subject: [PATCH] USB: serial: mxuport: fix memory corruption with small + endpoint + +commit 4085f0dbb1ce2251c9a5938d693de6593f0ab2bd upstream. + +Make sure that the bulk-out endpoint max packet size is at least eight +bytes to avoid user-controlled slab corruption should a malicious device +report a smaller size. + +Fixes: ee467a1f2066 ("USB: serial: add Moxa UPORT 12XX/14XX/16XX driver") +Cc: stable@vger.kernel.org # 3.14 +Cc: Andrew Lunn +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +CVE-2026-63899 + +Backported from linux-5.15.y commit 2f3661eb2446e1ef593da45e01a3b21a906768ec. +drivers/usb/serial/mxuport.c mxuport_calc_num_ports() carries the vulnerable +pre-image verbatim; applies cleanly, zero-fuzz. + +diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c +index eb45a9b0005c..b4270beb6fe0 100644 +--- a/drivers/usb/serial/mxuport.c ++++ b/drivers/usb/serial/mxuport.c +@@ -962,6 +962,14 @@ static int mxuport_calc_num_ports(struct usb_serial *serial, + */ + BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < 16); + ++ /* ++ * The bulk-out buffers must be large enough for the four-byte header ++ * (and following data), but assume anything smaller than eight bytes ++ * is broken. ++ */ ++ if (usb_endpoint_maxp(epds->bulk_out[0]) < 8) ++ return -EINVAL; ++ + for (i = 1; i < num_ports; ++i) + epds->bulk_out[i] = epds->bulk_out[0]; + +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch b/SOURCES/1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch new file mode 100644 index 000000000..01d6bb59b --- /dev/null +++ b/SOURCES/1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch @@ -0,0 +1,80 @@ +From f5c68875e25f331e497ddfbe81e2d8163a87f136 Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 21 May 2026 21:05:54 +0800 +Subject: [PATCH] ip6: vti: Use ip6_tnl.net in vti6_changelink(). + +commit 11b326fb0a374f4654f9be22d0f0f7abd9f7d3fe upstream. + +ip netns add ns1 +ip netns add ns2 +ip -n ns1 link add vti6_test type vti6 remote ::1 local ::2 key 7 +ip -n ns1 link set vti6_test netns ns2 +ip -n ns2 link set vti6_test type vti6 remote ::3 local ::4 key 9 +ip netns del ns2 +ip netns del ns1 +[ 132.495484] ------------[ cut here ]------------ +[ 132.497609] kernel BUG at net/core/dev.c:12376! + +Commit 61220ab34948 ("vti6: Enable namespace changing") dropped +NETIF_F_NETNS_LOCAL from vti6 devices. A vti6 tunnel can then +move through IFLA_NET_NS_FD. After the move dev_net(dev) points +at the new netns while t->net stays at the creation netns. + +vti6_changelink() and vti6_update() still use dev_net(dev) and +dev_net(t->dev). They unlink from one per netns hash and relink +into another. The creation netns is left with a stale entry. +cleanup_net() of that netns later walks freed memory. + +Reachable from an unprivileged user namespace (unshare --user +--map-root-user --net). Cross tenant scope on container hosts. + +Fixes: 61220ab34948 ("vti6: Enable namespace changing") +Reported-by: Maoyi Xie +Reviewed-by: Eric Dumazet +Cc: stable@vger.kernel.org # v5.15+ +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260521130555.3421684-2-maoyixie.tju@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +CVE: CVE-2026-63917 +[ Backported to AlmaLinux 9 from linux-5.15.y commit f5c68875e25f331e497ddfbe81e2d8163a87f136 (backport of mainline + 11b326fb0a37). Applied to 5.14.0-687.26.1.el9_8 with hunk offsets adjusted; the + change is otherwise identical. ] +Signed-off-by: Andrew Lukoshko + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index f829c29..6ee727d 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -729,10 +729,11 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p, + static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p, + bool keep_mtu) + { +- struct net *net = dev_net(t->dev); +- struct vti6_net *ip6n = net_generic(net, vti6_net_id); ++ struct net *net = t->net; ++ struct vti6_net *ip6n; + int err; + ++ ip6n = net_generic(net, vti6_net_id); + vti6_tnl_unlink(ip6n, t); + synchronize_net(); + err = vti6_tnl_change(t, p, keep_mtu); +@@ -1039,11 +1040,12 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) + { +- struct ip6_tnl *t; ++ struct ip6_tnl *t = netdev_priv(dev); ++ struct net *net = t->net; + struct __ip6_tnl_parm p; +- struct net *net = dev_net(dev); +- struct vti6_net *ip6n = net_generic(net, vti6_net_id); ++ struct vti6_net *ip6n; + ++ ip6n = net_generic(net, vti6_net_id); + if (dev == ip6n->fb_tnl_dev) + return -EINVAL; + +-- +2.50.1 diff --git a/SOURCES/1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch b/SOURCES/1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch new file mode 100644 index 000000000..843a56f3d --- /dev/null +++ b/SOURCES/1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch @@ -0,0 +1,42 @@ +From 645b99b1a185c91a79bdac4c5de0f91b212d64f0 Mon Sep 17 00:00:00 2001 +From: Justin Iurman +Date: Fri, 22 May 2026 13:20:13 +0200 +Subject: [PATCH] ipv6: exthdrs: refresh nh pointer after ipv6_hop_jumbo() + +commit d47548a36639095939f4747d4c43f2271366f565 upstream. + +ipv6_hop_jumbo() calls pskb_trim_rcsum(), which can change skb pointers. +Let's recompute nh pointer to make sure any change won't mess things up. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260522112013.12342-1-justin.iurman@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman + +[ CVE-2026-63924: backported to AlmaLinux 9 (kernel-5.14.0-687.26.1.el9_8) + from linux-5.15.y commit 645b99b1a185c91a79bdac4c5de0f91b212d64f0. + Adapted: a9 predates commit 51b8f812e5b3 ("ipv6: exthdrs: get rid of + indirect calls in ip6_parse_tlv()", v5.15) and still dispatches all TLV + handlers through a single indirect curr->func(skb, off) call rather than + a per-option switch. The nh refresh is therefore guarded on + curr->type == IPV6_TLV_JUMBO so it fires only after ipv6_hop_jumbo(), + matching upstream which refreshes nh only after that handler. + Applies before the CVE-2026-63922 (HAO) refresh. ] + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -181,6 +181,8 @@ + func(). */ + if (curr->func(skb, off) == false) + return false; ++ if (curr->type == IPV6_TLV_JUMBO) ++ nh = skb_network_header(skb); + break; + } + } +-- +2.50.1 (Apple Git-155) diff --git a/SOURCES/1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch b/SOURCES/1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch new file mode 100644 index 000000000..115dddf15 --- /dev/null +++ b/SOURCES/1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch @@ -0,0 +1,56 @@ +From f8aabed3ff3e986920cf02a2a2785e08e586b234 Mon Sep 17 00:00:00 2001 +From: Zhengchuan Liang +Date: Fri, 22 May 2026 17:42:26 +0800 +Subject: [PATCH] ipv6: exthdrs: refresh nh after handling HAO option + +commit f7b52afe3592eae66e160586b45a3f2242972c63 upstream. + +ip6_parse_tlv() caches skb_network_header(skb) in nh while walking +IPv6 TLVs. + +ipv6_dest_hao() may call pskb_expand_head() for a cloned skb, which can +move the skb head and invalidate the cached network header pointer. +Refresh nh after ipv6_dest_hao() returns so any trailing padding or TLVs +are parsed from the current skb head. + +This matches the existing pattern used in ip6_parse_tlv() after helpers +that can modify skb header storage. + +Fixes: a831f5bbc89a ("[IPV6] MIP6: Add inbound interface of home address option.") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Xin Liu +Co-developed-by: Luxing Yin +Signed-off-by: Luxing Yin +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/7aba1debc2196189172499e5769802b026f8caf8.1779247873.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman + +[ CVE-2026-63922: backported to AlmaLinux 9 (kernel-5.14.0-687.26.1.el9_8) + from linux-5.15.y commit f8aabed3ff3e986920cf02a2a2785e08e586b234. + Adapted: a9 predates commit 51b8f812e5b3 ("ipv6: exthdrs: get rid of + indirect calls in ip6_parse_tlv()", v5.15) and still dispatches all TLV + handlers through a single indirect curr->func(skb, off) call rather than + a per-option switch. The nh refresh is therefore guarded on + curr->type == IPV6_TLV_HAO so it fires only after ipv6_dest_hao(), + matching upstream which refreshes nh only after that handler. + Applies after the CVE-2026-63924 (JUMBO) refresh. ] + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -182,6 +182,8 @@ + if (curr->func(skb, off) == false) + return false; + if (curr->type == IPV6_TLV_JUMBO) ++ nh = skb_network_header(skb); ++ if (curr->type == IPV6_TLV_HAO) + nh = skb_network_header(skb); + break; + } +-- +2.50.1 (Apple Git-155) diff --git a/SOURCES/1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch b/SOURCES/1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch new file mode 100644 index 000000000..b5a072c14 --- /dev/null +++ b/SOURCES/1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch @@ -0,0 +1,105 @@ +From 5867d7e202e09f037cefe77f7af4413c7c0fa088 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Fri, 1 May 2026 13:22:31 -0700 +Subject: [PATCH] KVM: SEV: Compute the correct max length of the in-GHCB + scratch area + +commit 5867d7e202e09f037cefe77f7af4413c7c0fa088 upstream. + +When setting the length of the GHCB scratch area, and the area is in the +GHCB shared buffer, set the effective length of the scratch area to the max +possible size given the start of the guest-provided pointer, and the end of +the shared buffer. + +The code was "fine" when first introduced, as KVM doesn't consult the +length of the buffer when emulating MMIO, because the passed in @len always +specifies the *max* size required. But for PSC requests, the incoming @len +is just the minimum length (to process the header), and KVM needs to know +the full size of the scratch area to avoid buffer overflows (spoiler alert). + +Opportunistically rename @len => @min_len to better reflect its role. + +Fixes: 9b54e248d264 ("KVM: SEV: Add support to handle Page State Change VMGEXIT") +Cc: stable@vger.kernel.org +Reviewed-by: Tom Lendacky +Reviewed-by: Michael Roth +Signed-off-by: Sean Christopherson +Message-ID: <20260501202250.2115252-7-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +[ CVE-2026-63939: backported to AlmaLinux 9 (kernel-5.14.0-687.26.1.el9_8) + from linux-6.12.y commit 6ca9400d36005ffdca25f80186bea781c7e1dc4c. + Adapted the in-GHCB hunk: a9 predates the "GHCB v2 requires the scratch + area to be within the GHCB" ghcb_version>=2 guard, so the new + ghcb_sa_len assignment was rebased onto a9's surrounding context. + Applies zero-fuzz after the CVE-2026-63794 sev_dbg_crypt fix. ] + +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -3448,7 +3448,7 @@ + } + + #define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE) +-static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) ++static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len) + { + struct vmcb_control_area *control = &svm->vmcb->control; + u64 ghcb_scratch_beg, ghcb_scratch_end; +@@ -3461,10 +3461,10 @@ + goto e_scratch; + } + +- scratch_gpa_end = scratch_gpa_beg + len; ++ scratch_gpa_end = scratch_gpa_beg + min_len; + if (scratch_gpa_end < scratch_gpa_beg) { + pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n", +- len, scratch_gpa_beg); ++ min_len, scratch_gpa_beg); + goto e_scratch; + } + +@@ -3488,21 +3488,23 @@ + + scratch_va = (void *)svm->sev_es.ghcb; + scratch_va += (scratch_gpa_beg - control->ghcb_gpa); ++ ++ svm->sev_es.ghcb_sa_len = ghcb_scratch_end - scratch_gpa_beg; + } else { + /* + * The guest memory must be read into a kernel buffer, so + * limit the size + */ +- if (len > GHCB_SCRATCH_AREA_LIMIT) { ++ if (min_len > GHCB_SCRATCH_AREA_LIMIT) { + pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n", +- len, GHCB_SCRATCH_AREA_LIMIT); ++ min_len, GHCB_SCRATCH_AREA_LIMIT); + goto e_scratch; + } +- scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT); ++ scratch_va = kvzalloc(min_len, GFP_KERNEL_ACCOUNT); + if (!scratch_va) + return -ENOMEM; + +- if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) { ++ if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, min_len)) { + /* Unable to copy scratch area from guest */ + pr_err("vmgexit: kvm_read_guest for scratch area failed\n"); + +@@ -3518,11 +3520,10 @@ + */ + svm->sev_es.ghcb_sa_sync = sync; + svm->sev_es.ghcb_sa_free = true; ++ svm->sev_es.ghcb_sa_len = min_len; + } + + svm->sev_es.ghcb_sa = scratch_va; +- svm->sev_es.ghcb_sa_len = len; +- + return 0; + + e_scratch: +-- +2.50.1 (Apple Git-155) diff --git a/SOURCES/1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch b/SOURCES/1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch new file mode 100644 index 000000000..37a27ef79 --- /dev/null +++ b/SOURCES/1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch @@ -0,0 +1,48 @@ +From ad3d1628a46134276546d7a12fedf04be9979158 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 4 Jun 2026 10:36:36 +0200 +Subject: [PATCH] USB: serial: cypress_m8: fix memory corruption with small + endpoint + +commit e1a9d791fd66ab2431b9e6f6f835823809869047 upstream. + +Make sure that the interrupt-out endpoint max packet size is at least +eight bytes to avoid user-controlled slab corruption or NULL-pointer +dereference should a malicious device report a smaller size. + +Fixes: 3416eaa1f8f8 ("USB: cypress_m8: Packet format is separate from characteristic size") +Cc: stable@vger.kernel.org # 2.6.26 +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +[ johan: adjust context for 6.18 ] +Signed-off-by: Johan Hovold +Signed-off-by: Sasha Levin + +CVE-2026-63956 + +Backported from linux-5.15.y commit ad3d1628a46134276546d7a12fedf04be9979158. +drivers/usb/serial/cypress_m8.c cypress_generic_port_probe() carries the +vulnerable pre-image verbatim; applies cleanly, zero-fuzz. + +diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c +index 115e2df92132..2ca7e7af714f 100644 +--- a/drivers/usb/serial/cypress_m8.c ++++ b/drivers/usb/serial/cypress_m8.c +@@ -447,6 +447,14 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) + return -ENODEV; + } + ++ /* ++ * The buffer must be large enough for the one or two-byte header (and ++ * following data), but assume anything smaller than eight bytes is ++ * broken. ++ */ ++ if (port->interrupt_out_size < 8) ++ return -EINVAL; ++ + priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1117-tunnels-load-network-headers-after-skb-cow-in.patch b/SOURCES/1117-tunnels-load-network-headers-after-skb-cow-in.patch new file mode 100644 index 000000000..f5737eb4d --- /dev/null +++ b/SOURCES/1117-tunnels-load-network-headers-after-skb-cow-in.patch @@ -0,0 +1,88 @@ +From 7254aef4d1a7e18e887af9010e2f2dc34806789b Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: [PATCH] tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin + +CVE-2026-63994 + +Backported from linux-5.15.y commit 7254aef4d1a7e18e887af9010e2f2dc34806789b. +net/ipv4/ip_tunnel_core.c iptunnel_pmtud_build_icmp[v6]() carry the vulnerable +pre-image verbatim; applies cleanly, zero-fuzz. + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 3737188ba4e1..4d80bbcd15d5 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -208,7 +208,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -218,7 +217,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -290,7 +289,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -305,7 +304,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -316,6 +314,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1118-blk-mq-pop-cached-request-if-it-is-usable.patch b/SOURCES/1118-blk-mq-pop-cached-request-if-it-is-usable.patch new file mode 100644 index 000000000..41eecf46b --- /dev/null +++ b/SOURCES/1118-blk-mq-pop-cached-request-if-it-is-usable.patch @@ -0,0 +1,117 @@ +From dc278e9bf2b9513a763353e6b9cc21e0f532954e Mon Sep 17 00:00:00 2001 +From: Keith Busch +Date: Thu, 21 May 2026 12:02:53 -0700 +Subject: [PATCH] blk-mq: pop cached request if it is usable + +When submitting a bio to blk-mq, if the task should sleep after peeking +a cached request, but before it pops it, the plug flushes and calls +blk_mq_free_plug_rqs, freeing the cached_rqs. This creates a +use-after-free bug. Fix this by popping the cached request before any +possible blocking calls if it is suitable for use. + +Popping this request first holds a queue reference, so avoid any +serialization races with queue freezes and can safely proceed with +dispatching that request to the driver. This potentially increases a +timing window from when a driver wants to freeze its queue to when +requests stop being dispatched. That scenario is off the fast path +though, and drivers need to appropriately handle requests during a +freeze request anyway. + +The downside is the popped element needs to be individually freed when +we performed a bio plug merge. The cached request would have had to be +freed later anyway, but this patch does it inline with building the plug +list instead of after flushing it. + +Fixes: b0077e269f6c1 ("blk-mq: make sure active queue usage is held for bio_integrity_prep()") +Fixes: 7b4f36cd22a65 ("block: ensure we hold a queue reference when using queue limits") +Signed-off-by: Keith Busch +Link: https://patch.msgid.link/20260521190253.242065-1-kbusch@meta.com +Signed-off-by: Jens Axboe + +CVE-2026-64017 + +Backported from mainline commit dc278e9bf2b9513a763353e6b9cc21e0f532954e. +block/blk-mq.c blk_mq_peek_cached_request()/blk_mq_use_cached_rq() carry the +vulnerable pre-image verbatim; applies cleanly, zero-fuzz. + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index d0c37daf568f..28c2d931e75e 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3077,7 +3077,7 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q, + /* + * Check if there is a suitable cached request and return it. + */ +-static struct request *blk_mq_peek_cached_request(struct blk_plug *plug, ++static struct request *blk_mq_get_cached_request(struct blk_plug *plug, + struct request_queue *q, blk_opf_t opf) + { + enum hctx_type type = blk_mq_get_hctx_type(opf); +@@ -3093,27 +3093,10 @@ static struct request *blk_mq_peek_cached_request(struct blk_plug *plug, + return NULL; + if (op_is_flush(rq->cmd_flags) != op_is_flush(opf)) + return NULL; ++ rq_list_pop(&plug->cached_rqs); + return rq; + } + +-static void blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug, +- struct bio *bio) +-{ +- if (rq_list_pop(&plug->cached_rqs) != rq) +- WARN_ON_ONCE(1); +- +- /* +- * If any qos ->throttle() end up blocking, we will have flushed the +- * plug and hence killed the cached_rq list as well. Pop this entry +- * before we throttle. +- */ +- rq_qos_throttle(rq->q, bio); +- +- blk_mq_rq_time_init(rq, blk_time_get_ns()); +- rq->cmd_flags = bio->bi_opf; +- INIT_LIST_HEAD(&rq->queuelist); +-} +- + static bool bio_unaligned(const struct bio *bio, struct request_queue *q) + { + unsigned int bs_mask = queue_logical_block_size(q) - 1; +@@ -3152,7 +3135,7 @@ void blk_mq_submit_bio(struct bio *bio) + /* + * If the plug has a cached request for this queue, try to use it. + */ +- rq = blk_mq_peek_cached_request(plug, q, bio->bi_opf); ++ rq = blk_mq_get_cached_request(plug, q, bio->bi_opf); + + /* + * A BIO that was released from a zone write plug has already been +@@ -3211,7 +3194,10 @@ void blk_mq_submit_bio(struct bio *bio) + + new_request: + if (rq) { +- blk_mq_use_cached_rq(rq, plug, bio); ++ rq_qos_throttle(rq->q, bio); ++ blk_mq_rq_time_init(rq, blk_time_get_ns()); ++ rq->cmd_flags = bio->bi_opf; ++ INIT_LIST_HEAD(&rq->queuelist); + } else { + rq = blk_mq_get_new_requests(q, plug, bio); + if (unlikely(!rq)) { +@@ -3257,12 +3243,10 @@ void blk_mq_submit_bio(struct bio *bio) + return; + + queue_exit: +- /* +- * Don't drop the queue reference if we were trying to use a cached +- * request and thus didn't acquire one. +- */ + if (!rq) + blk_queue_exit(q); ++ else ++ blk_mq_free_request(rq); + } + + #ifdef CONFIG_BLK_MQ_STACKING +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch b/SOURCES/1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch new file mode 100644 index 000000000..b047882bd --- /dev/null +++ b/SOURCES/1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch @@ -0,0 +1,409 @@ +From a05bf6d9e621fa71e89ccebe3047ba45218d7b38 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Fri, 29 May 2026 19:20:55 -0400 +Subject: [PATCH] rxrpc: Fix DATA decrypt vs splice() by copying data to buffer + in recvmsg + +commit d2bc90cf6c75cb96d2ce549be6c35efa3099d25b upstream. + +This improves the fix for CVE-2026-43500. + +Fix the pagecache corruption from in-place decryption of a DATA packet +transmitted locally by splice() by getting rid of the packet sharing in the +I/O thread and unconditionally extracting the packet content into a bounce +buffer in which the buffer is decrypted. recvmsg() (or the kernel +equivalent) then copies the data from the bounce buffer to the destination +buffer. The sk_buff then remains unmodified. + +This has an additional advantage in that the packet is then arranged in the +buffer with the correct alignment required for the crypto algorithms to +process directly. The performance of the crypto does seem to be a little +faster and, surprisingly, the unencrypted performance doesn't seem to +change much - possibly due to removing complexity from the I/O thread. + +Yet another advantage is that the I/O thread doesn't have to copy packets +which would slow down packet distribution, ACK generation, etc.. + +The buffer belongs to the call and is allocated initially at 2K, +sufficiently large to hold a whole jumbo subpacket, but the buffer will be +increased in size if needed. However, to take this work, MSG_PEEK may +cause a later packet to be decrypted into the buffer, in which case the +earlier one will need re-decrypting for a subsequent recvmsg(). + +Note that rx_pkt_offset may legitimately see 0 as a valid offset now, so +switch to using USHRT_MAX to indicate an invalid offset. + +Note also that I would generally prefer to replace the buffers of the +current sk_buff with a new kmalloc'd buffer of the right size, ditching the +old data and frags as this makes the handling of MSG_PEEK easier and +removes the re-decryption issue, but this looks like quite a complicated +thing to achieve. skb_morph() looks half way to what I want, but I don't +want to have to allocate a new sk_buff. + +Fixes: d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()") +Reported-by: Hyunwoo Kim +Closes: https://lore.kernel.org/r/afKV2zGR6rrelPC7@v4bel/ +Signed-off-by: David Howells +cc: Simon Horman +cc: Jiayuan Chen +cc: linux-afs@lists.infradead.org +Reviewed-by: Jeffrey Altman +Tested-by: Marc Dionne +Link: https://patch.msgid.link/20260515230516.2718212-3-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 8bfab4b6ffc2 ("rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman + +[ CVE-2026-64026: backported to AlmaLinux 9 (kernel-5.14.0-687.26.1.el9_8) from + linux-6.6.y commit a05bf6d9e621fa71e89ccebe3047ba45218d7b38. Adaptations: + the net/rxrpc/call_event.c hunk (removal of the skb_copy()/unshare block in + rxrpc_input_call_event) is already present in a9 via the ktime timer rework, + so it is dropped. In net/rxrpc/rxkad.c, a9's rxkad_verify_packet_1/_2 had + already dropped the round_down(len, 8) alignment step, the + crypto_skcipher_decrypt() return-value checks and the + rxkad_abort_2_crypto_unaligned abort (which is not defined in a9); those + pre-existing divergences are preserved (the decrypt is simply redirected + into the new per-call bounce buffer) and the now-unused ret/nsg locals are + removed. Remaining hunks apply with line-offset only. ] + +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 077e5df..9559093 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -203,8 +203,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 */ +@@ -689,6 +687,11 @@ struct rxrpc_call { + /* Received data tracking */ + struct sk_buff_head recvmsg_queue; /* Queue of packets ready for recvmsg() */ + 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_object.c b/net/rxrpc/call_object.c +index 3855e77..b46fa99 100644 +--- a/net/rxrpc/call_object.c ++++ b/net/rxrpc/call_object.c +@@ -155,6 +155,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, + spin_lock_init(&call->tx_lock); + refcount_set(&call->ref, 1); + call->debug_id = debug_id; ++ call->rx_pkt_offset = USHRT_MAX; + call->tx_total_len = -1; + call->next_rx_timo = 20 * HZ; + call->next_req_timo = 1 * HZ; +@@ -537,6 +538,7 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call) + { + rxrpc_purge_queue(&call->recvmsg_queue); + rxrpc_purge_queue(&call->rx_oos_queue); ++ kfree(call->rx_dec_buffer); + } + + /* +diff --git a/net/rxrpc/insecure.c b/net/rxrpc/insecure.c +index f270106..e1a9a4e 100644 +--- a/net/rxrpc/insecure.c ++++ b/net/rxrpc/insecure.c +@@ -29,9 +29,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; + } + +diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c +index a482f88..13cd795 100644 +--- a/net/rxrpc/recvmsg.c ++++ b/net/rxrpc/recvmsg.c +@@ -143,15 +143,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->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 = 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; + +- if (sp->flags & RXRPC_RX_VERIFIED) +- return 0; +- return call->security->verify_packet(call, skb); ++ 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; + } + + /* +@@ -202,17 +239,22 @@ 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) { + kdebug("verify = %d", ret2); + 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); +@@ -224,10 +266,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; + } + +@@ -248,7 +290,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); +diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c +index f1a6827..20cada2 100644 +--- a/net/rxrpc/rxkad.c ++++ b/net/rxrpc/rxkad.c +@@ -409,27 +409,24 @@ 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)); +@@ -441,13 +438,11 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, + skcipher_request_zero(req); + + /* 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; +@@ -456,10 +451,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; +@@ -473,40 +468,24 @@ 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; + +- _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. ++ /* 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_array(nsg, sizeof(*sg), 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]; +@@ -514,20 +493,16 @@ 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); + crypto_skcipher_decrypt(req); + skcipher_request_zero(req); +- if (sg != _sg) +- kfree(sg); + + /* 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; +@@ -537,17 +512,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) + { +-- +2.50.1 (Apple Git-155) diff --git a/SOURCES/1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch b/SOURCES/1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch new file mode 100644 index 000000000..58b13323e --- /dev/null +++ b/SOURCES/1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch @@ -0,0 +1,53 @@ +From f718506edd2d9c6a308ded9d13c632bf7b7d5a2c Mon Sep 17 00:00:00 2001 +From: Alexandru Hossu +Date: Fri, 15 May 2026 12:29:08 +0200 +Subject: [PATCH] wifi: mac80211: bounds-check link_id in ieee80211_ml_epcs + +IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID is 0x000f, so link_id extracted +from a PRIO_ACCESS ML element PER_STA_PROFILE subelement can be 0..15. +sdata->link[] has IEEE80211_MLD_MAX_NUM_LINKS (15) entries (indices 0..14), +making index 15 out-of-bounds. + +A connected WiFi 7 AP can trigger this by sending an EPCS Enable Response +action frame with a PER_STA_PROFILE subelement where link_id = 15. The +unsolicited-notification path (dialog_token = 0) is reachable any time +EPCS is already enabled, without any prior client request. + +sdata->link[15] reads into the first word of sdata->activate_links_work +(a wiphy_work whose embedded list_head is non-NULL after INIT_LIST_HEAD), +so the NULL check on the result does not catch the invalid access. The +garbage pointer is then passed to ieee80211_sta_wmm_params(), which +dereferences link->sdata and crashes the kernel. + +The same class of bug was fixed for ieee80211_ml_reconfiguration() by +commit 162d331d833d ("wifi: mac80211: bounds-check link_id in +ieee80211_ml_reconfiguration"). + +Fixes: de86c5f60839 ("wifi: mac80211: Add support for EPCS configuration") +Signed-off-by: Alexandru Hossu +Link: https://patch.msgid.link/20260515102908.1653088-1-hossu.alexandru@gmail.com +Signed-off-by: Johannes Berg + +CVE-2026-64030 + +Backported from mainline commit f718506edd2d9c6a308ded9d13c632bf7b7d5a2c. +net/mac80211/mlme.c ieee80211_ml_epcs() carries the vulnerable pre-image +verbatim (unchecked link_id); applies cleanly, zero-fuzz. + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 0a0f27836d57..ca1d29daf019 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -11232,6 +11232,9 @@ static void ieee80211_ml_epcs(struct ieee80211_sub_if_data *sdata, + control = get_unaligned_le16(pos); + link_id = control & IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID; + ++ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) ++ continue; ++ + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; +-- +2.50.1 (Apple Git-155) + diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index 0f493ebc5..7aab752e2 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -176,13 +176,13 @@ Summary: The Linux kernel # define buildid .local %define specversion 5.14.0 %define patchversion 5.14 -%define pkgrelease 687.26.2 +%define pkgrelease 687.26.3 %define kversion 5 %define tarfile_release 5.14.0-687.26.1.el9_8 # This is needed to do merge window version magic %define patchlevel 14 # This allows pkg_release to have configurable %%{?dist} tag -%define specrelease 687.26.2%{?buildid}%{?dist} +%define specrelease 687.26.3%{?buildid}%{?dist} # This defines the kabi tarball version %define kabiversion 5.14.0-687.26.1.el9_8 @@ -985,6 +985,19 @@ Patch1104: 1104-net-ip-gre-require-cap-net-admin-in-device-netns-for-changelink. Patch1105: 1105-wifi-iwlwifi-mld-fix-tso-segmentation-explosion.patch Patch1106: 1106-ixgbevf-fix-uaf-in-vepa-multicast-source-pruning.patch Patch1107: 1107-i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch +Patch1108: 1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch +Patch1109: 1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch +Patch1110: 1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch +Patch1111: 1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch +Patch1112: 1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch +Patch1113: 1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch +Patch1114: 1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch +Patch1115: 1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch +Patch1116: 1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch +Patch1117: 1117-tunnels-load-network-headers-after-skb-cow-in.patch +Patch1118: 1118-blk-mq-pop-cached-request-if-it-is-usable.patch +Patch1119: 1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch +Patch1120: 1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch # END OF PATCH DEFINITIONS %description @@ -1737,6 +1750,19 @@ ApplyPatch 1104-net-ip-gre-require-cap-net-admin-in-device-netns-for-changelink. ApplyPatch 1105-wifi-iwlwifi-mld-fix-tso-segmentation-explosion.patch ApplyPatch 1106-ixgbevf-fix-uaf-in-vepa-multicast-source-pruning.patch ApplyPatch 1107-i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch +ApplyPatch 1108-scsi-target-iscsi-validate-chap-r-length-before-base.patch +ApplyPatch 1109-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch +ApplyPatch 1110-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch +ApplyPatch 1111-usb-serial-mxuport-fix-memory-corruption-with-small.patch +ApplyPatch 1112-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch +ApplyPatch 1113-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch +ApplyPatch 1114-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch +ApplyPatch 1115-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch +ApplyPatch 1116-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch +ApplyPatch 1117-tunnels-load-network-headers-after-skb-cow-in.patch +ApplyPatch 1118-blk-mq-pop-cached-request-if-it-is-usable.patch +ApplyPatch 1119-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch +ApplyPatch 1120-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch # END OF PATCH APPLICATIONS # Any further pre-build tree manipulations happen here. @@ -3811,6 +3837,21 @@ fi # # %changelog +* Wed Jul 22 2026 Andrew Lukoshko - 5.14.0-687.26.3 +- scsi: target: iscsi: Validate CHAP_R length before base64 decode (Alexandru Hossu) {CVE-2026-63886} +- scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf (Michael Bommarito) {CVE-2026-63887} +- scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd() (Michael Bommarito) {CVE-2026-63888} +- USB: serial: mxuport: fix memory corruption with small endpoint (Johan Hovold) {CVE-2026-63899} +- ip6: vti: Use ip6_tnl.net in vti6_changelink() (Kuniyuki Iwashima) {CVE-2026-63917} +- ipv6: exthdrs: refresh nh pointer after ipv6_hop_jumbo() (Justin Iurman) {CVE-2026-63924} +- ipv6: exthdrs: refresh nh after handling HAO option (Zhengchuan Liang) {CVE-2026-63922} +- KVM: SEV: Compute the correct max length of the in-GHCB scratch area (Sean Christopherson) {CVE-2026-63939} +- USB: serial: cypress_m8: fix memory corruption with small endpoint (Johan Hovold) {CVE-2026-63956} +- tunnels: load network headers after skb_cow() in iptunnel_pmtud_build_icmp[v6]() (Eric Dumazet) {CVE-2026-63994} +- blk-mq: pop cached request if it is usable (Keith Busch) {CVE-2026-64017} +- rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg (David Howells) {CVE-2026-64026} +- wifi: mac80211: bounds-check link_id in ieee80211_ml_epcs (Alexandru Hossu) {CVE-2026-64030} + * Tue Jul 21 2026 Andrew Lukoshko - 5.14.0-687.26.2 - NFSD: Fix SECINFO_NO_NAME decode error cleanup (Guannan Wang) {CVE-2026-53398} - nfsd: release layout stid on setlease failure (Chris Mason) {CVE-2026-53399}