tests/9pfs: add deep absolute path test
Add fs_deep_absolute_path test that creates a deep directory structure with an absolute path length exceeding 16-bit range (i.e. >65536) to verify the previous buffer overflow fix. This is a slow test (may take several seconds) and therefore registered as "slow" test and not running by default. Use -m slow to run this test. Link: https://gitlab.com/qemu-project/qemu/-/issues/3358 Link: https://lore.kernel.org/qemu-devel/933552b2cfc2c442fac7f4e68c777dce20ee8d7e.1779126034.git.qemu_oss@crudebyte.com Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Christian Schoenebeck committed
May 18, 2026 at 19:36 UTC
198627807a6b94e2aab157cf345f98edb1ac1a7a
1 file changed
+69
tests/qtest/virtio-9p-test.c
+69
@@ -14,6 +14,7 @@
14
15
#include "qemu/osdep.h"
16
#include "qemu/module.h"
17
+#include "libqos/virtio.h"
18
#include "libqos/virtio-9p-client.h"
19
20
#define twalk(...) v9fs_twalk((TWalkOpt) __VA_ARGS__)
@@ -752,6 +753,72 @@ static void fs_use_after_unlink(void *obj, void *data,
753
g_assert_cmpint(attr.size, ==, 2001);
754
}
755
756
+/* https://gitlab.com/qemu-project/qemu/-/issues/3358 */
757
+static void fs_deep_absolute_path(void *obj, void *data,
758
+ QGuestAllocator *t_alloc)
759
+{
760
+ QVirtio9P *v9p = obj;
761
+ v9fs_set_allocator(t_alloc);
762
+
763
+ if (!g_test_slow()) {
764
+ g_test_skip("This is a slow test, run with -m slow");
765
+ return;
766
+ }
767
+
768
+ GString *path = g_string_new("/");
769
+ char name[256];
770
+ uint32_t current_fid = 0;
771
+
772
+ tattach({ .client = v9p });
773
+
774
+ /* Create deep directory structure until absolute path length
775
+ * exceeds 16-bit range.
776
+ */
777
+ while (path->len <= 65536) {
778
+ /* use 255-byte name (NAME_MAX) to reduce iterations to ~257 */
779
+ memset(name, 'A', 255);
780
+ name[255] = '\0';
781
+
782
+ /* create the directory relative to current FID */
783
+ tmkdir({
784
+ .client = v9p,
785
+ .dfid = current_fid,
786
+ .name = name
787
+ });
788
+
789
+ /* just for locally tracking the current path length */
790
+ g_string_append(path, name);
791
+ g_string_append(path, "/");
792
+
793
+ /* acquire new FID for the newly created directory */
794
+ char *wnames[] = { name };
795
+ current_fid = twalk({
796
+ .client = v9p,
797
+ .fid = current_fid,
798
+ .nwname = 1,
799
+ .wnames = wnames
800
+ }).newfid;
801
+
802
+ /* Reset descriptor pool to avoid exhaustion. The simplified
803
+ * virtio test driver does never free descriptors back to the pool
804
+ * after use, so we must manually reset it for the required high
805
+ * amount of 9p requests here.
806
+ */
807
+ qvirtqueue_reset_pool(v9p->vq);
808
+ }
809
+
810
+ /* check if the deepest directory is accessible */
811
+ v9fs_attr attr = {};
812
+ tgetattr({
813
+ .client = v9p,
814
+ .fid = current_fid,
815
+ .request_mask = P9_GETATTR_BASIC,
816
+ .rgetattr.attr = &attr
817
+ });
818
+
819
+ g_string_free(path, TRUE);
820
+}
821
+
822
static void cleanup_9p_local_driver(void *data)
823
{
824
/* remove previously created test dir when test is completed */
@@ -819,6 +886,8 @@ static void register_virtio_9p_test(void)
886
&opts);
887
qos_add_test("local/use_after_unlink", "virtio-9p", fs_use_after_unlink,
888
&opts);
889
+ qos_add_test("local/deep_absolute_path", "virtio-9p",
890
+ fs_deep_absolute_path, &opts);
891
}
892
893
libqos_init(register_virtio_9p_test);