Fix 13 more Important CVEs ahead of RHEL; bump to 211.34.3
Backport upstream stable fixes for newly RHEL-Affected Important CVEs (patches 1113-1120, 1122-1126), closest-to-6.12 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) CVE-2026-63950 (mm/rmap) dropped: not applicable to el10 (try_to_unmap_one has no nr_pages batching variable; the stale-nr_pages bug the fix targets cannot occur).
This commit is contained in:
parent
e44942141f
commit
9eb71456e2
@ -0,0 +1,95 @@
|
||||
From bf154c657828ed05399bca5d98cf1611bb048b12 Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Hossu <hossu.alexandru@gmail.com>
|
||||
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 <hossu.alexandru@gmail.com>
|
||||
Reviewed-by: David Disseldorp <ddiss@suse.de>
|
||||
Link: https://patch.msgid.link/20260521151121.808477-1-hossu.alexandru@gmail.com
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
[ CVE-2026-63886: backported to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2) from linux-6.12.y commit bf154c657828ed05399bca5d98cf1611bb048b12; applies cleanly, zero-fuzz. ]
|
||||
|
||||
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
|
||||
index c8a248bd11be..02a4c9aff98d 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 (Apple Git-155)
|
||||
|
||||
204
1114-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch
Normal file
204
1114-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch
Normal file
@ -0,0 +1,204 @@
|
||||
From 30bf335e8fe170322080ee001f05ca29c50680b3 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Bommarito <michael.bommarito@gmail.com>
|
||||
Date: Mon, 11 May 2026 14:49:14 -0400
|
||||
Subject: [PATCH] scsi: target: iscsi: Bound iscsi_encode_text_output() appends
|
||||
to rsp_buf
|
||||
|
||||
commit bf33e01f88388c43e285492a63e539df6ffed64c upstream.
|
||||
|
||||
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 <michael.bommarito@gmail.com>
|
||||
Tested-by: John Garry <john.g.garry@oracle.com>
|
||||
Reviewed-by: John Garry <john.g.garry@oracle.com>
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
[ CVE-2026-63887: backported to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2) from linux-6.12.y commit 30bf335e8fe170322080ee001f05ca29c50680b3; applies cleanly, zero-fuzz. ]
|
||||
|
||||
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
|
||||
index fa3fb5f4e6bc..f98734524693 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 5b90c22ee3dc..5e15c2ea7d65 100644
|
||||
--- a/drivers/target/iscsi/iscsi_target_parameters.c
|
||||
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
|
||||
@@ -1419,19 +1419,42 @@ int iscsi_decode_text_input(
|
||||
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 00fbbebb8c75..d6cbe5dd4b00 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 (Apple Git-155)
|
||||
|
||||
124
1115-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch
Normal file
124
1115-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From ec9f19d52074a191ed1756ed4a7d39fff1a2085c Mon Sep 17 00:00:00 2001
|
||||
From: Michael Bommarito <michael.bommarito@gmail.com>
|
||||
Date: Fri, 5 Jun 2026 22:47:23 -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 <michael.bommarito@gmail.com>
|
||||
Tested-by: John Garry <john.g.garry@oracle.com>
|
||||
Reviewed-by: John Garry <john.g.garry@oracle.com>
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
[ CVE-2026-63888: backported to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2) from linux-6.12.y commit ec9f19d52074a191ed1756ed4a7d39fff1a2085c; applies cleanly, zero-fuzz. ]
|
||||
|
||||
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
|
||||
index 68bbdf3ee101..8a7d308da991 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 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
From e906545641d34fb1a09a65b4b5cfdff40eb09681 Mon Sep 17 00:00:00 2001
|
||||
From: Johan Hovold <johan@kernel.org>
|
||||
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 <andrew@lunn.ch>
|
||||
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
Signed-off-by: Johan Hovold <johan@kernel.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
CVE-2026-63899
|
||||
|
||||
[ Backported from linux-6.12.y commit e906545641d34fb1a09a65b4b5cfdff40eb09681 (mainline 4085f0dbb1ce2251c9a5938d693de6593f0ab2bd); applies cleanly to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2), zero-fuzz. ]
|
||||
|
||||
diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c
|
||||
index ad5fdf55a02e..c9b9928c473a 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)
|
||||
|
||||
78
1117-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch
Normal file
78
1117-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch
Normal file
@ -0,0 +1,78 @@
|
||||
From 225b467e3b631f38be22e4b38062a1fed02fdd21 Mon Sep 17 00:00:00 2001
|
||||
From: Kuniyuki Iwashima <kuniyu@google.com>
|
||||
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 <maoyi.xie@ntu.edu.sg>
|
||||
Reviewed-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: stable@vger.kernel.org # v5.15+
|
||||
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
|
||||
Link: https://patch.msgid.link/20260521130555.3421684-2-maoyixie.tju@gmail.com
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
[ CVE-2026-63917: backported to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2) from linux-6.12.y commit 225b467e3b631f38be22e4b38062a1fed02fdd21; applies cleanly, zero-fuzz. ]
|
||||
|
||||
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
|
||||
index b931092da512..2ac88593a954 100644
|
||||
--- a/net/ipv6/ip6_vti.c
|
||||
+++ b/net/ipv6/ip6_vti.c
|
||||
@@ -722,10 +722,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);
|
||||
@@ -1036,11 +1037,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 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
From 72af7beae774e46ed543f3f2f267bf0a141bfcdd Mon Sep 17 00:00:00 2001
|
||||
From: Justin Iurman <justin.iurman@gmail.com>
|
||||
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 <justin.iurman@gmail.com>
|
||||
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
|
||||
Link: https://patch.msgid.link/20260522112013.12342-1-justin.iurman@gmail.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
CVE-2026-63924
|
||||
|
||||
Backported from linux-6.12.y commit 72af7beae774e46ed543f3f2f267bf0a141bfcdd
|
||||
(mainline d47548a36639095939f4747d4c43f2271366f565); applies cleanly to the
|
||||
a10 kernel-6.12.0-211.34.1.el10_2 tree, zero-fuzz (line offset only). Must be
|
||||
applied before CVE-2026-63922 (HAO) and after the already-shipped
|
||||
CVE-2026-64132 (1111, ipv6 ioam), matching upstream order.
|
||||
|
||||
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
|
||||
index 43e34fe448ff..d179077a2955 100644
|
||||
--- a/net/ipv6/exthdrs.c
|
||||
+++ b/net/ipv6/exthdrs.c
|
||||
@@ -184,6 +184,8 @@ static bool ip6_parse_tlv(bool hopbyhop,
|
||||
case IPV6_TLV_JUMBO:
|
||||
if (!ipv6_hop_jumbo(skb, off))
|
||||
return false;
|
||||
+
|
||||
+ nh = skb_network_header(skb);
|
||||
break;
|
||||
case IPV6_TLV_CALIPSO:
|
||||
if (!ipv6_hop_calipso(skb, off))
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
56
1119-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch
Normal file
56
1119-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch
Normal file
@ -0,0 +1,56 @@
|
||||
From ff375ed1cba81392346c5bfbf0bb7a13b2946f99 Mon Sep 17 00:00:00 2001
|
||||
From: Zhengchuan Liang <zcliangcn@gmail.com>
|
||||
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 <yuantan098@gmail.com>
|
||||
Reported-by: Xin Liu <bird@lzu.edu.cn>
|
||||
Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn>
|
||||
Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn>
|
||||
Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
|
||||
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
|
||||
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
|
||||
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
|
||||
Link: https://patch.msgid.link/7aba1debc2196189172499e5769802b026f8caf8.1779247873.git.zcliangcn@gmail.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
CVE-2026-63922
|
||||
|
||||
Backported from linux-6.12.y commit ff375ed1cba81392346c5bfbf0bb7a13b2946f99
|
||||
(mainline f7b52afe3592eae66e160586b45a3f2242972c63); applies cleanly to the
|
||||
a10 kernel-6.12.0-211.34.1.el10_2 tree, zero-fuzz (line offset only). Must be
|
||||
applied after CVE-2026-63924 (JUMBO) and the already-shipped CVE-2026-64132
|
||||
(1111, ipv6 ioam), matching upstream order.
|
||||
|
||||
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
|
||||
index d179077a2955..e91afe5ec0b5 100644
|
||||
--- a/net/ipv6/exthdrs.c
|
||||
+++ b/net/ipv6/exthdrs.c
|
||||
@@ -203,6 +203,8 @@ static bool ip6_parse_tlv(bool hopbyhop,
|
||||
case IPV6_TLV_HAO:
|
||||
if (!ipv6_dest_hao(skb, off))
|
||||
return false;
|
||||
+
|
||||
+ nh = skb_network_header(skb);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
109
1120-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch
Normal file
109
1120-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch
Normal file
@ -0,0 +1,109 @@
|
||||
From 6ca9400d36005ffdca25f80186bea781c7e1dc4c Mon Sep 17 00:00:00 2001
|
||||
From: Sean Christopherson <seanjc@google.com>
|
||||
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 <thomas.lendacky@amd.com>
|
||||
Reviewed-by: Michael Roth <michael.roth@amd.com>
|
||||
Signed-off-by: Sean Christopherson <seanjc@google.com>
|
||||
Message-ID: <20260501202250.2115252-7-seanjc@google.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
CVE-2026-63939
|
||||
|
||||
Backported from linux-6.12.y commit 6ca9400d36005ffdca25f80186bea781c7e1dc4c
|
||||
(mainline 5867d7e202e09f037cefe77f7af4413c7c0fa088). Adapted to the a10
|
||||
kernel-6.12.0-211.34.1.el10_2 tree: the hunk that adds the in-GHCB
|
||||
ghcb_sa_len assignment had its trailing context adjusted because the a10
|
||||
setup_vmgexit_scratch() else-branch lacks the upstream "GHCB v2 requires the
|
||||
scratch area to be within the GHCB" check. Applies on top of CVE-2026-63794
|
||||
(1102, sev_dbg_crypt) which touches a different function. Zero-fuzz.
|
||||
|
||||
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
|
||||
index 3ff71ce..d218568 100644
|
||||
--- a/arch/x86/kvm/svm/sev.c
|
||||
+++ b/arch/x86/kvm/svm/sev.c
|
||||
@@ -3521,7 +3521,7 @@ int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
||||
}
|
||||
|
||||
#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;
|
||||
@@ -3534,10 +3534,10 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -3561,21 +3561,23 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
|
||||
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");
|
||||
|
||||
@@ -3591,11 +3593,10 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
*/
|
||||
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
|
||||
@ -0,0 +1,46 @@
|
||||
From 1ef25704bd3b625fd151c09feee459479f71ee64 Mon Sep 17 00:00:00 2001
|
||||
From: Johan Hovold <johan@kernel.org>
|
||||
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 <gregkh@linuxfoundation.org>
|
||||
Signed-off-by: Johan Hovold <johan@kernel.org>
|
||||
[ johan: adjust context for 6.18 ]
|
||||
Signed-off-by: Johan Hovold <johan@kernel.org>
|
||||
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||||
|
||||
CVE-2026-63956
|
||||
|
||||
[ Backported from linux-6.12.y commit 1ef25704bd3b625fd151c09feee459479f71ee64 (mainline e1a9d791fd66ab2431b9e6f6f835823809869047); applies cleanly to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2), zero-fuzz. ]
|
||||
|
||||
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
|
||||
index eb47f35aab0c..905f6a560e04 100644
|
||||
--- a/drivers/usb/serial/cypress_m8.c
|
||||
+++ b/drivers/usb/serial/cypress_m8.c
|
||||
@@ -445,6 +445,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)
|
||||
|
||||
86
1123-tunnels-load-network-headers-after-skb-cow-in.patch
Normal file
86
1123-tunnels-load-network-headers-after-skb-cow-in.patch
Normal file
@ -0,0 +1,86 @@
|
||||
From 50750d86a2e5266aba0c295483b3397843198b11 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
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 <edumazet@google.com>
|
||||
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
|
||||
Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||||
|
||||
CVE-2026-63994
|
||||
|
||||
[ Backported from linux-6.12.y commit 50750d86a2e5266aba0c295483b3397843198b11 (mainline b4bc94353050b1fa7b702bd4c6600710dd926cff); applies cleanly to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2), zero-fuzz. ]
|
||||
|
||||
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
|
||||
index 507f2f9ec400..cf496644d3df 100644
|
||||
--- a/net/ipv4/ip_tunnel_core.c
|
||||
+++ b/net/ipv4/ip_tunnel_core.c
|
||||
@@ -210,7 +210,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;
|
||||
@@ -224,7 +224,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)
|
||||
@@ -234,7 +233,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,
|
||||
@@ -306,7 +305,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;
|
||||
@@ -321,7 +320,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)
|
||||
@@ -332,6 +330,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)
|
||||
|
||||
115
1124-blk-mq-pop-cached-request-if-it-is-usable.patch
Normal file
115
1124-blk-mq-pop-cached-request-if-it-is-usable.patch
Normal file
@ -0,0 +1,115 @@
|
||||
From dc278e9bf2b9513a763353e6b9cc21e0f532954e Mon Sep 17 00:00:00 2001
|
||||
From: Keith Busch <kbusch@kernel.org>
|
||||
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 <kbusch@kernel.org>
|
||||
Link: https://patch.msgid.link/20260521190253.242065-1-kbusch@meta.com
|
||||
Signed-off-by: Jens Axboe <axboe@kernel.dk>
|
||||
|
||||
CVE-2026-64017
|
||||
|
||||
[ Backported from mainline commit dc278e9bf2b9513a763353e6b9cc21e0f532954e; applies cleanly to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2), 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)
|
||||
|
||||
654
1125-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch
Normal file
654
1125-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch
Normal file
@ -0,0 +1,654 @@
|
||||
From b94a6ccbaf1104dd980150a65fdeb2f69d17d2f5 Mon Sep 17 00:00:00 2001
|
||||
From: David Howells <dhowells@redhat.com>
|
||||
Date: Fri, 29 May 2026 17:42:07 -0400
|
||||
Subject: [PATCH] rxrpc: Fix DATA decrypt vs splice() by copying data to buffer
|
||||
in recvmsg
|
||||
|
||||
[ Upstream commit d2bc90cf6c75cb96d2ce549be6c35efa3099d25b ]
|
||||
|
||||
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 <imv4bel@gmail.com>
|
||||
Closes: https://lore.kernel.org/r/afKV2zGR6rrelPC7@v4bel/
|
||||
Signed-off-by: David Howells <dhowells@redhat.com>
|
||||
cc: Simon Horman <horms@kernel.org>
|
||||
cc: Jiayuan Chen <jiayuan.chen@linux.dev>
|
||||
cc: linux-afs@lists.infradead.org
|
||||
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
|
||||
Tested-by: Marc Dionne <marc.dionne@auristor.com>
|
||||
Link: https://patch.msgid.link/20260515230516.2718212-3-dhowells@redhat.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Stable-dep-of: 8bfab4b6ffc2 ("rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer")
|
||||
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
CVE-2026-64026
|
||||
|
||||
Backported from linux-6.12.y commit b94a6ccbaf1104dd980150a65fdeb2f69d17d2f5
|
||||
(mainline d2bc90cf6c75cb96d2ce549be6c35efa3099d25b).
|
||||
|
||||
Adaptations for the a10 kernel-6.12.0-211.34.1.el10_2 tree:
|
||||
- rxgk: The 6.12.y stable commit touches only 6 files because the yfs-rxgk
|
||||
(GSSAPI) security class does not exist in 6.12.y stable. a10 DOES ship a
|
||||
functional rxgk security class, so the rxgk.c and rxgk_common.h hunks from
|
||||
the mainline commit are included as well (otherwise rxgk DATA would be read
|
||||
undecrypted from the bounce buffer and remain vulnerable to the splice
|
||||
corruption). rxgk_verify_packet_encrypted() is adapted to a10, which lacks
|
||||
the upstream crypto_krb5_check_data_len() pre-check (separate commit).
|
||||
- net/rxrpc/call_event.c: a10 carries the newer rx_queue batching rework, so
|
||||
the packet-unshare block that this fix removes has a different shape
|
||||
(skb_cloned() only, rxrpc_skb_put_call_rx); it is collapsed to a plain
|
||||
rxrpc_input_call_packet(call, skb) as upstream does.
|
||||
- net/rxrpc/rxkad.c: a10's rxkad_verify_packet_2() lacks the upstream
|
||||
round_down() length alignment and the crypto_skcipher_decrypt() return-value
|
||||
check (separate commits); those are preserved as-is (not introduced here).
|
||||
- net/rxrpc/recvmsg.c: a10 lacks the upstream kdebug("verify = %d") line;
|
||||
preserved as-is.
|
||||
- net/rxrpc/ar-internal.h, call_object.c: context differs only by a10's extra
|
||||
rx_queue field/init and the rxrpc_cleanup_rx_buffers() rename.
|
||||
|
||||
Vulnerable pre-image confirmed present in a10 (in-place skb decryption via
|
||||
skb_to_sgvec in rxkad/rxgk, RXRPC_RX_VERIFIED, rx_pkt_offset==0 recvmsg path,
|
||||
call_event unshare copy). Applies zero-fuzz on the a10 tree.
|
||||
|
||||
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
|
||||
index 2baa99b..a08e45c 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 */
|
||||
@@ -774,6 +772,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 fdd6832..fec59d9 100644
|
||||
--- a/net/rxrpc/call_event.c
|
||||
+++ b/net/rxrpc/call_event.c
|
||||
@@ -332,25 +332,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)
|
||||
|
||||
saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK;
|
||||
|
||||
- if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
|
||||
- sp->hdr.securityIndex != 0 &&
|
||||
- skb_cloned(skb)) {
|
||||
- /* Unshare the packet so that it can be
|
||||
- * modified by in-place decryption.
|
||||
- */
|
||||
- struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
|
||||
-
|
||||
- if (nskb) {
|
||||
- rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
|
||||
- rxrpc_input_call_packet(call, nskb);
|
||||
- rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx);
|
||||
- } else {
|
||||
- /* OOM - Drop the packet. */
|
||||
- rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
|
||||
- }
|
||||
- } else {
|
||||
- rxrpc_input_call_packet(call, skb);
|
||||
- }
|
||||
+ rxrpc_input_call_packet(call, skb);
|
||||
rxrpc_free_skb(skb, rxrpc_skb_put_call_rx);
|
||||
did_receive = true;
|
||||
}
|
||||
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
|
||||
index 918f41d..ffe0a89 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/insecure.c b/net/rxrpc/insecure.c
|
||||
index 0a260df..7a26c60 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;
|
||||
}
|
||||
|
||||
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
|
||||
index 7fa7e77..fc01ee3 100644
|
||||
--- a/net/rxrpc/recvmsg.c
|
||||
+++ b/net/rxrpc/recvmsg.c
|
||||
@@ -147,15 +147,52 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Decrypt and verify a DATA packet.
|
||||
+ * Decrypt and verify a DATA packet. The content of the packet is pulled out
|
||||
+ * into a flat buffer rather than decrypting in place in the skbuff. This also
|
||||
+ * has the advantage of aligning the buffer correctly for the crypto routines.
|
||||
+ *
|
||||
+ * We keep track of the sequence number of the packet currently decrypted into
|
||||
+ * the buffer in ->rx_dec_seq. If MSG_PEEK is used and steps onto a new
|
||||
+ * packet, subsequent recvmsg() calls will have to go back and re-decrypt the
|
||||
+ * current packet.
|
||||
*/
|
||||
static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
+ int ret;
|
||||
|
||||
- if (sp->flags & RXRPC_RX_VERIFIED)
|
||||
- return 0;
|
||||
- return call->security->verify_packet(call, skb);
|
||||
+ if (sp->len > call->rx_dec_bsize) {
|
||||
+ /* Make sure we can hold a 1412-byte jumbo subpacket and make
|
||||
+ * sure that the buffer size is aligned to a crypto blocksize.
|
||||
+ */
|
||||
+ size_t size = clamp(round_up(sp->len, 32), 2048, 65535);
|
||||
+ void *buffer = krealloc(call->rx_dec_buffer, size, GFP_NOFS);
|
||||
+
|
||||
+ if (!buffer)
|
||||
+ return -ENOMEM;
|
||||
+ call->rx_dec_buffer = buffer;
|
||||
+ call->rx_dec_bsize = size;
|
||||
+ }
|
||||
+
|
||||
+ ret = -EFAULT;
|
||||
+ if (skb_copy_bits(skb, sp->offset, call->rx_dec_buffer, sp->len) < 0)
|
||||
+ goto err;
|
||||
+
|
||||
+ call->rx_dec_offset = 0;
|
||||
+ call->rx_dec_len = sp->len;
|
||||
+ call->rx_dec_seq = sp->hdr.seq;
|
||||
+ ret = call->security->verify_packet(call, skb);
|
||||
+ if (ret < 0)
|
||||
+ goto err;
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ kfree(call->rx_dec_buffer);
|
||||
+ call->rx_dec_buffer = NULL;
|
||||
+ call->rx_dec_bsize = 0;
|
||||
+ call->rx_dec_offset = 0;
|
||||
+ call->rx_dec_len = 0;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -283,16 +320,21 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
|
||||
if (msg)
|
||||
sock_recv_timestamp(msg, sock->sk, skb);
|
||||
|
||||
- if (rx_pkt_offset == 0) {
|
||||
+ if (call->rx_dec_seq != sp->hdr.seq ||
|
||||
+ !call->rx_dec_buffer) {
|
||||
ret2 = rxrpc_verify_data(call, skb);
|
||||
trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,
|
||||
- sp->offset, sp->len, ret2);
|
||||
+ call->rx_dec_offset,
|
||||
+ call->rx_dec_len, ret2);
|
||||
if (ret2 < 0) {
|
||||
ret = ret2;
|
||||
goto out;
|
||||
}
|
||||
- rx_pkt_offset = sp->offset;
|
||||
- rx_pkt_len = sp->len;
|
||||
+ }
|
||||
+
|
||||
+ if (rx_pkt_offset == USHRT_MAX) {
|
||||
+ rx_pkt_offset = call->rx_dec_offset;
|
||||
+ rx_pkt_len = call->rx_dec_len;
|
||||
} else {
|
||||
trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq,
|
||||
rx_pkt_offset, rx_pkt_len, 0);
|
||||
@@ -304,10 +346,10 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
|
||||
if (copy > remain)
|
||||
copy = remain;
|
||||
if (copy > 0) {
|
||||
- ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
|
||||
- copy);
|
||||
- if (ret2 < 0) {
|
||||
- ret = ret2;
|
||||
+ ret2 = copy_to_iter(call->rx_dec_buffer + rx_pkt_offset,
|
||||
+ copy, iter);
|
||||
+ if (ret2 != copy) {
|
||||
+ ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -328,7 +370,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
|
||||
/* The whole packet has been transferred. */
|
||||
if (sp->hdr.flags & RXRPC_LAST_PACKET)
|
||||
ret = 1;
|
||||
- rx_pkt_offset = 0;
|
||||
+ rx_pkt_offset = USHRT_MAX;
|
||||
rx_pkt_len = 0;
|
||||
|
||||
skb = skb_peek_next(skb, &call->recvmsg_queue);
|
||||
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
|
||||
index 8d17b49..b9d2da9 100644
|
||||
--- a/net/rxrpc/rxgk.c
|
||||
+++ b/net/rxrpc/rxgk.c
|
||||
@@ -473,8 +473,9 @@ 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;
|
||||
|
||||
@@ -496,16 +497,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 +522,46 @@ 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);
|
||||
+ 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);
|
||||
diff --git a/net/rxrpc/rxgk_common.h b/net/rxrpc/rxgk_common.h
|
||||
index 80164d8..bae8b98 100644
|
||||
--- a/net/rxrpc/rxgk_common.h
|
||||
+++ b/net/rxrpc/rxgk_common.h
|
||||
@@ -104,6 +104,49 @@ int rxgk_decrypt_skb(const struct krb5_enctype *krb5,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * 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(const struct krb5_enctype *krb5,
|
||||
+ struct crypto_aead *aead,
|
||||
+ void **_data, unsigned int *_len,
|
||||
+ int *_error_code)
|
||||
+{
|
||||
+ struct scatterlist sg[1];
|
||||
+ size_t offset = 0, len = *_len;
|
||||
+ int ret;
|
||||
+
|
||||
+ sg_init_one(sg, *_data, len);
|
||||
+
|
||||
+ ret = crypto_krb5_decrypt(krb5, aead, sg, 1, &offset, &len);
|
||||
+ switch (ret) {
|
||||
+ case 0:
|
||||
+ if (offset & 3) {
|
||||
+ *_error_code = RXGK_INCONSISTENCY;
|
||||
+ ret = -EPROTO;
|
||||
+ break;
|
||||
+ }
|
||||
+ *_data += offset;
|
||||
+ *_len = len;
|
||||
+ break;
|
||||
+ case -EBADMSG: /* Checksum mismatch. */
|
||||
+ case -EPROTO:
|
||||
+ *_error_code = RXGK_SEALEDINCON;
|
||||
+ break;
|
||||
+ case -EMSGSIZE:
|
||||
+ *_error_code = RXGK_PACKETSHORT;
|
||||
+ break;
|
||||
+ case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
|
||||
+ default:
|
||||
+ *_error_code = RXGK_INCONSISTENCY;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Check the MIC on a region of an skbuff. The offset and length are updated
|
||||
* to reflect the actual content of the secure region.
|
||||
@@ -147,3 +190,42 @@ int rxgk_verify_mic_skb(const struct krb5_enctype *krb5,
|
||||
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * 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(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[1];
|
||||
+ size_t offset = 0, len = *_len;
|
||||
+ int ret;
|
||||
+
|
||||
+ sg_init_one(sg, *_data, len);
|
||||
+
|
||||
+ ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, 1, &offset, &len);
|
||||
+ switch (ret) {
|
||||
+ case 0:
|
||||
+ *_data += offset;
|
||||
+ *_len = len;
|
||||
+ break;
|
||||
+ case -EBADMSG: /* Checksum mismatch */
|
||||
+ case -EPROTO:
|
||||
+ *_error_code = RXGK_SEALEDINCON;
|
||||
+ break;
|
||||
+ case -EMSGSIZE:
|
||||
+ *_error_code = RXGK_PACKETSHORT;
|
||||
+ break;
|
||||
+ case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
|
||||
+ default:
|
||||
+ *_error_code = RXGK_INCONSISTENCY;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
|
||||
index 3657c06..cf780ba 100644
|
||||
--- a/net/rxrpc/rxkad.c
|
||||
+++ b/net/rxrpc/rxkad.c
|
||||
@@ -425,27 +425,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));
|
||||
@@ -457,13 +454,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;
|
||||
@@ -472,10 +467,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
if (check != 0)
|
||||
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
|
||||
rxkad_abort_1_short_check);
|
||||
- if (data_size > sp->len)
|
||||
+ if (data_size > len)
|
||||
return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
|
||||
rxkad_abort_1_short_data);
|
||||
- sp->len = data_size;
|
||||
+ call->rx_dec_len = data_size;
|
||||
|
||||
_leave(" = 0 [dlen=%x]", data_size);
|
||||
return 0;
|
||||
@@ -489,40 +484,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];
|
||||
@@ -530,20 +509,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;
|
||||
@@ -553,17 +528,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)
|
||||
{
|
||||
@ -0,0 +1,51 @@
|
||||
From f718506edd2d9c6a308ded9d13c632bf7b7d5a2c Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Hossu <hossu.alexandru@gmail.com>
|
||||
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 <hossu.alexandru@gmail.com>
|
||||
Link: https://patch.msgid.link/20260515102908.1653088-1-hossu.alexandru@gmail.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
|
||||
CVE-2026-64030
|
||||
|
||||
[ Backported from mainline commit f718506edd2d9c6a308ded9d13c632bf7b7d5a2c; applies cleanly to AlmaLinux 10 (kernel-6.12.0-211.34.1.el10_2), 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)
|
||||
|
||||
45
kernel.spec
45
kernel.spec
@ -176,13 +176,13 @@ Summary: The Linux kernel
|
||||
%define specrpmversion 6.12.0
|
||||
%define specversion 6.12.0
|
||||
%define patchversion 6.12
|
||||
%define pkgrelease 211.34.2
|
||||
%define pkgrelease 211.34.3
|
||||
%define kversion 6
|
||||
%define tarfile_release 6.12.0-211.34.1.el10_2
|
||||
# This is needed to do merge window version magic
|
||||
%define patchlevel 12
|
||||
# This allows pkg_release to have configurable %%{?dist} tag
|
||||
%define specrelease 211.34.2%{?buildid}%{?dist}
|
||||
%define specrelease 211.34.3%{?buildid}%{?dist}
|
||||
# This defines the kabi tarball version
|
||||
%define kabiversion 6.12.0-211.34.1.el10_2
|
||||
|
||||
@ -1152,6 +1152,19 @@ Patch1109: 1109-netfs-fix-early-put-of-sink-folio-in-netfs-read-gaps.patch
|
||||
Patch1110: 1110-ixgbevf-fix-use-after-free-in-vepa-multicast-source-pru.patch
|
||||
Patch1111: 1111-ipv6-ioam-refresh-hdr-pointer-before-ioam6-event.patch
|
||||
Patch1112: 1112-i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch
|
||||
Patch1113: 1113-scsi-target-iscsi-validate-chap-r-length-before-base.patch
|
||||
Patch1114: 1114-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch
|
||||
Patch1115: 1115-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch
|
||||
Patch1116: 1116-usb-serial-mxuport-fix-memory-corruption-with-small.patch
|
||||
Patch1117: 1117-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch
|
||||
Patch1118: 1118-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch
|
||||
Patch1119: 1119-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch
|
||||
Patch1120: 1120-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch
|
||||
Patch1122: 1122-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch
|
||||
Patch1123: 1123-tunnels-load-network-headers-after-skb-cow-in.patch
|
||||
Patch1124: 1124-blk-mq-pop-cached-request-if-it-is-usable.patch
|
||||
Patch1125: 1125-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch
|
||||
Patch1126: 1126-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%description
|
||||
@ -2026,6 +2039,19 @@ ApplyPatch 1109-netfs-fix-early-put-of-sink-folio-in-netfs-read-gaps.patch
|
||||
ApplyPatch 1110-ixgbevf-fix-use-after-free-in-vepa-multicast-source-pru.patch
|
||||
ApplyPatch 1111-ipv6-ioam-refresh-hdr-pointer-before-ioam6-event.patch
|
||||
ApplyPatch 1112-i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch
|
||||
ApplyPatch 1113-scsi-target-iscsi-validate-chap-r-length-before-base.patch
|
||||
ApplyPatch 1114-scsi-target-iscsi-bound-iscsi-encode-text-output-app.patch
|
||||
ApplyPatch 1115-scsi-target-iscsi-fix-crc-overread-and-double-free-i.patch
|
||||
ApplyPatch 1116-usb-serial-mxuport-fix-memory-corruption-with-small.patch
|
||||
ApplyPatch 1117-ip6-vti-use-ip6-tnl-net-in-vti6-changelink.patch
|
||||
ApplyPatch 1118-ipv6-exthdrs-refresh-nh-pointer-after-ipv6-hop-jumbo.patch
|
||||
ApplyPatch 1119-ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch
|
||||
ApplyPatch 1120-kvm-sev-compute-the-correct-max-length-of-the-in-ghc.patch
|
||||
ApplyPatch 1122-usb-serial-cypress-m8-fix-memory-corruption-with-sma.patch
|
||||
ApplyPatch 1123-tunnels-load-network-headers-after-skb-cow-in.patch
|
||||
ApplyPatch 1124-blk-mq-pop-cached-request-if-it-is-usable.patch
|
||||
ApplyPatch 1125-rxrpc-fix-data-decrypt-vs-splice-by-copying-data-to.patch
|
||||
ApplyPatch 1126-wifi-mac80211-bounds-check-link-id-in-ieee80211-ml-e.patch
|
||||
# END OF PATCH APPLICATIONS
|
||||
|
||||
# Any further pre-build tree manipulations happen here.
|
||||
@ -4537,6 +4563,21 @@ fi\
|
||||
#
|
||||
#
|
||||
%changelog
|
||||
* Wed Jul 22 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 6.12.0-211.34.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 <alukoshko@almalinux.org> - 6.12.0-211.34.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}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user