CVE-2014-1933: Permissions, Privileges, and Access Controls (CWE-264)
value: The (1) JpegImagePlugin.py and (2) EpsImagePlugin.py scripts in Python Image Library (PIL) 1.1.7 and earlier and Pillow before 2.3.1 uses the names of temporary files on the command line, which makes it easier for local users to conduct symlink attacks by listing the processes.
CWE description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.
Published: 2014-04-17T14:55Z
Repository: https://github.com/python-imaging/Pillow
Language: Python
Files changed: PIL/EpsImagePlugin.py, PIL/Image.py, PIL/IptcImagePlugin.py, PIL/JpegImagePlugin.py
Commit date: 2014-03-14 16:40:45 -0700
Commit message: Removed tempfile.mktemp, fixes CVE-2014-1932 CVE-2014-1933, debian bug #737059

Diff: diff --git a/PIL/EpsImagePlugin.py b/PIL/EpsImagePlugin.py
index a8706b0..fcfae8a 100644
--- a/PIL/EpsImagePlugin.py
+++ b/PIL/EpsImagePlugin.py
@@ -65,11 +65,12 @@ def Ghostscript(tile, size, fp, scale=1):
     bbox = [bbox[0], bbox[1], bbox[2] * scale, bbox[3] * scale]
     #print("Ghostscript", scale, size, orig_size, bbox, orig_bbox)
 
     import tempfile, os, subprocess
 
-    file = tempfile.mktemp()
+    out_fd, file = tempfile.mkstemp()
+    os.close(out_fd)
 
     # Build ghostscript command
     command = ["gs",
                "-q",                    # quite mode
                "-g%dx%d" % size,        # set output geometry (pixels)
diff --git a/PIL/Image.py b/PIL/Image.py
index 87631d6..915f5b1 100644
--- a/PIL/Image.py
+++ b/PIL/Image.py
@@ -493,18 +493,21 @@ class Image:
         self.load()
         self.im = self.im.copy()
         self.readonly = 0
 
     def _dump(self, file=None, format=None):
-        import tempfile
+        import tempfile, os
         if not file:
-            file = tempfile.mktemp()
+            f, file = tempfile.mkstemp(format or '')
+            os.close(f)
+            
         self.load()
         if not format or format == "PPM":
             self.im.save_ppm(file)
         else:
-            file = file + "." + format
+            if file.endswith(format):
+                file = file + "." + format
             self.save(file, format)
         return file
 
     def __repr__(self):
         return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
diff --git a/PIL/IptcImagePlugin.py b/PIL/IptcImagePlugin.py
index 157b735..1041530 100644
--- a/PIL/IptcImagePlugin.py
+++ b/PIL/IptcImagePlugin.py
@@ -170,12 +170,12 @@ class IptcImageFile(ImageFile.ImageFile):
         encoding, offset = tile
 
         self.fp.seek(offset)
 
         # Copy image data to temporary file
-        outfile = tempfile.mktemp()
-        o = open(outfile, "wb")
+        o_fd, outfile = tempfile.mkstemp(text=False)
+        o = os.fdopen(o_fd)
         if encoding == "raw":
             # To simplify access to the extracted file,
             # prepend a PPM header
             o.write("P5\n%d %d\n255\n" % self.size)
         while True:
diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py
index 90d3b51..67dc5ba 100644
--- a/PIL/JpegImagePlugin.py
+++ b/PIL/JpegImagePlugin.py
@@ -342,17 +342,21 @@ class JpegImageFile(ImageFile.ImageFile):
     def load_djpeg(self):
 
         # ALTERNATIVE: handle JPEGs via the IJG command line utilities
 
         import tempfile, os
-        file = tempfile.mktemp()
-        os.system("djpeg %s >%s" % (self.filename, file))
+        f, path = tempfile.mkstemp()
+        os.close(f)
+        if os.path.exists(self.filename):
+            os.system("djpeg '%s' >'%s'" % (self.filename, path))
+        else:
+            raise ValueError("Invalid Filename")
 
         try:
-            self.im = Image.core.open_ppm(file)
+            self.im = Image.core.open_ppm(path)
         finally:
-            try: os.unlink(file)
+            try: os.unlink(path)
             except: pass
 
         self.mode = self.im.mode
         self.size = self.im.size
 

Vulnerable code:     file = tempfile.mktemp()
        import tempfile
            file = tempfile.mktemp()
            file = file + "." + format
        outfile = tempfile.mktemp()
        o = open(outfile, "wb")
        file = tempfile.mktemp()
        os.system("djpeg %s >%s" % (self.filename, file))
            self.im = Image.core.open_ppm(file)
            try: os.unlink(file)
Fixed code:     out_fd, file = tempfile.mkstemp()
    os.close(out_fd)
        import tempfile, os
            f, file = tempfile.mkstemp(format or '')
            os.close(f)
            
            if file.endswith(format):
                file = file + "." + format
        o_fd, outfile = tempfile.mkstemp(text=False)
        o = os.fdopen(o_fd)
        f, path = tempfile.mkstemp()
        os.close(f)
        if os.path.exists(self.filename):
            os.system("djpeg '%s' >'%s'" % (self.filename, path))
        else:
            raise ValueError("Invalid Filename")
            self.im = Image.core.open_ppm(path)
            try: os.unlink(path)