[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