bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fixed obscure mkdir, mkfifo, mknod permissions problem


From: Paul Eggert
Subject: fixed obscure mkdir, mkfifo, mknod permissions problem
Date: Fri, 22 Apr 2005 17:07:32 -0700

In a few obscure instances mkdir, mkfifo, and mknod create files with
incorrect permissions.  For example:

   $ umask 027
   $ mkdir -m =+x a
   $ ls -ld a
   d--x--x--x  2 eggert eggert 4096 Apr 22 17:03 a

The permissions are wrong here.  They should be d--x--x---.
I verified that Solaris 8 conforms to POSIX, so it's pretty clear that
this is a bug.

I installed the following patch.

I see no need for the second argument for mode_compile any more; all
programs that I know of assume that it's MODE_MASK_ALL, with the
exception of "install" where the value of that argument is immaterial
since "install" runs with umask(0).  So I'm inclined to remove the
second argument, since I think its presence contributed to this
permissions bug.  I'll ask about this on bug-gnulib first, though.

2005-04-22  Paul Eggert  <address@hidden>

        * NEWS: Fix bug with "mkdir -m =+x dir"; the umask was being ignored
        when the "+x" was being evaluated.
        * mkdir.c (main): Compile mode with MODE_MASK_ALL and initial umask.
        * mkfifo.c (main): Likewise.
        * mknod.c (main): Likewise.
        * tests/mkdir/perm: Test for the above bug.

Index: NEWS
===================================================================
RCS file: /fetish/cu/NEWS,v
retrieving revision 1.276
diff -p -u -r1.276 NEWS
--- NEWS        9 Apr 2005 04:51:11 -0000       1.276
+++ NEWS        22 Apr 2005 23:50:46 -0000
@@ -44,6 +44,9 @@ GNU coreutils NEWS                      
   ls now refuses to generate time stamps containing more than 1000 bytes, to
   foil potential denial-of-service attacks on hosts with very large stacks.
 
+  "mkdir -m =+x dir" no longer ignores the umask when evaluating "+x",
+  and similarly for mkfifo and mknod.
+
   "pr -D FORMAT" now accepts the same formats that "date +FORMAT" does.
 
   test now detects integer overflow when evaluating large integers,
Index: src/mkdir.c
===================================================================
RCS file: /fetish/cu/src/mkdir.c,v
retrieving revision 1.91
diff -p -u -r1.91 mkdir.c
--- src/mkdir.c 21 Sep 2004 22:26:42 -0000      1.91
+++ src/mkdir.c 22 Apr 2005 23:50:53 -0000
@@ -82,7 +82,7 @@ int
 main (int argc, char **argv)
 {
   mode_t newmode;
-  mode_t parent_mode;
+  mode_t parent_mode IF_LINT (= 0);
   const char *specified_mode = NULL;
   const char *verbose_fmt_string = NULL;
   int exit_status = EXIT_SUCCESS;
@@ -125,16 +125,9 @@ main (int argc, char **argv)
     }
 
   newmode = S_IRWXUGO;
-  {
-    mode_t umask_value = umask (0);
-    umask (umask_value);               /* Restore the old value. */
-    parent_mode = (newmode & (~ umask_value)) | S_IWUSR | S_IXUSR;
-  }
-
   if (specified_mode)
     {
-      struct mode_change *change = mode_compile (specified_mode, 0);
-      newmode &= ~ umask (0);
+      struct mode_change *change = mode_compile (specified_mode, 
MODE_MASK_ALL);
       if (change == MODE_INVALID)
        error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
       else if (change == MODE_MEMORY_EXHAUSTED)
@@ -142,6 +135,14 @@ main (int argc, char **argv)
       newmode = mode_adjust (newmode, change);
     }
 
+  if (specified_mode || create_parents)
+    {
+      mode_t umask_value = umask (0);
+      if (! specified_mode)
+       umask (umask_value);
+      parent_mode = (S_IRWXUGO & ~umask_value) | (S_IWUSR | S_IXUSR);
+    }
+
   for (; optind < argc; ++optind)
     {
       bool ok;
Index: src/mkfifo.c
===================================================================
RCS file: /fetish/cu/src/mkfifo.c,v
retrieving revision 1.73
diff -p -u -r1.73 mkfifo.c
--- src/mkfifo.c        21 Sep 2004 22:26:42 -0000      1.73
+++ src/mkfifo.c        22 Apr 2005 23:50:53 -0000
@@ -116,13 +116,13 @@ main (int argc, char **argv)
   newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
   if (specified_mode)
     {
-      newmode &= ~ umask (0);
-      change = mode_compile (specified_mode, 0);
+      change = mode_compile (specified_mode, MODE_MASK_ALL);
       if (change == MODE_INVALID)
        error (EXIT_FAILURE, 0, _("invalid mode"));
       else if (change == MODE_MEMORY_EXHAUSTED)
        xalloc_die ();
       newmode = mode_adjust (newmode, change);
+      umask (0);
     }
 
   for (; optind < argc; ++optind)
Index: src/mknod.c
===================================================================
RCS file: /fetish/cu/src/mknod.c,v
retrieving revision 1.84
diff -p -u -r1.84 mknod.c
--- src/mknod.c 21 Sep 2004 22:26:42 -0000      1.84
+++ src/mknod.c 22 Apr 2005 23:50:53 -0000
@@ -121,13 +121,13 @@ main (int argc, char **argv)
   newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
   if (specified_mode)
     {
-      newmode &= ~ umask (0);
-      change = mode_compile (specified_mode, 0);
+      change = mode_compile (specified_mode, MODE_MASK_ALL);
       if (change == MODE_INVALID)
        error (EXIT_FAILURE, 0, _("invalid mode"));
       else if (change == MODE_MEMORY_EXHAUSTED)
        xalloc_die ();
       newmode = mode_adjust (newmode, change);
+      umask (0);
     }
 
   /* If the number of arguments is 0 or 1,
Index: tests/mkdir/perm
===================================================================
RCS file: /fetish/cu/tests/mkdir/perm,v
retrieving revision 1.15
diff -p -u -r1.15 perm
--- tests/mkdir/perm    23 Jun 2004 15:07:04 -0000      1.15
+++ tests/mkdir/perm    22 Apr 2005 23:50:55 -0000
@@ -41,6 +41,7 @@ tests='
     050  :   -m 312   : drwx-w-rwx : d-wx--x-w- :
     160  :   empty    : drwx--xrwx : drw---xrwx :
     160  :   -m 743   : drwx--xrwx : drwxr---wx :
+    027  :   -m =+x   : drwxr-x--- : d--x--x--- :
     -    :   -        : last       : last       :
     '
 for p in empty -p; do




reply via email to

[Prev in Thread] Current Thread [Next in Thread]