[PATCH v2 3/3] test: dm: nfs: add regression tests for the NFS reply-length checks

Shahriyar Jalayeri <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <20260813-nfs-oob-fix-v2-3-80993770518e__19879.6222031646$1786636648$gmane$org@byteray.co.uk>
Add DM tests that feed nfs_pkt_recv() crafted NFSv3 replies with a read and
a readlink request outstanding. The READ reply carries a count with the top
bit set; the READLINK reply carries a length of -1 that slips past the
destination bound as pathlen - 1. Either would drive a memcpy() out of the
reply buffer; the tests assert that nothing is stored and the path buffer is
left untouched.

Enable CONFIG_CMD_NFS in sandbox_defconfig so the NFS client and these tests
are built and run under sandbox.

Signed-off-by: Shahriyar Jalayeri <[email protected]>
---
 configs/sandbox_defconfig |  1 +
 test/dm/Makefile          |  1 +
 test/dm/nfs.c             | 90 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 79f46317e45..ca73080b06d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -123,6 +123,7 @@ CONFIG_CMD_LINK_LOCAL=y
 CONFIG_IPV6_ROUTER_DISCOVERY=y
 CONFIG_CMD_ETHSW=y
 CONFIG_CMD_DNS=y
+CONFIG_CMD_NFS=y
 CONFIG_CMD_SNTP=y
 CONFIG_CMD_2048=y
 CONFIG_CMD_BMP=y
diff --git a/test/dm/Makefile b/test/dm/Makefile
index fb3e6a7008f..cc51fd33079 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
 obj-y += fdtdec.o
 obj-$(CONFIG_MTD_RAW_NAND) += nand.o
 obj-$(CONFIG_IP_DEFRAG) += net_defrag.o
+obj-$(CONFIG_CMD_NFS) += nfs.o
 obj-$(CONFIG_UT_DM) += nop.o
 obj-y += ofnode.o
 obj-y += ofread.o
diff --git a/test/dm/nfs.c b/test/dm/nfs.c
new file mode 100644
index 00000000000..c7ab1e912b8
--- /dev/null
+++ b/test/dm/nfs.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Regression tests for the NFS reply-length checks.
+ */
+
+#include <net.h>
+#include <string.h>
+#include <test/ut.h>
+#include <dm/test.h>
+#include "../../net/nfs-common.h"
+
+static int dm_test_nfs_read_oob(struct unit_test_state *uts)
+{
+	int saved_state = nfs_state;
+	unsigned long saved_id = rpc_id;
+	int saved_offset = nfs_offset;
+	enum nfs_version saved_version = choosen_nfs_version;
+	u32 saved_size = net_boot_file_size;
+	struct rpc_t reply;
+
+	/* Pretend a READ request is outstanding (NFSv3). */
+	choosen_nfs_version = NFS_V3;
+	nfs_state = STATE_READ_REQ;
+	nfs_offset = 0;
+	rpc_id = 0x11223344;
+	net_boot_file_size = 0;
+
+	/* Accepted reply, matching xid, READ status OK, no attributes, then a
+	 * count with the top bit set.
+	 */
+	memset(&reply, 0, sizeof(reply));
+	reply.u.reply.id = htonl((u32)rpc_id);
+	reply.u.reply.data[0] = 0;			/* nfsstat3: OK */
+	reply.u.reply.data[1] = 0;			/* attributes_follow: no */
+	reply.u.reply.data[2] = htonl(0x80000000);	/* count */
+
+	nfs_pkt_recv((uchar *)&reply.u.reply, sizeof(reply.u.reply));
+
+	/* Rejected: nothing stored. */
+	ut_asserteq(0, net_boot_file_size);
+
+	nfs_state = saved_state;
+	rpc_id = saved_id;
+	nfs_offset = saved_offset;
+	choosen_nfs_version = saved_version;
+	net_boot_file_size = saved_size;
+
+	return 0;
+}
+DM_TEST(dm_test_nfs_read_oob, 0);
+
+static int dm_test_nfs_readlink_oob(struct unit_test_state *uts)
+{
+	int saved_state = nfs_state;
+	unsigned long saved_id = rpc_id;
+	enum nfs_version saved_version = choosen_nfs_version;
+	char *saved_path = nfs_path;
+	struct rpc_t reply;
+
+	/* Pretend a READLINK request is outstanding (NFSv3). */
+	choosen_nfs_version = NFS_V3;
+	nfs_state = STATE_READLINK_REQ;
+	rpc_id = 0x11223344;
+	nfs_path = nfs_path_buff;
+	strcpy(nfs_path_buff, "dir");
+
+	/* Accepted reply, matching xid, READLINK status OK, no attributes, a
+	 * length of -1 that slips past the destination bound as pathlen - 1,
+	 * then a relative (non-'/') target.
+	 */
+	memset(&reply, 0, sizeof(reply));
+	reply.u.reply.id = htonl((u32)rpc_id);
+	reply.u.reply.data[0] = 0;			/* nfsstat3: OK */
+	reply.u.reply.data[1] = 0;			/* attributes_follow: no */
+	reply.u.reply.data[2] = htonl(0xffffffff);	/* symlink length -1 */
+	reply.u.reply.data[3] = htonl(0x61616161);	/* target, not '/' */
+
+	nfs_pkt_recv((uchar *)&reply.u.reply, sizeof(reply.u.reply));
+
+	/* Rejected: the path buffer is untouched. */
+	ut_asserteq_str("dir", nfs_path_buff);
+
+	nfs_state = saved_state;
+	rpc_id = saved_id;
+	choosen_nfs_version = saved_version;
+	nfs_path = saved_path;
+
+	return 0;
+}
+DM_TEST(dm_test_nfs_readlink_oob, 0);

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.