Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
27c09a84
Commit
27c09a84
authored
Aug 04, 1995
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new package support, import hooks, restricted execution support
parent
eb1c063a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
197 additions
and
164 deletions
+197
-164
Lib/rexec.py
Lib/rexec.py
+197
-164
No files found.
Lib/rexec.py
View file @
27c09a84
# Implement restricted execution of Python code
"""Restricted execution facilities.
The class RExec exports methods rexec(), reval(), rexecfile(), and
import_module(), which correspond roughly to the built-in operations
exec, eval(), execfile() and import, but executing the code in an
environment that only exposes those built-in operations that are
deemed safe. To this end, a modest collection of 'fake' modules is
created which mimics the standard modules by the same names. It is a
policy decision which built-in modules and operations are made
available; this module provides a reasonable default, but derived
classes can change the policies e.g. by overriding or extending class
variables like ok_builtin_modules or methods like make_sys().
"""
import
sys
import
__builtin__
import
imp
import
os
import
sys
import
types
def
trace
(
fmt
,
*
args
):
if
0
:
sys
.
stderr
.
write
(
fmt
%
args
+
'
\
n
'
)
def
copydict
(
src
,
dst
,
exceptions
=
[],
only
=
None
):
if
only
is
None
:
for
key
in
src
.
keys
():
if
key
not
in
exceptions
:
dst
[
key
]
=
src
[
key
]
else
:
for
key
in
only
:
dst
[
key
]
=
src
[
key
]
def
copymodule
(
src
,
dst
,
exceptions
=
[],
only
=
None
):
copydict
(
src
.
__dict__
,
dst
.
__dict__
,
exceptions
,
only
)
safe_path
=
[
'/usr/local/lib/python'
]
safe_modules
=
[
'array'
,
'math'
,
'regex'
,
'strop'
,
'time'
]
unsafe_builtin_names
=
[
'open'
,
'reload'
,
'__import__'
,
'raw_input'
,
'input'
]
safe_posix_names
=
[
'error'
,
'fstat'
,
'listdir'
,
'lstat'
,
'readlink'
,
'stat'
,
'times'
,
'uname'
,
'getpid'
,
'getppid'
,
'getcwd'
,
'getuid'
,
'getgid'
,
'geteuid'
,
'getegid'
]
safe_sys
=
imp
.
new_module
(
'sys'
)
safe_sys
.
modules
=
{}
safe_sys
.
modules
[
'sys'
]
=
safe_sys
safe_sys
.
path
=
safe_path
[:]
safe_sys
.
argv
=
[
'-'
]
safe_sys
.
builtin_module_names
=
safe_modules
[:]
+
[
'posix'
]
safe_sys
.
builtin_module_names
.
sort
()
safe_sys
.
copyright
=
sys
.
copyright
safe_sys
.
version
=
sys
.
version
+
' [restricted mode]'
safe_sys
.
exit
=
sys
.
exit
def
new_module
(
name
):
safe_sys
.
modules
[
name
]
=
m
=
imp
.
new_module
(
name
)
import
marshal
import
ihooks
class
RHooks
(
ihooks
.
Hooks
):
def
__init__
(
self
,
rexec
,
verbose
=
0
):
ihooks
.
Hooks
.
__init__
(
self
,
verbose
)
self
.
rexec
=
rexec
def
is_builtin
(
self
,
name
):
return
self
.
rexec
.
is_builtin
(
name
)
def
init_builtin
(
self
,
name
):
m
=
__import__
(
name
)
return
self
.
rexec
.
copy_except
(
m
,
())
def
init_frozen
(
self
,
name
):
raise
SystemError
,
"don't use this"
def
load_source
(
self
,
*
args
):
raise
SystemError
,
"don't use this"
def
load_compiled
(
self
,
*
args
):
raise
SystemError
,
"don't use this"
def
load_dynamic
(
self
,
*
args
):
raise
ImportError
,
"import of dynamically loaded modules not allowed"
def
add_module
(
self
,
name
):
return
self
.
rexec
.
add_module
(
name
)
def
modules_dict
(
self
):
return
self
.
rexec
.
modules
def
default_path
(
self
):
return
self
.
rexec
.
modules
[
'sys'
].
path
class
RModuleLoader
(
ihooks
.
FancyModuleLoader
):
pass
class
RModuleImporter
(
ihooks
.
ModuleImporter
):
pass
class
RExec
(
ihooks
.
_Verbose
):
"""Restricted Execution environment."""
ok_path
=
tuple
(
sys
.
path
)
# That's a policy decision
ok_builtin_modules
=
(
'array'
,
'audioop'
,
'imageop'
,
'marshal'
,
'math'
,
'md5'
,
'parser'
,
'regex'
,
'rotor'
,
'select'
,
'strop'
,
'struct'
,
'time'
)
ok_posix_names
=
(
'error'
,
'fstat'
,
'listdir'
,
'lstat'
,
'readlink'
,
'stat'
,
'times'
,
'uname'
,
'getpid'
,
'getppid'
,
'getcwd'
,
'getuid'
,
'getgid'
,
'geteuid'
,
'getegid'
)
ok_sys_names
=
(
'ps1'
,
'ps2'
,
'copyright'
,
'version'
,
'platform'
,
'exit'
,
'maxint'
)
nok_builtin_names
=
(
'open'
,
'reload'
,
'__import__'
,
'raw_input'
,
'input'
)
def
__init__
(
self
,
hooks
=
None
,
verbose
=
0
):
ihooks
.
_Verbose
.
__init__
(
self
,
verbose
)
# XXX There's a circular reference here:
self
.
hooks
=
hooks
or
RHooks
(
self
,
verbose
)
self
.
modules
=
{}
self
.
ok_builtin_modules
=
map
(
None
,
filter
(
lambda
mname
:
mname
in
sys
.
builtin_module_names
,
self
.
ok_builtin_modules
))
self
.
make_builtin
()
self
.
make_initial_modules
()
# make_sys must be last because it adds the already created
# modules to its builtin_module_names
self
.
make_sys
()
self
.
loader
=
RModuleLoader
(
self
.
hooks
,
verbose
)
self
.
importer
=
RModuleImporter
(
self
.
loader
,
verbose
)
def
make_initial_modules
(
self
):
self
.
make_main
()
self
.
make_osname
()
# Helpers for RHooks
def
is_builtin
(
self
,
mname
):
return
mname
in
self
.
ok_builtin_modules
# The make_* methods create specific built-in modules
def
make_builtin
(
self
):
m
=
self
.
copy_except
(
__builtin__
,
self
.
nok_builtin_names
)
m
.
__import__
=
self
.
r_import
def
make_main
(
self
):
m
=
self
.
add_module
(
'__main__'
)
def
make_osname
(
self
):
osname
=
os
.
name
src
=
__import__
(
osname
)
dst
=
self
.
copy_only
(
src
,
self
.
ok_posix_names
)
dst
.
environ
=
e
=
{}
for
key
,
value
in
os
.
environ
.
items
():
e
[
key
]
=
value
def
make_sys
(
self
):
m
=
self
.
copy_only
(
sys
,
self
.
ok_sys_names
)
m
.
modules
=
self
.
modules
m
.
argv
=
[
'RESTRICTED'
]
m
.
path
=
map
(
None
,
self
.
ok_path
)
m
=
self
.
modules
[
'sys'
]
m
.
builtin_module_names
=
\
self
.
modules
.
keys
()
+
self
.
ok_builtin_modules
m
.
builtin_module_names
.
sort
()
# The copy_* methods copy existing modules with some changes
def
copy_except
(
self
,
src
,
exceptions
):
dst
=
self
.
copy_none
(
src
)
for
name
in
dir
(
src
):
if
name
not
in
exceptions
:
setattr
(
dst
,
name
,
getattr
(
src
,
name
))
return
dst
def
copy_only
(
self
,
src
,
names
):
dst
=
self
.
copy_none
(
src
)
for
name
in
names
:
try
:
value
=
getattr
(
src
,
name
)
except
AttributeError
:
continue
setattr
(
dst
,
name
,
value
)
return
dst
def
copy_none
(
self
,
src
):
return
self
.
add_module
(
src
.
__name__
)
# Add a module -- return an existing module or create one
def
add_module
(
self
,
mname
):
if
self
.
modules
.
has_key
(
mname
):
return
self
.
modules
[
mname
]
self
.
modules
[
mname
]
=
m
=
self
.
hooks
.
new_module
(
mname
)
m
.
__builtins__
=
self
.
modules
[
'__builtin__'
]
return
m
safe_builtin
=
new_module
(
'__builtin__'
)
copymodule
(
__builtin__
,
safe_builtin
,
unsafe_builtin_names
)
safe_main
=
new_module
(
'__main__'
)
safe_posix
=
new_module
(
'posix'
)
import
posix
copymodule
(
posix
,
safe_posix
,
None
,
safe_posix_names
)
safe_posix
.
environ
=
{}
copydict
(
posix
.
environ
,
safe_posix
.
environ
)
safe_types
=
new_module
(
'types'
)
copymodule
(
types
,
safe_types
)
def
safe_import
(
name
,
globals
=
None
,
locals
=
None
,
fromlist
=
None
):
if
'.'
in
name
:
raise
ImportError
,
"import of dotted names not supported"
if
safe_sys
.
modules
.
has_key
(
name
):
return
safe_sys
.
modules
[
name
]
if
name
in
safe_modules
:
temp
=
{}
exec
"import "
+
name
in
temp
m
=
new_module
(
name
)
copymodule
(
temp
[
name
],
m
)
return
m
for
dirname
in
safe_path
:
filename
=
os
.
path
.
join
(
dirname
,
name
+
'.py'
)
try
:
f
=
open
(
filename
,
'r'
)
f
.
close
()
except
IOError
:
continue
m
=
new_module
(
name
)
rexecfile
(
filename
,
m
.
__dict__
)
return
m
raise
ImportError
,
name
safe_builtin
.
__import__
=
safe_import
def
safe_open
(
file
,
mode
=
'r'
):
if
type
(
file
)
!=
types
.
StringType
or
type
(
mode
)
!=
types
.
StringType
:
raise
TypeError
,
'open argument(s) must be string(s)'
if
mode
not
in
(
'r'
,
'rb'
):
raise
IOError
,
'open for writing not allowed'
file
=
os
.
path
.
join
(
os
.
getcwd
(),
file
)
file
=
os
.
path
.
normpath
(
file
)
if
file
[:
2
]
==
'//'
or
file
[:
5
]
==
'/etc/'
or
file
[:
4
]
==
'/../'
:
raise
IOError
,
'this path not allowed for reading'
return
open
(
file
,
mode
)
safe_builtin
.
open
=
safe_open
def
exterior
():
"""Return env of caller's caller, as triple: (name, locals, globals).
Name will be None if env is __main__, and locals will be None if same
as globals, ie local env is global env."""
import
sys
,
__main__
bogus
=
'bogus'
# A locally usable exception
try
:
raise
bogus
# Force an exception
except
bogus
:
at
=
sys
.
exc_traceback
.
tb_frame
.
f_back
# The external frame.
if
at
.
f_back
:
at
=
at
.
f_back
# And further, if any.
where
,
globals
,
locals
=
at
.
f_code
,
at
.
f_globals
,
at
.
f_locals
if
locals
==
globals
:
# Exterior is global?
locals
=
None
if
where
:
where
=
where
.
co_name
return
(
where
,
locals
,
globals
)
def
rexec
(
str
,
globals
=
None
,
locals
=
None
):
trace
(
'rexec(%s, ...)'
,
`str`
)
if
globals
is
None
:
globals
=
locals
=
exterior
()[
2
]
elif
locals
is
None
:
locals
=
globals
globals
[
'__builtins__'
]
=
safe_builtin
.
__dict__
safe_sys
.
stdout
=
sys
.
stdout
safe_sys
.
stderr
=
sys
.
stderr
exec
str
in
globals
,
locals
def
rexecfile
(
file
,
globals
=
None
,
locals
=
None
):
trace
(
'rexecfile(%s, ...)'
,
`file`
)
if
globals
is
None
:
globals
=
locals
=
exterior
()[
2
]
elif
locals
is
None
:
locals
=
globals
globals
[
'__builtins__'
]
=
safe_builtin
.
__dict__
safe_sys
.
stdout
=
sys
.
stdout
safe_sys
.
stderr
=
sys
.
stderr
return
execfile
(
file
,
globals
,
locals
)
def
reval
(
str
,
globals
=
None
,
locals
=
None
):
trace
(
'reval(%s, ...)'
,
`str`
)
if
globals
is
None
:
globals
=
locals
=
exterior
()[
2
]
elif
locals
is
None
:
locals
=
globals
globals
[
'__builtins__'
]
=
safe_builtin
.
__dict__
safe_sys
.
stdout
=
sys
.
stdout
safe_sys
.
stderr
=
sys
.
stderr
return
eval
(
str
,
globals
,
locals
)
safe_builtin
.
eval
=
reval
# The r* methods are public interfaces
def
r_exec
(
self
,
code
):
m
=
self
.
add_module
(
'__main__'
)
exec
code
in
m
.
__dict__
def
r_eval
(
self
,
code
):
m
=
self
.
add_module
(
'__main__'
)
return
eval
(
code
,
m
.
__dict__
)
def
r_execfile
(
self
,
file
):
m
=
self
.
add_module
(
'__main__'
)
return
execfile
(
file
,
m
.
__dict__
)
def
r_import
(
self
,
mname
,
globals
=
{},
locals
=
{},
fromlist
=
[]):
return
self
.
importer
.
import_module
(
mname
,
globals
,
locals
,
fromlist
)
def
test
():
import
traceback
g
=
{}
while
1
:
try
:
s
=
raw_input
(
'--> '
)
except
EOFError
:
break
try
:
try
:
c
=
compile
(
s
,
''
,
'eval'
)
except
:
rexec
(
s
,
g
)
else
:
print
reval
(
c
,
g
)
except
:
traceback
.
print_exc
()
import
traceback
r
=
RExec
(
None
,
'-v'
in
sys
.
argv
[
1
:])
print
"*** RESTRICTED *** Python"
,
sys
.
version
print
sys
.
copyright
while
1
:
try
:
try
:
s
=
raw_input
(
'>>> '
)
except
EOFError
:
print
break
if
s
and
s
[
0
]
!=
'#'
:
s
=
s
+
'
\
n
'
c
=
compile
(
s
,
'<stdin>'
,
'single'
)
r
.
r_exec
(
c
)
except
SystemExit
,
n
:
sys
.
exit
(
n
)
except
:
traceback
.
print_exc
()
if
__name__
==
'__main__'
:
test
()
test
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment