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, nvdimm@lists.linux.dev
Cc: iweiny@kernel.org, ming.li@zohomail.com, gourry@gourry.net,
rrichter@amd.com, linux-cxl@vger.kernel.org,
linux-kernel@vger.kernel.org, newtonl@nvidia.com,
kristinc@nvidia.com, kaihengf@nvidia.com, kobak@nvidia.com,
mochs@nvidia.com, Richard Cheng <icheng@nvidia.com>
Subject: [ndctl PATCH v2] test/fwctl: Add Feature OOB rejection regression tests
Date: Tue, 21 Jul 2026 14:21:22 +0800 [thread overview]
Message-ID: <20260721062122.24138-1-icheng@nvidia.com> (raw)
Add negative cases for the CXL fwctl Get Feature and Set Feature output
buffer bounds checks.
For Get Feature, request a non-zero payload while providing room only
for the fwctl_rpc_cxl_out header. Verify that the kernel rejects the
request with -EINVAL instead of writing past the rpc_out buffer.
For Set Feature, build a valid request and set out_len to zero. Verify
that the kernel rejects it with -EINVAL. Without the bounds check,
kvzalloc(0) returns ZERO_SIZE_PTR and the output header write can oops
the kernel.
Both cases depend on fixes [1]. Gate the tests on the running kernel
version so older kernels skip the unsafe requests rather than failing
the fwctl test.
[1]: https://lore.kernel.org/all/20260624134737.49166-1-icheng@nvidia.com/
Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
Changelog:
v1->v2:
- Gate the fix-dependent regression cases on kernel v7.3
- Add Set Feature out_len == 0 rejection coverage
- Group both cases behind one local kernel-version check
Best regards,
Richard Cheng.
---
test/fwctl.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 144 insertions(+)
diff --git a/test/fwctl.c b/test/fwctl.c
index 979c1a6..fb0d1da 100644
--- a/test/fwctl.c
+++ b/test/fwctl.c
@@ -5,10 +5,13 @@
#include <stdio.h>
#include <endian.h>
#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
+#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <cxl/libcxl.h>
#include <linux/uuid.h>
@@ -20,6 +23,35 @@
static const char provider[] = "cxl_test";
+/* Running kernel version parsed once in main(). */
+static unsigned int kver_major;
+static unsigned int kver_minor;
+
+/*
+ * kver_ge - Whether the running kernel at least major.minor
+ *
+ * Test cases for fixes tied to a specific kver gate here so that they quietly
+ * skip rather than fail on kernels that predate the fix.
+ */
+static bool kver_ge(unsigned int major, unsigned int minor)
+{
+ if (kver_major != major)
+ return kver_major > major;
+ return kver_minor >= minor;
+}
+
+static void parse_kver(void)
+{
+ struct utsname uts;
+
+ if (uname(&uts) == 0 &&
+ sscanf(uts.release, "%u.%u", &kver_major, &kver_minor) == 2)
+ return;
+
+ kver_major = 0;
+ kver_minor = 0;
+}
+
UUID_DEFINE(test_uuid,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
@@ -207,6 +239,45 @@ out:
return rc;
}
+static int cxl_fwctl_rpc_get_feature_oob(int fd, struct test_feature *feat_ctx)
+{
+ struct cxl_mbox_get_feat_in *feat_in;
+ struct fwctl_rpc_cxl_out *out;
+ size_t out_size, in_size;
+ struct fwctl_rpc_cxl *in;
+ struct fwctl_rpc *rpc;
+ int rc;
+
+ in_size = sizeof(*in) + sizeof(*feat_in);
+ /* header only => zero payload room */
+ out_size = offsetof(struct fwctl_rpc_cxl_out, payload);
+
+ rpc = get_prepped_command(in_size, out_size,
+ CXL_MBOX_OPCODE_GET_FEATURE);
+ if (!rpc)
+ return -ENXIO;
+
+ in = (struct fwctl_rpc_cxl *)rpc->in;
+ out = (struct fwctl_rpc_cxl_out *)rpc->out;
+
+ feat_in = &in->get_feat_in;
+ uuid_copy(feat_in->uuid, feat_ctx->uuid);
+ /* non-zero count that exceeds the zero payload room */
+ feat_in->count = feat_ctx->get_size;
+
+ rc = send_command(fd, rpc, out);
+ free_rpc(rpc);
+
+ if (rc == -EINVAL)
+ return 0;
+ if (rc == 0) {
+ fprintf(stderr, "Get Feature with undersized out_len was not rejected\n");
+ return -ENXIO;
+ }
+ fprintf(stderr, "Get Feature OOB rejection test: unexpected rc %d\n", rc);
+ return rc;
+}
+
static int cxl_fwctl_rpc_set_test_feature(int fd, struct test_feature *feat_ctx)
{
struct cxl_mbox_set_feat_in *feat_in;
@@ -249,6 +320,73 @@ out:
return rc;
}
+static int cxl_fwctl_rpc_set_feature_oob(int fd, struct test_feature *feat_ctx)
+{
+ struct cxl_mbox_set_feat_in *feat_in;
+ struct fwctl_rpc_cxl_out *out;
+ size_t in_size, out_size;
+ struct fwctl_rpc_cxl *in;
+ struct fwctl_rpc *rpc;
+ uint32_t val;
+ void *data;
+ int rc;
+
+ in_size = sizeof(*in) + sizeof(*feat_in) + sizeof(val);
+ out_size = sizeof(*out) + sizeof(val);
+ rpc = get_prepped_command(in_size, out_size,
+ CXL_MBOX_OPCODE_SET_FEATURE);
+ if (!rpc)
+ return -ENXIO;
+
+ in = (struct fwctl_rpc_cxl *)rpc->in;
+ out = (struct fwctl_rpc_cxl_out *)rpc->out;
+ feat_in = &in->set_feat_in;
+ uuid_copy(feat_in->uuid, feat_ctx->uuid);
+ data = feat_in->feat_data;
+ val = DEFAULT_TEST_DATA2;
+ *(uint32_t *)data = htole32(val);
+ feat_in->flags = CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER;
+
+ /* A valid Set Feature request with no room for the output header */
+ rpc->out_len = 0;
+ rc = send_command(fd, rpc, out);
+ free_rpc(rpc);
+
+ if (rc == -EINVAL)
+ return 0;
+ if (rc == 0) {
+ fprintf(stderr,
+ "Set Feature with zero out_len was not rejected\n");
+ return -ENXIO;
+ }
+ fprintf(stderr,
+ "Set Feature OOB rejection test: unexpected rc %d\n", rc);
+ return rc;
+}
+
+static int cxl_fwctl_rpc_feature_oob_tests(int fd,
+ struct test_feature *feat_ctx)
+{
+ int rc;
+
+ if (!kver_ge(7, 3)) {
+ fprintf(stderr,
+ "skip: Feature OOB rejection tests need kernel >= 7.3\n");
+ return 0;
+ }
+
+ rc = cxl_fwctl_rpc_get_feature_oob(fd, feat_ctx);
+ if (rc) {
+ fprintf(stderr, "Failed Get Feature OOB rejection test: %d\n", rc);
+ return rc;
+ }
+
+ rc = cxl_fwctl_rpc_set_feature_oob(fd, feat_ctx);
+ if (rc)
+ fprintf(stderr, "Failed Set Feature OOB rejection test: %d\n", rc);
+ return rc;
+}
+
static int cxl_fwctl_rpc_get_supported_features(int fd, struct test_feature *feat_ctx)
{
struct cxl_mbox_get_sup_feats_out *feat_out;
@@ -393,6 +531,10 @@ static int test_fwctl_features(struct cxl_memdev *memdev)
goto out;
}
+ rc = cxl_fwctl_rpc_feature_oob_tests(fd, &feat_ctx);
+ if (rc)
+ goto out;
+
out:
close(fd);
return rc;
@@ -417,6 +559,8 @@ int main(int argc, char *argv[])
struct cxl_bus *bus;
int rc;
+ parse_kver();
+
rc = cxl_new(&ctx);
if (rc < 0)
return rc;
--
2.43.0
next reply other threads:[~2026-07-21 6:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-21 6:21 Richard Cheng [this message]
2026-07-22 0:19 ` [ndctl PATCH v2] test/fwctl: Add Feature OOB rejection regression tests Alison Schofield
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=20260721062122.24138-1-icheng@nvidia.com \
--to=icheng@nvidia.com \
--cc=alison.schofield@intel.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=djbw@kernel.org \
--cc=gourry@gourry.net \
--cc=iweiny@kernel.org \
--cc=jic23@kernel.org \
--cc=kaihengf@nvidia.com \
--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=rrichter@amd.com \
--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.