]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/rexec.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / rexec.py
1 """Restricted execution facilities.
2
3 The class RExec exports methods r_exec(), r_eval(), r_execfile(), and
4 r_import(), which correspond roughly to the built-in operations
5 exec, eval(), execfile() and import, but executing the code in an
6 environment that only exposes those built-in operations that are
7 deemed safe. To this end, a modest collection of 'fake' modules is
8 created which mimics the standard modules by the same names. It is a
9 policy decision which built-in modules and operations are made
10 available; this module provides a reasonable default, but derived
11 classes can change the policies e.g. by overriding or extending class
12 variables like ok_builtin_modules or methods like make_sys().
13
14 XXX To do:
15 - r_open should allow writing tmp dir
16 - r_exec etc. with explicit globals/locals? (Use rexec("exec ... in ...")?)
17
18 """
19 from warnings import warnpy3k
20 warnpy3k("the rexec module has been removed in Python 3.0", stacklevel=2)
21 del warnpy3k
22
23
24 import sys
25 import __builtin__
26 import os
27 import ihooks
28 import imp
29
30 __all__ = ["RExec"]
31
32 class FileBase:
33
34 ok_file_methods = ('fileno', 'flush', 'isatty', 'read', 'readline',
35 'readlines', 'seek', 'tell', 'write', 'writelines', 'xreadlines',
36 '__iter__')
37
38
39 class FileWrapper(FileBase):
40
41 # XXX This is just like a Bastion -- should use that!
42
43 def __init__(self, f):
44 for m in self.ok_file_methods:
45 if not hasattr(self, m) and hasattr(f, m):
46 setattr(self, m, getattr(f, m))
47
48 def close(self):
49 self.flush()
50
51
52 TEMPLATE = """
53 def %s(self, *args):
54 return getattr(self.mod, self.name).%s(*args)
55 """
56
57 class FileDelegate(FileBase):
58
59 def __init__(self, mod, name):
60 self.mod = mod
61 self.name = name
62
63 for m in FileBase.ok_file_methods + ('close',):
64 exec TEMPLATE % (m, m)
65
66
67 class RHooks(ihooks.Hooks):
68
69 def __init__(self, *args):
70 # Hacks to support both old and new interfaces:
71 # old interface was RHooks(rexec[, verbose])
72 # new interface is RHooks([verbose])
73 verbose = 0
74 rexec = None
75 if args and type(args[-1]) == type(0):
76 verbose = args[-1]
77 args = args[:-1]
78 if args and hasattr(args[0], '__class__'):
79 rexec = args[0]
80 args = args[1:]
81 if args:
82 raise TypeError, "too many arguments"
83 ihooks.Hooks.__init__(self, verbose)
84 self.rexec = rexec
85
86 def set_rexec(self, rexec):
87 # Called by RExec instance to complete initialization
88 self.rexec = rexec
89
90 def get_suffixes(self):
91 return self.rexec.get_suffixes()
92
93 def is_builtin(self, name):
94 return self.rexec.is_builtin(name)
95
96 def init_builtin(self, name):
97 m = __import__(name)
98 return self.rexec.copy_except(m, ())
99
100 def init_frozen(self, name): raise SystemError, "don't use this"
101 def load_source(self, *args): raise SystemError, "don't use this"
102 def load_compiled(self, *args): raise SystemError, "don't use this"
103 def load_package(self, *args): raise SystemError, "don't use this"
104
105 def load_dynamic(self, name, filename, file):
106 return self.rexec.load_dynamic(name, filename, file)
107
108 def add_module(self, name):
109 return self.rexec.add_module(name)
110
111 def modules_dict(self):
112 return self.rexec.modules
113
114 def default_path(self):
115 return self.rexec.modules['sys'].path
116
117
118 # XXX Backwards compatibility
119 RModuleLoader = ihooks.FancyModuleLoader
120 RModuleImporter = ihooks.ModuleImporter
121
122
123 class RExec(ihooks._Verbose):
124 """Basic restricted execution framework.
125
126 Code executed in this restricted environment will only have access to
127 modules and functions that are deemed safe; you can subclass RExec to
128 add or remove capabilities as desired.
129
130 The RExec class can prevent code from performing unsafe operations like
131 reading or writing disk files, or using TCP/IP sockets. However, it does
132 not protect against code using extremely large amounts of memory or
133 processor time.
134
135 """
136
137 ok_path = tuple(sys.path) # That's a policy decision
138
139 ok_builtin_modules = ('audioop', 'array', 'binascii',
140 'cmath', 'errno', 'imageop',
141 'marshal', 'math', 'md5', 'operator',
142 'parser', 'select',
143 'sha', '_sre', 'strop', 'struct', 'time',
144 '_weakref')
145
146 ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink',
147 'stat', 'times', 'uname', 'getpid', 'getppid',
148 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
149
150 ok_sys_names = ('byteorder', 'copyright', 'exit', 'getdefaultencoding',
151 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
152 'platform', 'ps1', 'ps2', 'version', 'version_info')
153
154 nok_builtin_names = ('open', 'file', 'reload', '__import__')
155
156 ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
157
158 def __init__(self, hooks = None, verbose = 0):
159 """Returns an instance of the RExec class.
160
161 The hooks parameter is an instance of the RHooks class or a subclass
162 of it. If it is omitted or None, the default RHooks class is
163 instantiated.
164
165 Whenever the RExec module searches for a module (even a built-in one)
166 or reads a module's code, it doesn't actually go out to the file
167 system itself. Rather, it calls methods of an RHooks instance that
168 was passed to or created by its constructor. (Actually, the RExec
169 object doesn't make these calls --- they are made by a module loader
170 object that's part of the RExec object. This allows another level of
171 flexibility, which can be useful when changing the mechanics of
172 import within the restricted environment.)
173
174 By providing an alternate RHooks object, we can control the file
175 system accesses made to import a module, without changing the
176 actual algorithm that controls the order in which those accesses are
177 made. For instance, we could substitute an RHooks object that
178 passes all filesystem requests to a file server elsewhere, via some
179 RPC mechanism such as ILU. Grail's applet loader uses this to support
180 importing applets from a URL for a directory.
181
182 If the verbose parameter is true, additional debugging output may be
183 sent to standard output.
184
185 """
186
187 raise RuntimeError, "This code is not secure in Python 2.2 and later"
188
189 ihooks._Verbose.__init__(self, verbose)
190 # XXX There's a circular reference here:
191 self.hooks = hooks or RHooks(verbose)
192 self.hooks.set_rexec(self)
193 self.modules = {}
194 self.ok_dynamic_modules = self.ok_builtin_modules
195 list = []
196 for mname in self.ok_builtin_modules:
197 if mname in sys.builtin_module_names:
198 list.append(mname)
199 self.ok_builtin_modules = tuple(list)
200 self.set_trusted_path()
201 self.make_builtin()
202 self.make_initial_modules()
203 # make_sys must be last because it adds the already created
204 # modules to its builtin_module_names
205 self.make_sys()
206 self.loader = RModuleLoader(self.hooks, verbose)
207 self.importer = RModuleImporter(self.loader, verbose)
208
209 def set_trusted_path(self):
210 # Set the path from which dynamic modules may be loaded.
211 # Those dynamic modules must also occur in ok_builtin_modules
212 self.trusted_path = filter(os.path.isabs, sys.path)
213
214 def load_dynamic(self, name, filename, file):
215 if name not in self.ok_dynamic_modules:
216 raise ImportError, "untrusted dynamic module: %s" % name
217 if name in sys.modules:
218 src = sys.modules[name]
219 else:
220 src = imp.load_dynamic(name, filename, file)
221 dst = self.copy_except(src, [])
222 return dst
223
224 def make_initial_modules(self):
225 self.make_main()
226 self.make_osname()
227
228 # Helpers for RHooks
229
230 def get_suffixes(self):
231 return [item # (suff, mode, type)
232 for item in imp.get_suffixes()
233 if item[2] in self.ok_file_types]
234
235 def is_builtin(self, mname):
236 return mname in self.ok_builtin_modules
237
238 # The make_* methods create specific built-in modules
239
240 def make_builtin(self):
241 m = self.copy_except(__builtin__, self.nok_builtin_names)
242 m.__import__ = self.r_import
243 m.reload = self.r_reload
244 m.open = m.file = self.r_open
245
246 def make_main(self):
247 self.add_module('__main__')
248
249 def make_osname(self):
250 osname = os.name
251 src = __import__(osname)
252 dst = self.copy_only(src, self.ok_posix_names)
253 dst.environ = e = {}
254 for key, value in os.environ.items():
255 e[key] = value
256
257 def make_sys(self):
258 m = self.copy_only(sys, self.ok_sys_names)
259 m.modules = self.modules
260 m.argv = ['RESTRICTED']
261 m.path = map(None, self.ok_path)
262 m.exc_info = self.r_exc_info
263 m = self.modules['sys']
264 l = self.modules.keys() + list(self.ok_builtin_modules)
265 l.sort()
266 m.builtin_module_names = tuple(l)
267
268 # The copy_* methods copy existing modules with some changes
269
270 def copy_except(self, src, exceptions):
271 dst = self.copy_none(src)
272 for name in dir(src):
273 setattr(dst, name, getattr(src, name))
274 for name in exceptions:
275 try:
276 delattr(dst, name)
277 except AttributeError:
278 pass
279 return dst
280
281 def copy_only(self, src, names):
282 dst = self.copy_none(src)
283 for name in names:
284 try:
285 value = getattr(src, name)
286 except AttributeError:
287 continue
288 setattr(dst, name, value)
289 return dst
290
291 def copy_none(self, src):
292 m = self.add_module(src.__name__)
293 m.__doc__ = src.__doc__
294 return m
295
296 # Add a module -- return an existing module or create one
297
298 def add_module(self, mname):
299 m = self.modules.get(mname)
300 if m is None:
301 self.modules[mname] = m = self.hooks.new_module(mname)
302 m.__builtins__ = self.modules['__builtin__']
303 return m
304
305 # The r* methods are public interfaces
306
307 def r_exec(self, code):
308 """Execute code within a restricted environment.
309
310 The code parameter must either be a string containing one or more
311 lines of Python code, or a compiled code object, which will be
312 executed in the restricted environment's __main__ module.
313
314 """
315 m = self.add_module('__main__')
316 exec code in m.__dict__
317
318 def r_eval(self, code):
319 """Evaluate code within a restricted environment.
320
321 The code parameter must either be a string containing a Python
322 expression, or a compiled code object, which will be evaluated in
323 the restricted environment's __main__ module. The value of the
324 expression or code object will be returned.
325
326 """
327 m = self.add_module('__main__')
328 return eval(code, m.__dict__)
329
330 def r_execfile(self, file):
331 """Execute the Python code in the file in the restricted
332 environment's __main__ module.
333
334 """
335 m = self.add_module('__main__')
336 execfile(file, m.__dict__)
337
338 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
339 """Import a module, raising an ImportError exception if the module
340 is considered unsafe.
341
342 This method is implicitly called by code executing in the
343 restricted environment. Overriding this method in a subclass is
344 used to change the policies enforced by a restricted environment.
345
346 """
347 return self.importer.import_module(mname, globals, locals, fromlist)
348
349 def r_reload(self, m):
350 """Reload the module object, re-parsing and re-initializing it.
351
352 This method is implicitly called by code executing in the
353 restricted environment. Overriding this method in a subclass is
354 used to change the policies enforced by a restricted environment.
355
356 """
357 return self.importer.reload(m)
358
359 def r_unload(self, m):
360 """Unload the module.
361
362 Removes it from the restricted environment's sys.modules dictionary.
363
364 This method is implicitly called by code executing in the
365 restricted environment. Overriding this method in a subclass is
366 used to change the policies enforced by a restricted environment.
367
368 """
369 return self.importer.unload(m)
370
371 # The s_* methods are similar but also swap std{in,out,err}
372
373 def make_delegate_files(self):
374 s = self.modules['sys']
375 self.delegate_stdin = FileDelegate(s, 'stdin')
376 self.delegate_stdout = FileDelegate(s, 'stdout')
377 self.delegate_stderr = FileDelegate(s, 'stderr')
378 self.restricted_stdin = FileWrapper(sys.stdin)
379 self.restricted_stdout = FileWrapper(sys.stdout)
380 self.restricted_stderr = FileWrapper(sys.stderr)
381
382 def set_files(self):
383 if not hasattr(self, 'save_stdin'):
384 self.save_files()
385 if not hasattr(self, 'delegate_stdin'):
386 self.make_delegate_files()
387 s = self.modules['sys']
388 s.stdin = self.restricted_stdin
389 s.stdout = self.restricted_stdout
390 s.stderr = self.restricted_stderr
391 sys.stdin = self.delegate_stdin
392 sys.stdout = self.delegate_stdout
393 sys.stderr = self.delegate_stderr
394
395 def reset_files(self):
396 self.restore_files()
397 s = self.modules['sys']
398 self.restricted_stdin = s.stdin
399 self.restricted_stdout = s.stdout
400 self.restricted_stderr = s.stderr
401
402
403 def save_files(self):
404 self.save_stdin = sys.stdin
405 self.save_stdout = sys.stdout
406 self.save_stderr = sys.stderr
407
408 def restore_files(self):
409 sys.stdin = self.save_stdin
410 sys.stdout = self.save_stdout
411 sys.stderr = self.save_stderr
412
413 def s_apply(self, func, args=(), kw={}):
414 self.save_files()
415 try:
416 self.set_files()
417 r = func(*args, **kw)
418 finally:
419 self.restore_files()
420 return r
421
422 def s_exec(self, *args):
423 """Execute code within a restricted environment.
424
425 Similar to the r_exec() method, but the code will be granted access
426 to restricted versions of the standard I/O streams sys.stdin,
427 sys.stderr, and sys.stdout.
428
429 The code parameter must either be a string containing one or more
430 lines of Python code, or a compiled code object, which will be
431 executed in the restricted environment's __main__ module.
432
433 """
434 return self.s_apply(self.r_exec, args)
435
436 def s_eval(self, *args):
437 """Evaluate code within a restricted environment.
438
439 Similar to the r_eval() method, but the code will be granted access
440 to restricted versions of the standard I/O streams sys.stdin,
441 sys.stderr, and sys.stdout.
442
443 The code parameter must either be a string containing a Python
444 expression, or a compiled code object, which will be evaluated in
445 the restricted environment's __main__ module. The value of the
446 expression or code object will be returned.
447
448 """
449 return self.s_apply(self.r_eval, args)
450
451 def s_execfile(self, *args):
452 """Execute the Python code in the file in the restricted
453 environment's __main__ module.
454
455 Similar to the r_execfile() method, but the code will be granted
456 access to restricted versions of the standard I/O streams sys.stdin,
457 sys.stderr, and sys.stdout.
458
459 """
460 return self.s_apply(self.r_execfile, args)
461
462 def s_import(self, *args):
463 """Import a module, raising an ImportError exception if the module
464 is considered unsafe.
465
466 This method is implicitly called by code executing in the
467 restricted environment. Overriding this method in a subclass is
468 used to change the policies enforced by a restricted environment.
469
470 Similar to the r_import() method, but has access to restricted
471 versions of the standard I/O streams sys.stdin, sys.stderr, and
472 sys.stdout.
473
474 """
475 return self.s_apply(self.r_import, args)
476
477 def s_reload(self, *args):
478 """Reload the module object, re-parsing and re-initializing it.
479
480 This method is implicitly called by code executing in the
481 restricted environment. Overriding this method in a subclass is
482 used to change the policies enforced by a restricted environment.
483
484 Similar to the r_reload() method, but has access to restricted
485 versions of the standard I/O streams sys.stdin, sys.stderr, and
486 sys.stdout.
487
488 """
489 return self.s_apply(self.r_reload, args)
490
491 def s_unload(self, *args):
492 """Unload the module.
493
494 Removes it from the restricted environment's sys.modules dictionary.
495
496 This method is implicitly called by code executing in the
497 restricted environment. Overriding this method in a subclass is
498 used to change the policies enforced by a restricted environment.
499
500 Similar to the r_unload() method, but has access to restricted
501 versions of the standard I/O streams sys.stdin, sys.stderr, and
502 sys.stdout.
503
504 """
505 return self.s_apply(self.r_unload, args)
506
507 # Restricted open(...)
508
509 def r_open(self, file, mode='r', buf=-1):
510 """Method called when open() is called in the restricted environment.
511
512 The arguments are identical to those of the open() function, and a
513 file object (or a class instance compatible with file objects)
514 should be returned. RExec's default behaviour is allow opening
515 any file for reading, but forbidding any attempt to write a file.
516
517 This method is implicitly called by code executing in the
518 restricted environment. Overriding this method in a subclass is
519 used to change the policies enforced by a restricted environment.
520
521 """
522 mode = str(mode)
523 if mode not in ('r', 'rb'):
524 raise IOError, "can't open files for writing in restricted mode"
525 return open(file, mode, buf)
526
527 # Restricted version of sys.exc_info()
528
529 def r_exc_info(self):
530 ty, va, tr = sys.exc_info()
531 tr = None
532 return ty, va, tr
533
534
535 def test():
536 import getopt, traceback
537 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
538 verbose = 0
539 trusted = []
540 for o, a in opts:
541 if o == '-v':
542 verbose = verbose+1
543 if o == '-t':
544 trusted.append(a)
545 r = RExec(verbose=verbose)
546 if trusted:
547 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
548 if args:
549 r.modules['sys'].argv = args
550 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
551 else:
552 r.modules['sys'].path.insert(0, "")
553 fp = sys.stdin
554 if args and args[0] != '-':
555 try:
556 fp = open(args[0])
557 except IOError, msg:
558 print "%s: can't open file %r" % (sys.argv[0], args[0])
559 return 1
560 if fp.isatty():
561 try:
562 import readline
563 except ImportError:
564 pass
565 import code
566 class RestrictedConsole(code.InteractiveConsole):
567 def runcode(self, co):
568 self.locals['__builtins__'] = r.modules['__builtin__']
569 r.s_apply(code.InteractiveConsole.runcode, (self, co))
570 try:
571 RestrictedConsole(r.modules['__main__'].__dict__).interact()
572 except SystemExit, n:
573 return n
574 else:
575 text = fp.read()
576 fp.close()
577 c = compile(text, fp.name, 'exec')
578 try:
579 r.s_exec(c)
580 except SystemExit, n:
581 return n
582 except:
583 traceback.print_exc()
584 return 1
585
586
587 if __name__ == '__main__':
588 sys.exit(test())