Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8fa4567

Browse files
committed
Now that file objects are subclassable, you can get at the file constructor
just by doing type(f) where f is any file object. This left a hole in restricted execution mode that rexec.py can't plug by itself (although it can plug part of it; the rest is plugged in fileobject.c now).
1 parent 561f899 commit 8fa4567

3 files changed

Lines changed: 52 additions & 2 deletions

File tree

Lib/rexec.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class RExec(ihooks._Verbose):
132132
ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
133133
'platform', 'exit', 'maxint')
134134

135-
nok_builtin_names = ('open', 'reload', '__import__')
135+
nok_builtin_names = ('open', 'file', 'reload', '__import__')
136136

137137
def __init__(self, hooks = None, verbose = 0):
138138
ihooks._Verbose.__init__(self, verbose)
@@ -186,7 +186,7 @@ def make_builtin(self):
186186
m = self.copy_except(__builtin__, self.nok_builtin_names)
187187
m.__import__ = self.r_import
188188
m.reload = self.r_reload
189-
m.open = self.r_open
189+
m.open = m.file = self.r_open
190190

191191
def make_main(self):
192192
m = self.add_module('__main__')

Lib/test/test_descr.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,47 @@ def keywords():
17171717
raise TestFailed("expected TypeError from bogus keyword "
17181718
"argument to %r" % constructor)
17191719

1720+
def restricted():
1721+
import rexec
1722+
if verbose:
1723+
print "Testing interaction with restricted execution ..."
1724+
1725+
sandbox = rexec.RExec()
1726+
1727+
code1 = """f = open(%r, 'w')""" % TESTFN
1728+
code2 = """f = file(%r, 'w')""" % TESTFN
1729+
code3 = """\
1730+
f = open(%r)
1731+
t = type(f) # a sneaky way to get the file() constructor
1732+
f.close()
1733+
f = t(%r, 'w') # rexec can't catch this by itself
1734+
""" % (TESTFN, TESTFN)
1735+
1736+
f = open(TESTFN, 'w') # Create the file so code3 can find it.
1737+
f.close()
1738+
1739+
try:
1740+
for code in code1, code2, code3:
1741+
try:
1742+
sandbox.r_exec(code)
1743+
except IOError, msg:
1744+
if str(msg).find("restricted") >= 0:
1745+
outcome = "OK"
1746+
else:
1747+
outcome = "got an exception, but not an expected one"
1748+
else:
1749+
outcome = "expected a restricted-execution exception"
1750+
1751+
if outcome != "OK":
1752+
raise TestFailed("%s, in %r" % (outcome, code))
1753+
1754+
finally:
1755+
try:
1756+
import os
1757+
os.unlink(TESTFN)
1758+
except:
1759+
pass
1760+
17201761
def all():
17211762
lists()
17221763
dicts()
@@ -1752,6 +1793,7 @@ def all():
17521793
supers()
17531794
inherits()
17541795
keywords()
1796+
restricted()
17551797

17561798
all()
17571799

Objects/fileobject.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ open_the_file(PyFileObject *f, char *name, char *mode)
9292
assert(name != NULL);
9393
assert(mode != NULL);
9494

95+
/* rexec.py can't stop a user from getting the file() constructor --
96+
all they have to do is get *any* file object f, and then do
97+
type(f). Here we prevent them from doing damage with it. */
98+
if (PyEval_GetRestricted()) {
99+
PyErr_SetString(PyExc_IOError,
100+
"file() constructor not accessible in restricted mode");
101+
return NULL;
102+
}
95103
#ifdef HAVE_FOPENRF
96104
if (*mode == '*') {
97105
FILE *fopenRF();

0 commit comments

Comments
 (0)