[Python-bugs-list] PRIVATE: Tempfile module security issue (w/patch) (PR#304)

chrism@digicool.com chrism@digicool.com
Sun, 23 Apr 2000 01:51:24 -0400 (EDT)


Full_Name: Chris McDonough
Version: CVS
OS: All
Submission from: 208-58-241-97.s605.tnt1.atnnj.pa.dialup.rcn.com (208.58.241.97)


Folks,

Hi.  I've included a patch that I believe improves the security of the tempfile
module.  I'm using the web submission form instead of patches@python.org
because I'm not sure if the list that patches gets sent to isn't public, and
this is a security-related fix.

Currently, on a posix platform, the module chooses a temp directory by finding
the first of a few potential temp directories by trying to write to a file
inside the temp directory that is named "@[PID].test" (e.g. "@8907.test"). 
It opens this file, writes out the string "blat" to it, and unlinks it.  If
it's successful, it uses that temp directory for further writing of tempfiles.
Unfortunately, the test file isn't opened in a safe mode and follows symlinks. 
A symlink contained in Python's chosen temp directory,
named properly, can cause Python to overwrite any process-writable file with
the "blat" string.  I've modified the module to test for a writable directory
in much the same way the actual tempfile is created (using O_CREAT and O_EXCL)
when the test is invoked on a posix platform.  If the test is not invoked on a
posix platform, the old method of testing is used.

The included patch is against the CVS tempfile module:

*** tempfile.py	Sun Apr 23 00:55:34 2000
--- newtempfile.py	Sun Apr 23 01:02:22 2000
***************
*** 42,54 ****
      testfile = gettempprefix() + 'test'
      for dir in attempdirs:
          try:
!             filename = os.path.join(dir, testfile)
!             fp = open(filename, 'w')
!             fp.write('blat')
!             fp.close()
!             os.unlink(filename)
!             tempdir = dir
!             break
          except IOError:
              pass
      if tempdir is None:
--- 42,69 ----
      testfile = gettempprefix() + 'test'
      for dir in attempdirs:
          try:
!            filename = os.path.join(dir, testfile)
!            if os.name == 'posix':
!                try:
!                    fd = os.open(filename, os.O_RDWR|os.O_CREAT|os.O_EXCL,
!                                  0700)
!                except OSError:
!                    pass
!                else:
!                    fp = os.fdopen(fd, 'w')
!                    fp.write('blat')
!                    fp.close()
!                    os.unlink(filename)
!                    del fp, fd
!                    tempdir = dir
!                    break
!            else:
!                fp = open(filename, 'w')
!                fp.write('blat')
!                fp.close()
!                os.unlink(filename)
!                tempdir = dir
!                break
          except IOError:
              pass
      if tempdir is None:


I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under
copyright, patent or other rights or interests ("claims").  To
the extent that I have any such claims, I hereby grant to CNRI a
nonexclusive, irrevocable, royalty-free, worldwide license to
reproduce, distribute, perform and/or display publicly, prepare
derivative versions, and otherwise use this contribution as part
of the Python software and its related documentation, or any
derivative versions thereof, at no cost to CNRI or its licensed
users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide
whether or not to incorporate this contribution in the Python
software and its related documentation.  I further grant CNRI
permission to use my name and other identifying information
provided to CNRI by me for use in connection with the Python
software and its related documentation.

Thanks!

Chris McDonough
Digital Creations
Publishers of Zope - http://www.zope.org