readdir-rand: Copy full size of struct dirent
authorSimon McVittie <smcv@collabora.com>
Fri, 28 Oct 2022 11:21:29 +0000 (12:21 +0100)
committerSimon McVittie <smcv@collabora.com>
Fri, 28 Oct 2022 11:21:58 +0000 (12:21 +0100)
As noted in readdir(3), in the presence of long filenames it is
possible for a directory entry to be larger than `sizeof (struct dirent)`.
Copy the full length instead.

Signed-off-by: Simon McVittie <smcv@collabora.com>
tests/readdir-rand.c

index f5d31ffbc9c43c1201c6129973ee58a0ddeb28ab..cd3b3b0994e913b97fa744ce0f4ee71e30c3ad31 100644 (file)
 # define READDIR_R "readdir_r"
 #endif
 
+/*
+ * copy_dirent:
+ * @other: Another struct dirent
+ *
+ * Returns: a copy of @other. Free with g_free().
+ */
+static struct dirent *
+copy_dirent (const struct dirent *other)
+{
+  struct dirent *self;
+  size_t len;
+
+  /* We can't just use sizeof (struct dirent) for the length to copy,
+   * because filenames are allowed to be longer than NAME_MAX bytes. */
+  len = G_STRUCT_OFFSET (struct dirent, d_name) + strlen (other->d_name) + 1;
+
+  if (len < other->d_reclen)
+    len = other->d_reclen;
+
+  if (len < sizeof (struct dirent))
+    len = sizeof (struct dirent);
+
+  self = g_malloc0 (len);
+  memcpy (self, other, len);
+  return self;
+}
+
 static GHashTable *direntcache;
 static GMutex direntcache_lock;
 static gsize initialized;
@@ -114,7 +141,7 @@ readdir (DIR *dirp)
                   de = dir_entries_new ();
                   g_hash_table_insert (direntcache, dirp, de);
                 }
-              copy = g_memdup (ret, sizeof (struct dirent));
+              copy = copy_dirent (ret);
               g_ptr_array_add (de->entries, copy);
             }
           else