[Patch]: NUL and other special names

Pierre A. Humblet pierre@phumblet.no-ip.org
Mon May 31 22:49:00 GMT 2004


This patch prevents NtCreateFile from creating files with special
names such as NUL.
Because this needs to be checked very often, I tried to code it
efficiently with a binary search (it can perhaps be reused elsewhere). 

The new function is_special_name() overlaps with special_name(),
although there are small differences (it was designed from tests
on XP Home Ed). Perhaps these two can be merged one day.

Pierre

2004-05-31  Pierre Humblet <pierre.humblet@ieee.org>

	* winsup.h: Declare DIM macro.
	(find_in_list): Declare function.
	* miscfunc.c (find_in_list): New function.
	* path.cc (is_special_name): New function.
	(path_conv::check): Call is_special_name.
-------------- next part --------------
Index: winsup.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/winsup.h,v
retrieving revision 1.147
diff -u -p -r1.147 winsup.h
--- winsup.h	17 May 2004 15:27:56 -0000	1.147
+++ winsup.h	31 May 2004 22:33:56 -0000
@@ -29,6 +29,7 @@ details. */
 # define memset __builtin_memset
 #endif

+#define DIM(x) (sizeof (x) / sizeof ((x)[0]))
 #define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
 #define NO_COPY_INIT __attribute__((section(".data_cygwin_nocopy")))

@@ -245,10 +246,16 @@ void __stdcall nofinalslash (const char
 extern "C" char *__stdcall rootdir (const char *full_path, char *root_path) __attribute__ ((regparm(2)));

 /* String manipulation */
+typedef struct {
+  const unsigned char length;
+  const char * name;
+} name_list;
+
 extern "C" char *__stdcall strccpy (char *s1, const char **s2, char c);
 extern "C" int __stdcall strcasematch (const char *s1, const char *s2) __attribute__ ((regparm(2)));
 extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3)));
 extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2)));
+extern int find_in_list (const char *, const name_list *, int);

 /* Time related */
 void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag);
Index: miscfuncs.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/miscfuncs.cc,v
retrieving revision 1.30
diff -u -p -r1.30 miscfuncs.cc
--- miscfuncs.cc	26 Feb 2004 11:32:20 -0000	1.30
+++ miscfuncs.cc	31 May 2004 22:33:57 -0000
@@ -144,6 +144,26 @@ strcasestr (const char *searchee, const
   return NULL;
 }

+/* Return TRUE if find name in name_list */
+int
+find_in_list (const char * name, const name_list * list, int dim)
+{
+  int start = 0, end = dim - 1, curr, res;
+  do
+    {
+      curr = (start + end) / 2;
+      if (!(res = strncasecmp (name, list[curr].name, list[curr].length)))
+	return curr;
+      if (res < 0)
+	end = curr - 1;
+      else
+	start = curr + 1;
+    }
+  while (start <= end);
+  return -1;
+}
+
+
 int __stdcall
 check_null_str (const char *name)
 {
Index: path.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/path.cc,v
retrieving revision 1.314
diff -u -p -r1.314 path.cc
--- path.cc	31 May 2004 02:20:39 -0000	1.314
+++ path.cc	31 May 2004 22:34:03 -0000
@@ -482,6 +482,61 @@ path_conv::get_nt_native_path (UNICODE_S
   return &upath;
 }

+/* Keep sorted */
+const name_list special_names[] = {
+  {3, "AUX"},
+  {7, "CLOCK$"}, /* Include final 0 */
+  {3, "COM"},
+  {3, "CON"},
+  {3, "LPT"},
+  {3, "NUL"},
+  {3, "PRN"}
+};
+
+static bool
+is_special_name (const char * name)
+{
+  bool res = false;
+  const char *currptr;
+  int pos;
+
+  if ((currptr = strrchr (name, '\\'))
+      && (pos = find_in_list (++currptr, special_names, DIM (special_names))) >= 0
+      && !strncasematch (name, "\\\\.\\", 4))
+    {
+      currptr += special_names[pos].length;
+      switch (pos)
+        {
+	  /* CLOCK$ must match exactly. */
+	case 1:
+	  res = true;
+	  break;
+	  /* COM and LPT must be followed by a single digit */
+	case 2:
+	case 4:
+	  res = *currptr >= '0' && *currptr <= '9' && currptr[1] == '\0';
+	  break;
+	  /* CON */
+	case 3:
+	  /* CONIN$ and CONOUT$ must match exactly */
+	  if (!strcasecmp (currptr, "IN$")
+	      || !strcasecmp (currptr, "OUT$"))
+	    {
+	      res = true;
+	      break;
+	    }
+	  /* Fall through */
+	  /* Others can have an arbitray extension */
+	default:
+	  res = *currptr == '\0' || *currptr == '.';
+	  break;
+	}
+    }
+
+  debug_printf ("%d = is_special_name (%s)", res, name);
+  return res;
+}
+
 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
    passing to Win32 API routines.

@@ -837,6 +892,13 @@ out:

   if (dev.devn == FH_FS)
     {
+      /* Check if the file is special */
+      if (wincap.is_winnt () && pcheck_case != PCHECK_STRICT
+	  && is_special_name (this->path))
+        {
+	  error = ENOENT;
+	  return;
+	}
       if (fs.update (path))
 	{
 	  set_isdisk ();


More information about the Cygwin-patches mailing list