]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Security: CUPS could overwrite files as root in directories owned or writable by
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 16 Jun 2010 00:29:06 +0000 (00:29 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 16 Jun 2010 00:29:06 +0000 (00:29 +0000)
non-root users (STR #3510)

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@9149 7a7537e8-13f0-0310-91df-b6672ffda945

CHANGES-1.4.txt
cups/file.c

index 880f5f739ae08e79df2279052d647f7b32c9289f..f185aa595a2becb4f4562e515e46ab2073eac4d9 100644 (file)
@@ -13,6 +13,8 @@ CHANGES IN CUPS V1.4.4
          (STR #3516)
        - Security: The web admin interface could disclose the contents of
          memory (STR #3577)
+       - Security: CUPS could overwrite files as root in directories owned or
+         writable by non-root users (STR #3510)
        - Fixed some IPP conformance issues with the scheduler's
          ippget-event-life, operations-supported, output-bin, and sides
          attributes (STR #3554)
index 68535bcff399be5d9a356ed189589471e82731c9..d00a627127f0cadd9f95152d15167d833e93f329 100644 (file)
@@ -59,6 +59,7 @@
  */
 
 #include "file-private.h"
+#include <sys/stat.h>
 
 
 /*
@@ -69,6 +70,7 @@
 static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
 #endif /* HAVE_LIBZ */
 static ssize_t cups_fill(cups_file_t *fp);
+static int     cups_open(const char *filename, int mode);
 static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
 static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
 
@@ -827,7 +829,8 @@ cupsFileOpen(const char *filename,  /* I - Name of file */
   switch (*mode)
   {
     case 'a' : /* Append file */
-        fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
+        fd = cups_open(filename,
+                      O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY);
         break;
 
     case 'r' : /* Read file */
@@ -835,7 +838,17 @@ cupsFileOpen(const char *filename, /* I - Name of file */
        break;
 
     case 'w' : /* Write file */
-        fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
+        fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+       if (fd < 0 && errno == ENOENT)
+       {
+         fd = cups_open(filename,
+                        O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY);
+         if (fd < 0 && errno == EEXIST)
+           fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+       }
+
+       if (fd >= 0)
+         ftruncate(fd, 0);
         break;
 
     case 's' : /* Read/write socket */
@@ -2208,6 +2221,88 @@ cups_fill(cups_file_t *fp)               /* I - CUPS file */
 }
 
 
+/*
+ * 'cups_open()' - Safely open a file for writing.
+ *
+ * We don't allow appending to directories or files that are hard-linked or
+ * symlinked.
+ */
+
+static int                             /* O - File descriptor or -1 otherwise */
+cups_open(const char *filename,                /* I - Filename */
+         int        mode)              /* I - Open mode */
+{
+  int          fd;                     /* File descriptor */
+  struct stat  fileinfo;               /* File information */
+#ifndef WIN32
+  struct stat  linkinfo;               /* Link information */
+#endif /* !WIN32 */
+
+
+ /*
+  * Open the file...
+  */
+
+  if ((fd = open(filename, mode, 0666)) < 0)
+    return (-1);
+
+ /*
+  * Then verify that the file descriptor doesn't point to a directory or hard-
+  * linked file.
+  */
+
+  if (fstat(fd, &fileinfo))
+  {
+    close(fd);
+    return (-1);
+  }
+
+  if (fileinfo.st_nlink != 1)
+  {
+    close(fd);
+    errno = EPERM;
+    return (-1);
+  }
+
+  if (S_ISDIR(fileinfo.st_mode))
+  {
+    close(fd);
+    errno = EISDIR;
+    return (-1);
+  }
+
+#ifndef WIN32
+ /*
+  * Then use lstat to determine whether the filename is a symlink...
+  */
+
+  if (lstat(filename, &linkinfo))
+  {
+    close(fd);
+    return (-1);
+  }
+
+  if (S_ISLNK(linkinfo.st_mode) ||
+      fileinfo.st_dev != linkinfo.st_dev ||
+      fileinfo.st_ino != linkinfo.st_ino ||
+      fileinfo.st_gen != linkinfo.st_gen ||
+      fileinfo.st_nlink != linkinfo.st_nlink ||
+      fileinfo.st_mode != linkinfo.st_mode)
+  {
+   /*
+    * Yes, don't allow!
+    */
+
+    close(fd);
+    errno = EPERM;
+    return (-1);
+  }
+#endif /* !WIN32 */
+
+  return (fd);
+}
+
+
 /*
  * 'cups_read()' - Read from a file descriptor.
  */