]> granicus.if.org Git - python/commitdiff
Now that file objects are subclassable, you can get at the file constructor
authorTim Peters <tim.peters@gmail.com>
Thu, 13 Sep 2001 21:01:29 +0000 (21:01 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 13 Sep 2001 21:01:29 +0000 (21:01 +0000)
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).

Lib/rexec.py
Lib/test/test_descr.py
Objects/fileobject.c

index d1dd4ebf1bd1c4e446b80c401b836f1846dc8f82..cece5446d8d3c771db79bfd53f05155e716a8752 100644 (file)
@@ -132,7 +132,7 @@ class RExec(ihooks._Verbose):
     ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
                     'platform', 'exit', 'maxint')
 
-    nok_builtin_names = ('open', 'reload', '__import__')
+    nok_builtin_names = ('open', 'file', 'reload', '__import__')
 
     def __init__(self, hooks = None, verbose = 0):
         ihooks._Verbose.__init__(self, verbose)
@@ -186,7 +186,7 @@ class RExec(ihooks._Verbose):
         m = self.copy_except(__builtin__, self.nok_builtin_names)
         m.__import__ = self.r_import
         m.reload = self.r_reload
-        m.open = self.r_open
+        m.open = m.file = self.r_open
 
     def make_main(self):
         m = self.add_module('__main__')
index 02ef0ef46f3c6074b4d3280aa02e97665eabe5c0..f1af5b94b7f15bd2cb8fa2f21ce3611cedc945f9 100644 (file)
@@ -1717,6 +1717,47 @@ def keywords():
             raise TestFailed("expected TypeError from bogus keyword "
                              "argument to %r" % constructor)
 
+def restricted():
+    import rexec
+    if verbose:
+        print "Testing interaction with restricted execution ..."
+
+    sandbox = rexec.RExec()
+
+    code1 = """f = open(%r, 'w')""" % TESTFN
+    code2 = """f = file(%r, 'w')""" % TESTFN
+    code3 = """\
+f = open(%r)
+t = type(f)  # a sneaky way to get the file() constructor
+f.close()
+f = t(%r, 'w')  # rexec can't catch this by itself
+""" % (TESTFN, TESTFN)
+
+    f = open(TESTFN, 'w')  # Create the file so code3 can find it.
+    f.close()
+
+    try:
+        for code in code1, code2, code3:
+            try:
+                sandbox.r_exec(code)
+            except IOError, msg:
+                if str(msg).find("restricted") >= 0:
+                    outcome = "OK"
+                else:
+                    outcome = "got an exception, but not an expected one"
+            else:
+                outcome = "expected a restricted-execution exception"
+
+            if outcome != "OK":
+                raise TestFailed("%s, in %r" % (outcome, code))
+
+    finally:
+        try:
+            import os
+            os.unlink(TESTFN)
+        except:
+            pass
+
 def all():
     lists()
     dicts()
@@ -1752,6 +1793,7 @@ def all():
     supers()
     inherits()
     keywords()
+    restricted()
 
 all()
 
index 3cadff51568a83443905f6f0a4af74db66b1796d..b37302421caa9d0fa7e1365af9b0179532315a4e 100644 (file)
@@ -92,6 +92,14 @@ open_the_file(PyFileObject *f, char *name, char *mode)
        assert(name != NULL);
        assert(mode != NULL);
 
+       /* rexec.py can't stop a user from getting the file() constructor --
+          all they have to do is get *any* file object f, and then do
+          type(f).  Here we prevent them from doing damage with it. */
+       if (PyEval_GetRestricted()) {
+               PyErr_SetString(PyExc_IOError,
+                       "file() constructor not accessible in restricted mode");
+               return NULL;
+       }
 #ifdef HAVE_FOPENRF
        if (*mode == '*') {
                FILE *fopenRF();