From: Richard Cheng <icheng@nvidia.com>
To: dave@stgolabs.net, jic23@kernel.org, dave.jiang@intel.com,
alison.schofield@intel.com, vishal.l.verma@intel.com,
djbw@kernel.org, danwilliams@nvidia.com, nvdimm@lists.linux.dev
Cc: iweiny@kernel.org, ming.li@zohomail.com, kobak@nvidia.com,
kaihengf@nvidia.com, kees@kernel.org, newtonl@nvidia.com,
kristinc@nvidia.com, mochs@nvidia.com, linux-cxl@vger.kernel.org,
linux-kernel@vger.kernel.org, Richard Cheng <icheng@nvidia.com>
Subject: [ndctl PATCH RESEND] test/cxl-mbox: Regression test for huge CXL_MEM_SEND_COMMAND out.size
Date: Wed, 24 Jun 2026 23:01:58 +0800 [thread overview]
Message-ID: <20260624150158.55264-1-icheng@nvidia.com> (raw)
Implement a regression test for unbounded kvzalloc() in the kernel's
cxl_mbox_cmd_ctor(), which a CXL_MEM_SEND_COMMAND with an out.size
greater than INT_MAX could drive into a size > INT_MAX kvmalloc() WARN.
libcxl's cxl_cmd_set_output_payload() rejects an out.size larger than
the mailbox payload_max, so the test crafts a raw struct
cxl_send_command and issues the CXL_MEM_SEND_COMMAND ioctl directly
against the cxl_test mock memdev.
The test is for a kernel bug fix [1].
[1]: https://lore.kernel.org/all/20260624144147.53997-1-icheng@nvidia.com/
Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
test/cxl-mbox.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++
test/cxl-mbox.sh | 48 ++++++++++++++++++
2 files changed, 177 insertions(+)
create mode 100644 test/cxl-mbox.c
create mode 100755 test/cxl-mbox.sh
diff --git a/test/cxl-mbox.c b/test/cxl-mbox.c
new file mode 100644
index 0000000..d81327b
--- /dev/null
+++ b/test/cxl-mbox.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2026 Nvidia Corporation. All rights reserved.
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <cxl/libcxl.h>
+#include <cxl/cxl_mem.h>
+
+static const char provider[] = "cxl_test";
+
+/*
+ * The cxl_test mock advertises a 4 KiB (SZ_4K) mailbox payload_size and
+ * IDENTIFY returns a full struct cxl_mbox_identify. Post-fix the kernel
+ * clamps the output allocation to payload_size and copies that many bytes
+ * back into out.payload, so the buffer must be >= payload_size. 64 KiB is
+ * comfortably above the mock's 4 KiB payload.
+ */
+#define OUT_BUF_SIZE (64 * 1024)
+
+/*
+ * Regression for the unbounded kvzalloc() in cxl_mbox_cmd_ctor() driven by a
+ * huge CXL_MEM_SEND_COMMAND out.size. The kernel fix CLAMPS the output
+ * allocation to the mailbox payload_size; it does not reject the request.
+ * Assert the ioctl SUCCEEDS (no -ENOMEM) -- do NOT assert -EINVAL.
+ */
+static int test_cxl_mbox_huge_out_size(struct cxl_memdev *memdev)
+{
+ struct cxl_send_command c = { 0 };
+ const char *devname;
+ char path[256];
+ void *buf;
+ int fd, rc;
+
+ devname = cxl_memdev_get_devname(memdev);
+ if (!devname)
+ return -ENODEV;
+
+ snprintf(path, sizeof(path), "/dev/cxl/%s", devname);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ if (errno == ENOENT || errno == ENODEV)
+ return -ENODEV;
+ fprintf(stderr, "failed to open %s: %s\n", path,
+ strerror(errno));
+ return -errno;
+ }
+
+ buf = calloc(1, OUT_BUF_SIZE);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ c.id = CXL_MEM_COMMAND_ID_IDENTIFY;
+ /*
+ * 0x80000000 (2^31, > INT_MAX) is the proven reproducer that trips the
+ * size > INT_MAX kvmalloc() WARN. out.size is __s32 in this vendored
+ * UAPI; cast to avoid -Woverflow, the kernel reads the same 4 bytes
+ * (kernel UAPI declares it __u32).
+ */
+ c.out.size = (typeof(c.out.size))0x80000000U;
+ c.out.payload = (__u64)(uintptr_t)buf;
+
+ rc = ioctl(fd, CXL_MEM_SEND_COMMAND, &c);
+
+ /* Pass iff the kernel clamped (success), not rejected. */
+ if (rc == 0 && c.retval == 0) {
+ rc = 0;
+ goto out;
+ }
+
+ fprintf(stderr,
+ "CXL_MEM_SEND_COMMAND huge out.size mishandled: rc=%d errno=%d retval=%u\n",
+ rc, errno, c.retval);
+ rc = -ENXIO;
+
+out:
+ free(buf);
+ close(fd);
+ return rc;
+}
+
+static int test_cxl_mbox(struct cxl_ctx *ctx, struct cxl_bus *bus)
+{
+ struct cxl_memdev *memdev;
+
+ cxl_memdev_foreach(ctx, memdev) {
+ if (cxl_memdev_get_bus(memdev) != bus)
+ continue;
+ return test_cxl_mbox_huge_out_size(memdev);
+ }
+
+ return -ENODEV;
+}
+
+int main(int argc, char *argv[])
+{
+ struct cxl_ctx *ctx;
+ struct cxl_bus *bus;
+ int rc;
+
+ rc = cxl_new(&ctx);
+ if (rc < 0)
+ return rc;
+
+ cxl_set_log_priority(ctx, LOG_DEBUG);
+
+ bus = cxl_bus_get_by_provider(ctx, provider);
+ if (!bus) {
+ fprintf(stderr, "%s: unable to find bus (%s)\n",
+ argv[0], provider);
+ rc = -ENODEV;
+ goto out;
+ }
+
+ rc = test_cxl_mbox(ctx, bus);
+
+out:
+ cxl_unref(ctx);
+ return rc;
+}
diff --git a/test/cxl-mbox.sh b/test/cxl-mbox.sh
new file mode 100755
index 0000000..67fecf5
--- /dev/null
+++ b/test/cxl-mbox.sh
@@ -0,0 +1,48 @@
+#!/bin/bash -Ex
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2026 Nvidia Corporation. All rights reserved.
+
+. $(dirname "$0")/common
+
+BIN="$TEST_PATH"/cxl-mbox
+rc=77
+# 237 is -ENODEV
+ERR_NODEV=237
+# TAINT_WARN is bit 9
+TAINT_WARN=512
+
+trap 'err $LINENO' ERR
+
+modprobe -r cxl_test 2>/dev/null
+modprobe cxl_test
+# cxl_test alone does not autoload the mock memdev module on this box
+modprobe cxl_mock_mem
+
+main()
+{
+ test -x "$BIN" || do_skip "no CXL mailbox test"
+
+ t0=$(cat /proc/sys/kernel/tainted)
+
+ rc=0
+ "$BIN" || rc=$?
+
+ t1=$(cat /proc/sys/kernel/tainted)
+
+ echo "status: $rc"
+ if [ "$rc" -eq "$ERR_NODEV" ]; then
+ do_skip "no cxl_test memdev"
+ elif [ "$rc" -ne 0 ]; then
+ echo "fail: $LINENO" && exit 1
+ fi
+
+ if (( (t1 & TAINT_WARN) && !(t0 & TAINT_WARN) )); then
+ echo "fail: $LINENO kernel WARN taint (bit 9) set" && exit 1
+ fi
+
+ _cxl_cleanup
+}
+
+{
+ main "$@"; exit "$?"
+}
base-commit: 8ad90e54f0ff4f7291e7f21d44d769d10f24e2b6
--
2.43.0
next reply other threads:[~2026-06-24 15:02 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 15:01 Richard Cheng [this message]
2026-06-24 15:09 ` [ndctl PATCH RESEND] test/cxl-mbox: Regression test for huge CXL_MEM_SEND_COMMAND out.size sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260624150158.55264-1-icheng@nvidia.com \
--to=icheng@nvidia.com \
--cc=alison.schofield@intel.com \
--cc=danwilliams@nvidia.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=djbw@kernel.org \
--cc=iweiny@kernel.org \
--cc=jic23@kernel.org \
--cc=kaihengf@nvidia.com \
--cc=kees@kernel.org \
--cc=kobak@nvidia.com \
--cc=kristinc@nvidia.com \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ming.li@zohomail.com \
--cc=mochs@nvidia.com \
--cc=newtonl@nvidia.com \
--cc=nvdimm@lists.linux.dev \
--cc=vishal.l.verma@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.