From nobody Fri Sep 25 10:05:34 2026 Received: from cstnet.cn (smtp21.cstnet.cn [159.226.251.21]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EF10486424; Mon, 14 Sep 2026 13:02:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.21 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789390959; cv=none; b=q2UVRZR7Noue9gqKbwexiHYq2sx15OYONSupFNcrfc207wYFcMFaRaxVpuLXNGZd+tOjjr3mmgXbWoulHjTxn5Z5qXMoTOAk6ffLM1wzBMyTVi4sdDXfhaGE6iy4yN6gsd7+iKDTgSaoiFCnMrdEDagYjqlDfE50wSls9DozazU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789390959; c=relaxed/simple; bh=LqGS9Eb2l3Lg570G7hppxAYGPGcpW4Hza3JY5sXhCPw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=H6ho6WWapcCtkjCMG81i/I0mnWAxsRCOuOd24L/lcBkKtQJ5nqAxi6JaQ3r0qGQS0ZuaTKomwcymdpZAEjkemMLdP86L/Di4Y4VO2vupfg7Cr2IqHcUCTU8fcT1rgIu3MY2xOajm4+afIHW9DSdcU52ITf0+pk1xJ39HOkJRhJ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=semi.ac.cn; spf=pass smtp.mailfrom=semi.ac.cn; arc=none smtp.client-ip=159.226.251.21 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=semi.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=semi.ac.cn Received: from localhost.localdomain (unknown [159.226.228.11]) by APP-01 (Coremail) with SMTP id qwCowACHWOwe76dqyj74Bw--.19200S3; Mon, 14 Sep 2026 20:57:08 +0800 (CST) From: Gaobin Huang To: linux-cxl@vger.kernel.org Cc: Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams , linux-kernel@vger.kernel.org Subject: [PATCH 1/2] cxl/mbox: clamp the event record count to the received payload Date: Mon, 14 Sep 2026 20:57:00 +0800 Message-Id: <20260914125701.1160136-2-huanggaobin23@semi.ac.cn> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260914125701.1160136-1-huanggaobin23@semi.ac.cn> References: <20260914125701.1160136-1-huanggaobin23@semi.ac.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qwCowACHWOwe76dqyj74Bw--.19200S3 X-Coremail-Antispam: 1UD129KBjvJXoWxuF15XryfWry8KF4rtF4rAFb_yoWrXryxpF WfAFy3trs7JayxuwnxXay5Zas0kw1kXrZxXw1qq343Kr1fJrnxZasxJa4UZw45Kr95JF9a y34jqFW3CayUZaUanT9S1TB71UUUUUJqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUQ2b7Iv0xC_Kw4lb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUGwA2048vs2IY020Ec7CjxVAFwI0_JFI_Gr1l8cAvFVAK0II2c7xJM28CjxkF 64kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcV CY1x0267AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv 6xkF7I0E14v26F4UJVW0owAaw2AFwI0_Jrv_JF1lnxkEFVAIw20F6cxK64vIFxWle2I262 IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAF wI0_Jrv_JF1lYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0x vY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCY02Avz4vE14v_Xr1l42xK82IYc2Ij64vI r41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8Gjc xK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0 cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8V AvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E 14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxUkqXdUUUUU X-CM-SenderInfo: xkxd0wxjdruxrqstq2xhplhtffof0/ Content-Type: text/plain; charset="utf-8" cxl_mem_get_records_log() walks payload->records[] using the record_count the device wrote into that same payload, and cxl_clear_event_record() repeats the walk with the same unvalidated value, reading record handles past the end of the mailbox buffer. The handle it reads is then handed back to the device in the Clear Event Records payload. The command is issued with .size_out =3D cxl_mbox->payload_size and only .min_out =3D struct_size(payload, records, 0) enforced, so the count is never compared against what the device actually returned. __cxl_pci_mbox_send_cmd() already knows that number: it stores the bytes it copied into the driver buffer in mbox_cmd.size_out. Derive the record bound from it, and pass the validated count to cxl_clear_event_record() instead of letting it re-read the raw field. Seen with a QEMU Type-3 device that returns one record in a 2048 byte buffer while claiming more, so records[16] is the first access outside it: BUG: KASAN: slab-out-of-bounds in cxl_clear_event_record+0x1ad/0x2e0 Read of size 2 at addr ffff888003306834 by task irq/27-0000:35:/58 which belongs to the cache kmalloc-2k of size 2048 The buggy address is located 52 bytes to the right of allocated 2048-byte region A sweep of the claimed count agrees: 16 stays inside the allocation and 17 does not. With the clamp in place the same device logs Event log '4': device claimed 4096 records but the payload holds 1 and the log is drained normally. Fixes: 6ebe28f9ec72 ("cxl/mem: Read, trace, and clear events on driver load= ") Signed-off-by: Gaobin Huang --- drivers/cxl/core/mbox.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 55828a836..a8f51bf0f 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -992,11 +992,13 @@ static void __cxl_event_trace_record(struct cxl_memde= v *cxlmd, =20 static int cxl_clear_event_record(struct cxl_memdev_state *mds, enum cxl_event_log_type log, - struct cxl_get_event_payload *get_pl) + struct cxl_get_event_payload *get_pl, + u16 nr_rec) { struct cxl_mailbox *cxl_mbox =3D &mds->cxlds.cxl_mbox; struct cxl_mbox_clear_event_payload *payload; - u16 total =3D le16_to_cpu(get_pl->record_count); + /* count validated by cxl_mem_get_records_log(), not re-read here */ + u16 total =3D nr_rec; u8 max_handles =3D CXL_CLEAR_EVENT_MAX_HANDLES; size_t pl_size =3D struct_size(payload, handles, max_handles); struct cxl_mbox_cmd mbox_cmd; @@ -1070,6 +1072,7 @@ static void cxl_mem_get_records_log(struct cxl_memdev= _state *mds, struct cxl_get_event_payload *payload; u8 log_type =3D type; u16 nr_rec; + size_t max_recs; =20 mutex_lock(&mds->event.log_lock); payload =3D mds->event.buf; @@ -1093,7 +1096,20 @@ static void cxl_mem_get_records_log(struct cxl_memde= v_state *mds, break; } =20 + /* + * The record count is device-supplied. Never walk records[] + * past the payload the device actually returned. + */ + max_recs =3D (mbox_cmd.size_out - + offsetof(struct cxl_get_event_payload, records)) / + sizeof(struct cxl_event_record_raw); nr_rec =3D le16_to_cpu(payload->record_count); + if (nr_rec > max_recs) { + dev_warn_ratelimited(dev, + "Event log '%d': device claimed %u records but the payload holds= %zu\n", + type, nr_rec, max_recs); + nr_rec =3D max_recs; + } if (!nr_rec) break; =20 @@ -1104,7 +1120,7 @@ static void cxl_mem_get_records_log(struct cxl_memdev= _state *mds, if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW) trace_cxl_overflow(cxlmd, type, payload); =20 - rc =3D cxl_clear_event_record(mds, type, payload); + rc =3D cxl_clear_event_record(mds, type, payload, nr_rec); if (rc) { dev_err_ratelimited(dev, "Event log '%d': Failed to clear events : %d", --=20 2.34.1 From nobody Fri Sep 25 10:05:34 2026 Received: from cstnet.cn (smtp21.cstnet.cn [159.226.251.21]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EFDC486623; Mon, 14 Sep 2026 13:02:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.21 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789390959; cv=none; b=S77cU/OQlMkzsVZUx3yzeqOhUIOfuccD6ML5rb3HWhefAy6ym2+QIk9tKJ8NTmTbXHve4a03I6lAScfOXkMH1/eiGzfyxB00UK9rstNXrgYdvzUEbfOHv5QQVcHzju5g9oxVKn8tPwTWMxs3ZlHtLFpgpATTFUUEASUSIwBFacU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789390959; c=relaxed/simple; bh=7GbaiCEjRwQUmr3ACyN5hD3nr1lFtbeBjz7zYOw52pQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=UlUKDRNYuq90rK64/nFjwDnOVP7R6K3upB1LiLaSn972+Sj+fX6qwJrjiw64mmREuCWPjemhFsts3fhPQCSmhcYvCc92J9uPpkNqzjnmTMo6tuC1pT0anFx9nO2Ziil6TnDNA3lPgHSiObtrCUzwlvecHB+zHMINEuSsy+RuI1g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=semi.ac.cn; spf=pass smtp.mailfrom=semi.ac.cn; arc=none smtp.client-ip=159.226.251.21 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=semi.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=semi.ac.cn Received: from localhost.localdomain (unknown [159.226.228.11]) by APP-01 (Coremail) with SMTP id qwCowACHWOwe76dqyj74Bw--.19200S4; Mon, 14 Sep 2026 20:57:08 +0800 (CST) From: Gaobin Huang To: linux-cxl@vger.kernel.org Cc: Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams , linux-kernel@vger.kernel.org Subject: [PATCH 2/2] cxl/mbox: bound the Get Supported Logs entry count by the payload Date: Mon, 14 Sep 2026 20:57:01 +0800 Message-Id: <20260914125701.1160136-3-huanggaobin23@semi.ac.cn> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260914125701.1160136-1-huanggaobin23@semi.ac.cn> References: <20260914125701.1160136-1-huanggaobin23@semi.ac.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qwCowACHWOwe76dqyj74Bw--.19200S4 X-Coremail-Antispam: 1UD129KBjvJXoWxAw4rWF15uw1xAryrtF48Crg_yoWrAr1kpF WY9a4UJrn3ZFy7CwnrZay5WrZ8uw4kZryUAFyvg34YkwnxCr12qFyDGayYq34FvryfGF12 k3Z0qF98Ca1kXF7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUmqb7Iv0xC_Kw4lb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUXwA2048vs2IY020Ec7CjxVAFwI0_Gr0_Xr1l8cAvFVAK0II2c7xJM28CjxkF 64kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcV CY1x0267AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280 aVCY1x0267AKxVWxJr0_GcWlnxkEFVAIw20F6cxK64vIFxWle2I262IYc4CY6c8Ij28IcV AaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0E x4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x 0262kKe7AKxVWUtVW8ZwCY02Avz4vE14v_Xr1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC 6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWw C2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_ JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rVWUJV WUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIY CTnIWIevJa73UjIFyTuYvjxUkRBTDUUUU X-CM-SenderInfo: xkxd0wxjdruxrqstq2xhplhtffof0/ Content-Type: text/plain; charset="utf-8" cxl_enumerate_cmds() iterates gsl->entries entries of gsl->entry[] using the count the device put in the Get Supported Logs response. The response is only checked with .min_out =3D 2, so a device may report more entries than it delivered and the driver reads past the end of the buffer. This is probe time, so it happens on every boot of a machine with such a device, without any host action. cxl_get_gsl() can already tell the caller how much arrived, because __cxl_pci_mbox_send_cmd() records the copied byte count in mbox_cmd.size_out. Derive the number of entries that fit from it and stop the loop there. Guard the subtraction too: min_out is smaller than the response header, so a two byte response would otherwise wrap the size_t arithmetic and leave the bound with nothing to do. Seen with a QEMU Type-3 device that reports 0xffff entries while writing one, in a 2048 byte buffer: BUG: KASAN: slab-out-of-bounds in cxl_enumerate_cmds+0x1e3/0x980 Read of size 4 at addr ffff888003707810 by task kworker/u8:2/38 cxl_enumerate_cmds+0x1e3/0x980 cxl_pci_probe+0x84a/0x11e0 which belongs to the cache kmalloc-2k of size 2048 The buggy address is located 16 bytes to the right of the allocated region The Read of size 4 is gsl->entry[i].size. The buffer can hold 102 entries, so claiming 102 is still inside it and 103 is not, which is what the sweep shows. With the bound in place the same device logs GSL: device claimed 65535 entries but the payload holds 1 and enumeration continues with the entries that are present. This is the cross-check get_supported_features() already performs in drivers/cxl/core/features.c, where a device supplied count is compared against the retrieved length before the entries are used. Fixes: 472b1ce6e9d6 ("cxl/mem: Enable commands via CEL") Signed-off-by: Gaobin Huang --- drivers/cxl/core/mbox.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index a8f51bf0f..c94439554 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -794,7 +794,8 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, = size_t size, u8 *cel) set_features_cap(cxl_mbox, ro_cmds, wr_cmds); } =20 -static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_memdev_s= tate *mds) +static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_memdev_s= tate *mds, + size_t *len) { struct cxl_mailbox *cxl_mbox =3D &mds->cxlds.cxl_mbox; struct cxl_mbox_get_supported_logs *ret; @@ -818,7 +819,7 @@ static struct cxl_mbox_get_supported_logs *cxl_get_gsl(= struct cxl_memdev_state * return ERR_PTR(rc); } =20 - + *len =3D mbox_cmd.size_out; /* bytes actually received */ return ret; } =20 @@ -849,18 +850,39 @@ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) struct cxl_mbox_get_supported_logs *gsl; struct device *dev =3D mds->cxlds.dev; struct cxl_mem_command *cmd; + size_t gsl_len, gsl_hdr, max_entries; int i, rc; =20 - gsl =3D cxl_get_gsl(mds); + gsl =3D cxl_get_gsl(mds, &gsl_len); if (IS_ERR(gsl)) return PTR_ERR(gsl); =20 + /* + * The device chooses the reported payload length and may return a + * response as short as the entry count field on its own (min_out is + * 2), so derive the entry count without underflowing. + */ + gsl_hdr =3D offsetof(struct cxl_mbox_get_supported_logs, entry); + max_entries =3D gsl_len > gsl_hdr ? + (gsl_len - gsl_hdr) / sizeof(gsl->entry[0]) : 0; + rc =3D -ENOENT; for (i =3D 0; i < le16_to_cpu(gsl->entries); i++) { - u32 size =3D le32_to_cpu(gsl->entry[i].size); - uuid_t uuid =3D gsl->entry[i].uuid; + u32 size; + uuid_t uuid; u8 *log; =20 + if (i >=3D max_entries) { + dev_warn_ratelimited(dev, + "GSL: device claimed %u entries but the payload holds %zu\n", + le16_to_cpu(gsl->entries), + max_entries); + break; + } + + size =3D le32_to_cpu(gsl->entry[i].size); + uuid =3D gsl->entry[i].uuid; + dev_dbg(dev, "Found LOG type %pU of size %d", &uuid, size); =20 if (!uuid_equal(&uuid, &log_uuid[CEL_UUID])) --=20 2.34.1