Fix security issue with Python 2.1/2.2

Zack Weinberg found a vulnerability in the way the exevpe() method
from the os.py module uses a temporary file name. A file which
supposedly should not exist is created in a unsafe way and the method
tries to execute it. The objective of such code is to discover what
error the operating system returns in a portable way.

By exploiting this vulnerability a local attacker can execute
arbitrary code with the privileges of the user running python code
which uses the execvpe() method.

http://python.org/sf/590294
http://python.org/sf/601077
This commit is contained in:
brad 2002-10-08 02:52:25 +00:00
parent 54ecef0709
commit 0da69615f6
9 changed files with 232 additions and 16 deletions

View File

@ -1,7 +1,8 @@
# $OpenBSD: Makefile,v 1.2 2002/04/19 12:19:30 matt Exp $
# $OpenBSD: Makefile,v 1.3 2002/10/08 02:52:25 brad Exp $
VERSION= 2.1
PATCHLEVEL= .3
PKG_PATCHLEVEL= p1
.include <bsd.port.mk>

View File

@ -0,0 +1,79 @@
$OpenBSD: patch-Lib_os_py,v 1.1 2002/10/08 02:52:25 brad Exp $
--- Lib/os.py.orig Mon Oct 7 21:55:08 2002
+++ Lib/os.py Mon Oct 7 21:55:31 2002
@@ -291,7 +291,7 @@ def execvp(file, args):
_execvpe(file, args)
def execvpe(file, args, env):
- """execv(file, args, env)
+ """execvpe(file, args, env)
Execute the executable file (which is searched for along $PATH)
with argument list args and environment env , replacing the
@@ -301,8 +301,9 @@ def execvpe(file, args, env):
__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
-_notfound = None
def _execvpe(file, args, env=None):
+ from errno import ENOENT, ENOTDIR
+
if env is not None:
func = execve
argrest = (args, env)
@@ -310,7 +311,7 @@ def _execvpe(file, args, env=None):
func = execv
argrest = (args,)
env = environ
- global _notfound
+
head, tail = path.split(file)
if head:
apply(func, (file,) + argrest)
@@ -320,30 +321,21 @@ def _execvpe(file, args, env=None):
else:
envpath = defpath
PATH = envpath.split(pathsep)
- if not _notfound:
- if sys.platform[:4] == 'beos':
- # Process handling (fork, wait) under BeOS (up to 5.0)
- # doesn't interoperate reliably with the thread interlocking
- # that happens during an import. The actual error we need
- # is the same on BeOS for posix.open() et al., ENOENT.
- try: unlink('/_#.# ## #.#')
- except error, _notfound: pass
- else:
- import tempfile
- t = tempfile.mktemp()
- # Exec a file that is guaranteed not to exist
- try: execv(t, ('blah',))
- except error, _notfound: pass
- exc, arg = error, _notfound
+ saved_exc = None
+ saved_tb = None
for dir in PATH:
fullname = path.join(dir, file)
try:
apply(func, (fullname,) + argrest)
- except error, (errno, msg):
- if errno != arg[0]:
- exc, arg = error, (errno, msg)
- raise exc, arg
-
+ except error, e:
+ tb = sys.exc_info()[2]
+ if (e.errno != ENOENT and e.errno != ENOTDIR
+ and saved_exc is None):
+ saved_exc = e
+ saved_tb = tb
+ if saved_exc:
+ raise error, saved_exc, saved_tb
+ raise error, e, tb
# Change environ to automatically call putenv() if it exists
try:
@@ -560,3 +552,4 @@ if _exists("fork"):
stdout, stdin = popen2.popen4(cmd, bufsize)
return stdin, stdout
__all__.append("popen4")
+

View File

@ -0,0 +1,19 @@
$OpenBSD: patch-Modules_Setup_dist,v 1.1 2002/10/08 02:52:25 brad Exp $
--- Modules/Setup.dist.orig Thu Mar 22 17:18:55 2001
+++ Modules/Setup.dist Mon Oct 7 21:51:07 2002
@@ -97,6 +97,7 @@ PYTHONPATH=$(COREPYTHONPATH)
# setup.py script in the root of the Python source tree.
posix posixmodule.c # posix (UNIX) system calls
+errno errnomodule.c # posix (UNIX) errno values
_sre _sre.c # Fredrik Lundh's new regular expressions
# The rest of the modules listed in this file are all commented out by
@@ -162,7 +163,6 @@ GLHACK=-Dclear=__GLclear
#fcntl fcntlmodule.c # fcntl(2) and ioctl(2)
#pwd pwdmodule.c # pwd(3)
#grp grpmodule.c # grp(3)
-#errno errnomodule.c # posix (UNIX) errno values
#select selectmodule.c # select(2); not on ancient System V
# Memory-mapped files (also works on Win32).

