public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
From: Corinna Vinschen <corinna@sourceware.org>
To: cygwin-cvs@sourceware.org
Subject: [newlib-cygwin] Cygwin: fhandler_procsys::readdir: fix NtQueryDirectoryObject usage
Date: Thu, 19 Aug 2021 19:17:40 +0000 (GMT)	[thread overview]
Message-ID: <20210819191740.6538439B90AB@sourceware.org> (raw)

https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=5036d447c54c41968ccd19a6294f69e4085d0143

commit 5036d447c54c41968ccd19a6294f69e4085d0143
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Thu Aug 19 21:17:11 2021 +0200

    Cygwin: fhandler_procsys::readdir: fix NtQueryDirectoryObject usage
    
    As outlined in the previous patch, the non-atomicity of iterating
    over a directory in the NT namespace via NtQueryDirectoryObject
    one entry each, results in potential duplication of directory entries.
    
    Fix this for fhandler_procsys::readdir as well by fetching the entire
    dir inside fhandler_procsys::opendir, storing it in a buffer, and just
    return buffer content from fhandler_procsys::readdir.
    
    Fixes: 43f65cdd7dae ("fhandler_procsys.cc: New file.")
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/fhandler_procsys.cc | 82 +++++++++++++++++++++++++++------------
 1 file changed, 58 insertions(+), 24 deletions(-)

diff --git a/winsup/cygwin/fhandler_procsys.cc b/winsup/cygwin/fhandler_procsys.cc
index f8abbe7c0..02741d0e9 100644
--- a/winsup/cygwin/fhandler_procsys.cc
+++ b/winsup/cygwin/fhandler_procsys.cc
@@ -309,59 +309,88 @@ fhandler_procsys::opendir (int fd)
   UNICODE_STRING path;
   OBJECT_ATTRIBUTES attr;
   NTSTATUS status;
-  HANDLE h;
+  HANDLE dir_hdl;
   DIR *dir;
 
   mk_unicode_path (&path);
   InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
-  status = NtOpenDirectoryObject (&h, DIRECTORY_QUERY, &attr);
+  status = NtOpenDirectoryObject (&dir_hdl, DIRECTORY_QUERY, &attr);
   if (!NT_SUCCESS (status))
     {
       __seterrno_from_nt_status (status);
       return NULL;
     }
+
+  void *dbi_buf = NULL;
+  ULONG size = 65536;
+  ULONG context = 0;
+  int iter;
+  for (iter = 0; iter <= 3; ++iter)	/* Allows for a 512K buffer */
+    {
+      void *new_buf = realloc (dbi_buf, size);
+      if (!new_buf)
+	goto err;
+      dbi_buf = new_buf;
+      status = NtQueryDirectoryObject (dir_hdl, dbi_buf, size, FALSE, TRUE,
+				       &context, NULL);
+      if (!NT_SUCCESS (status))
+	{
+	  __seterrno_from_nt_status (status);
+	  goto err;
+	}
+      if (status != STATUS_MORE_ENTRIES)
+	break;
+      size <<= 1;
+    }
+  if (iter > 3)
+    {
+      __seterrno_from_nt_status (STATUS_INSUFFICIENT_RESOURCES);
+      goto err;
+    }
   if (!(dir = fhandler_virtual::opendir (fd)))
-    NtClose (h);
-  else
-    dir->__handle = h;
+    goto err;
+  /* Note that dir->__handle points to the buffer, it does NOT contain an
+     actual handle! */
+  dir->__handle = dbi_buf;
+  /* dir->__d_internal contains the number of objects returned in the buffer. */
+  dir->__d_internal = context;
   return dir;
+
+err:
+  NtClose (dir_hdl);
+  free (dbi_buf);
+  return NULL;
 }
 
 int
 fhandler_procsys::readdir (DIR *dir, dirent *de)
 {
-  NTSTATUS status;
-  struct fdbi
-  {
-    DIRECTORY_BASIC_INFORMATION dbi;
-    WCHAR buf[2][NAME_MAX + 1];
-  } f;
+  PDIRECTORY_BASIC_INFORMATION dbi;
   int res = EBADF;
 
   if (dir->__handle != INVALID_HANDLE_VALUE)
     {
-      BOOLEAN restart = dir->__d_position ? FALSE : TRUE;
-      status = NtQueryDirectoryObject (dir->__handle, &f, sizeof f, TRUE,
-				       restart, (PULONG) &dir->__d_position,
-				       NULL);
-      if (!NT_SUCCESS (status))
+      dbi = ((PDIRECTORY_BASIC_INFORMATION) dir->__handle);
+      dbi += dir->__d_position;
+      if (dir->__d_position >= (__int32_t) dir->__d_internal
+	  || dbi->ObjectName.Length == 0)
 	res = ENMFILE;
       else
 	{
-	  sys_wcstombs (de->d_name, NAME_MAX + 1, f.dbi.ObjectName.Buffer,
-			f.dbi.ObjectName.Length / sizeof (WCHAR));
+	  sys_wcstombs (de->d_name, NAME_MAX + 1, dbi->ObjectName.Buffer,
+			dbi->ObjectName.Length / sizeof (WCHAR));
 	  de->d_ino = hash_path_name (get_ino (), de->d_name);
-	  if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdir,
-				     FALSE))
+	  if (RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natdir, FALSE))
 	    de->d_type = DT_DIR;
-	  else if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natsyml,
+	  else if (RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natsyml,
 					  FALSE))
 	    de->d_type = DT_LNK;
-	  else if (!RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdev,
+	  else if (!RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natdev,
 					   FALSE))
 	    de->d_type = DT_CHR;
 	  else /* Can't nail down "Device" objects without further testing. */
 	    de->d_type = DT_UNKNOWN;
+	  ++dir->__d_position;
 	  res = 0;
 	}
     }
@@ -378,7 +407,12 @@ fhandler_procsys::telldir (DIR *dir)
 void
 fhandler_procsys::seekdir (DIR *dir, long pos)
 {
-  dir->__d_position = pos;
+  if (pos < 0)
+    dir->__d_position = 0;
+  else if (pos > (__int32_t) dir->__d_internal)
+    dir->__d_position = (__int32_t) dir->__d_internal;
+  else
+    dir->__d_position = pos;
 }
 
 int
@@ -386,7 +420,7 @@ fhandler_procsys::closedir (DIR *dir)
 {
   if (dir->__handle != INVALID_HANDLE_VALUE)
     {
-      NtClose (dir->__handle);
+      free (dir->__handle);
       dir->__handle = INVALID_HANDLE_VALUE;
     }
   return fhandler_virtual::closedir (dir);


                 reply	other threads:[~2021-08-19 19:17 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20210819191740.6538439B90AB@sourceware.org \
    --to=corinna@sourceware.org \
    --cc=cygwin-cvs@sourceware.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).