View File

@ -1,7 +1,16 @@
$OpenBSD: patch-setup_py,v 1.1 2002/02/15 19:42:18 matt Exp $
$OpenBSD: patch-setup_py,v 1.2 2002/10/08 02:52:25 brad Exp $
--- setup.py.orig Thu Dec 27 16:51:02 2001
+++ setup.py Mon Jan 14 12:09:08 2002
@@ -346,22 +346,9 @@ class PyBuildExt(build_ext):
+++ setup.py Mon Oct 7 21:52:44 2002
@@ -215,8 +215,6 @@ class PyBuildExt(build_ext):
exts.append( Extension('pwd', ['pwdmodule.c']) )
# grp(3)
exts.append( Extension('grp', ['grpmodule.c']) )
- # posix (UNIX) errno values
- exts.append( Extension('errno', ['errnomodule.c']) )
# select(2); not on ancient System V
exts.append( Extension('select', ['selectmodule.c']) )
@@ -346,22 +344,9 @@ class PyBuildExt(build_ext):
# (See http://electricrain.com/greg/python/bsddb3/ for an interface to
# BSD DB 3.x.)
@ -27,7 +36,7 @@ $OpenBSD: patch-setup_py,v 1.1 2002/02/15 19:42:18 matt Exp $
# The mpz module interfaces to the GNU Multiple Precision library.
# You need to ftp the GNU MP library.
@@ -609,7 +596,8 @@ def main():
@@ -609,7 +594,8 @@ def main():
ext_modules=[Extension('struct', ['structmodule.c'])],
# Scripts to install

View File

@ -1,7 +1,8 @@
# $OpenBSD: Makefile,v 1.2 2002/05/11 21:35:13 matt Exp $
# $OpenBSD: Makefile,v 1.3 2002/10/08 02:52:25 brad Exp $
VERSION= 2.2
PATCHLEVEL= .1
PKG_PATCHLEVEL= p1
.include <bsd.port.mk>

View File

@ -0,0 +1,79 @@
$OpenBSD: patch-Lib_os_py,v 1.1 2002/10/08 02:52:25 brad Exp $
--- Lib/os.py.orig Mon Oct 7 22:16:49 2002
+++ Lib/os.py Mon Oct 7 22:16:51 2002
@@ -298,7 +298,7 @@ def execvp(file, args):
_execvpe(file, args)
def execvpe(file, args, env):
- """execv(file, args, env)
+ """execvpe(file, args, env)
Execute the executable file (which is searched for along $PATH)
with argument list args and environment env , replacing the
@@ -308,8 +308,9 @@ def execvpe(file, args, env):
__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
-_notfound = None
def _execvpe(file, args, env=None):
+ from errno import ENOENT, ENOTDIR
+
if env is not None:
func = execve
argrest = (args, env)
@@ -317,7 +318,7 @@ def _execvpe(file, args, env=None):
func = execv
argrest = (args,)
env = environ
- global _notfound
+
head, tail = path.split(file)
if head:
apply(func, (file,) + argrest)
@@ -327,30 +328,21 @@ def _execvpe(file, args, env=None):
else:
envpath = defpath
PATH = envpath.split(pathsep)
- if not _notfound:
- if sys.platform[:4] == 'beos':
- # Process handling (fork, wait) under BeOS (up to 5.0)
- # doesn't interoperate reliably with the thread interlocking
- # that happens during an import. The actual error we need
- # is the same on BeOS for posix.open() et al., ENOENT.
- try: unlink('/_#.# ## #.#')
- except error, _notfound: pass
- else:
- import tempfile
- t = tempfile.mktemp()
- # Exec a file that is guaranteed not to exist
- try: execv(t, ('blah',))
- except error, _notfound: pass
- exc, arg = error, _notfound
+ saved_exc = None
+ saved_tb = None
for dir in PATH:
fullname = path.join(dir, file)
try:
apply(func, (fullname,) + argrest)
- except error, (errno, msg):
- if errno != arg[0]:
- exc, arg = error, (errno, msg)
- raise exc, arg
-
+ except error, e:
+ tb = sys.exc_info()[2]
+ if (e.errno != ENOENT and e.errno != ENOTDIR
+ and saved_exc is None):
+ saved_exc = e
+ saved_tb = tb
+ if saved_exc:
+ raise error, saved_exc, saved_tb
+ raise error, e, tb
# Change environ to automatically call putenv() if it exists
try:
@@ -618,3 +610,4 @@ try:
_make_statvfs_result)
except NameError: # statvfs_result may not exist
pass
+

View File

@ -0,0 +1,19 @@
$OpenBSD: patch-Modules_Setup_dist,v 1.1 2002/10/08 02:52:25 brad Exp $
--- Modules/Setup.dist.orig Mon Oct 7 22:18:01 2002
+++ Modules/Setup.dist Mon Oct 7 22:18:36 2002
@@ -97,6 +97,7 @@ PYTHONPATH=$(COREPYTHONPATH)
# setup.py script in the root of the Python source tree.
posix posixmodule.c # posix (UNIX) system calls
+errno errnomodule.c # posix (UNIX) errno values
_sre _sre.c # Fredrik Lundh's new regular expressions
new newmodule.c # Tommy Burnette's 'new' module
@@ -166,7 +167,6 @@ GLHACK=-Dclear=__GLclear
#fcntl fcntlmodule.c # fcntl(2) and ioctl(2)
#pwd pwdmodule.c # pwd(3)
#grp grpmodule.c # grp(3)
-#errno errnomodule.c # posix (UNIX) errno values
#select selectmodule.c # select(2); not on ancient System V
# Memory-mapped files (also works on Win32).

View File

@ -1,7 +1,16 @@
$OpenBSD: patch-setup_py,v 1.2 2002/05/11 21:35:13 matt Exp $
$OpenBSD: patch-setup_py,v 1.3 2002/10/08 02:52:25 brad Exp $
--- setup.py.orig Tue Mar 26 08:43:04 2002
+++ setup.py Fri Apr 19 09:05:16 2002
@@ -793,7 +793,8 @@ def main():
+++ setup.py Mon Oct 7 22:19:31 2002
@@ -273,8 +273,6 @@ class PyBuildExt(build_ext):
exts.append( Extension('pwd', ['pwdmodule.c']) )
# grp(3)
exts.append( Extension('grp', ['grpmodule.c']) )
- # posix (UNIX) errno values
- exts.append( Extension('errno', ['errnomodule.c']) )
# select(2); not on ancient System V
exts.append( Extension('select', ['selectmodule.c']) )
@@ -793,7 +791,8 @@ def main():
ext_modules=[Extension('struct', ['structmodule.c'])],
# Scripts to install

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile.inc,v 1.7 2002/07/09 12:32:34 matt Exp $
# $OpenBSD: Makefile.inc,v 1.8 2002/10/08 02:52:25 brad Exp $
# IMPORTANT! If you make any changes to the Python ports, be sure
# to also update files/CHANGES.OpenBSD for your change. This is a
@ -12,7 +12,7 @@ COMMENT-mpz= "GNU arbitrary magnitude integer module for Python"
COMMENT-tkinter="tk GUI module for Python"
COMMENT-expat= "expat module for Python"
PKGNAME= python-${VERSION}${PATCHLEVEL}
PKGNAME= python-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
DISTNAME= Python-${VERSION}${PATCHLEVEL}
CATEGORIES= lang
MASTER_SITES= ftp://ftp.python.org/pub/${PSUBDIR}/ \
@ -103,11 +103,11 @@ LIB_DEPENDS+= expat::textproc/expat
FULLPKGNAME=${PKGNAME}${FLAVOR_EXT:S/-no_mpz//:S/-no_tkinter//:S/-no_expat//}
.endif
FULLPKGNAME-tests= python-tests-${VERSION}${PATCHLEVEL}
FULLPKGNAME-tools= python-tools-${VERSION}${PATCHLEVEL}
FULLPKGNAME-mpz= python-mpz-${VERSION}${PATCHLEVEL}
FULLPKGNAME-tkinter= python-tkinter-${VERSION}${PATCHLEVEL}
FULLPKGNAME-expat= python-expat-${VERSION}${PATCHLEVEL}
FULLPKGNAME-tests= python-tests-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
FULLPKGNAME-tools= python-tools-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
FULLPKGNAME-mpz= python-mpz-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
FULLPKGNAME-tkinter= python-tkinter-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
FULLPKGNAME-expat= python-expat-${VERSION}${PATCHLEVEL}${PKG_PATCHLEVEL}
CONFIGURE_STYLE= autoconf dest
CONFIGURE_ARGS+= ${CONFIGURE_SHARED}