Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
839c5684
Commit
839c5684
authored
Feb 26, 2013
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Hmm, turns out exec wants just one dict to properly simulate Python module execution.
parent
1473fe37
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
61 additions
and
67 deletions
+61
-67
common/lib/capa/capa/capa_problem.py
+1
-3
common/lib/capa/capa/responsetypes.py
+5
-9
common/lib/capa/capa/safe_exec.py
+2
-2
common/lib/capa/capa/tests/test_safe_exec.py
+16
-16
common/lib/codejail/codejail/safe_exec.py
+15
-15
common/lib/codejail/codejail/tests/test_safe_exec.py
+19
-19
lms/djangoapps/debug/views.py
+3
-3
No files found.
common/lib/capa/capa/capa_problem.py
View file @
839c5684
...
@@ -462,9 +462,7 @@ class LoncapaProblem(object):
...
@@ -462,9 +462,7 @@ class LoncapaProblem(object):
if
all_code
:
if
all_code
:
try
:
try
:
locals_dict
=
{}
safe_exec
.
safe_exec
(
all_code
,
context
,
random_seed
=
self
.
seed
,
python_path
=
python_path
)
safe_exec
.
safe_exec
(
all_code
,
context
,
locals_dict
,
random_seed
=
self
.
seed
,
python_path
=
python_path
)
context
.
update
(
locals_dict
)
except
Exception
as
err
:
except
Exception
as
err
:
log
.
exception
(
"Error while execing script code: "
+
all_code
)
log
.
exception
(
"Error while execing script code: "
+
all_code
)
msg
=
"Error while executing script code:
%
s"
%
str
(
err
)
.
replace
(
'<'
,
'<'
)
msg
=
"Error while executing script code:
%
s"
%
str
(
err
)
.
replace
(
'<'
,
'<'
)
...
...
common/lib/capa/capa/responsetypes.py
View file @
839c5684
...
@@ -936,9 +936,8 @@ class CustomResponse(LoncapaResponse):
...
@@ -936,9 +936,8 @@ class CustomResponse(LoncapaResponse):
'expect'
:
expect
,
'expect'
:
expect
,
'ans'
:
ans
,
'ans'
:
ans
,
}
}
locals_dict
=
{}
safe_exec
.
safe_exec
(
code
,
globals_dict
)
safe_exec
.
safe_exec
(
code
,
globals_dict
,
locals_dict
)
return
globals_dict
[
'cfn_return'
]
return
locals_dict
[
'cfn_return'
]
return
check_function
return
check_function
self
.
code
=
make_check_function
(
self
.
context
[
'script_code'
],
cfn
)
self
.
code
=
make_check_function
(
self
.
context
[
'script_code'
],
cfn
)
...
@@ -1055,9 +1054,7 @@ class CustomResponse(LoncapaResponse):
...
@@ -1055,9 +1054,7 @@ class CustomResponse(LoncapaResponse):
# exec the check function
# exec the check function
if
isinstance
(
self
.
code
,
basestring
):
if
isinstance
(
self
.
code
,
basestring
):
try
:
try
:
locals_dict
=
{}
safe_exec
.
safe_exec
(
self
.
code
,
self
.
context
)
safe_exec
.
safe_exec
(
self
.
code
,
self
.
context
,
locals_dict
)
self
.
context
.
update
(
locals_dict
)
except
Exception
as
err
:
except
Exception
as
err
:
self
.
_handle_exec_exception
(
err
)
self
.
_handle_exec_exception
(
err
)
...
@@ -1762,10 +1759,9 @@ class SchematicResponse(LoncapaResponse):
...
@@ -1762,10 +1759,9 @@ class SchematicResponse(LoncapaResponse):
json
.
loads
(
student_answers
[
k
])
for
k
in
sorted
(
self
.
answer_ids
)
json
.
loads
(
student_answers
[
k
])
for
k
in
sorted
(
self
.
answer_ids
)
]
]
self
.
context
.
update
({
'submission'
:
submission
})
self
.
context
.
update
({
'submission'
:
submission
})
locals_dict
=
{}
safe_exec
.
safe_exec
(
self
.
code
,
self
.
context
)
safe_exec
.
safe_exec
(
self
.
code
,
self
.
context
,
locals_dict
)
cmap
=
CorrectMap
()
cmap
=
CorrectMap
()
cmap
.
set_dict
(
dict
(
zip
(
sorted
(
self
.
answer_ids
),
locals_dic
t
[
'correct'
])))
cmap
.
set_dict
(
dict
(
zip
(
sorted
(
self
.
answer_ids
),
self
.
contex
t
[
'correct'
])))
return
cmap
return
cmap
def
get_answers
(
self
):
def
get_answers
(
self
):
...
...
common/lib/capa/capa/safe_exec.py
View file @
839c5684
...
@@ -14,13 +14,13 @@ random.Random = random_module.Random
...
@@ -14,13 +14,13 @@ random.Random = random_module.Random
del random_module
del random_module
"""
"""
def
safe_exec
(
code
,
globals_dict
,
locals_dict
,
random_seed
=
None
,
python_path
=
None
):
def
safe_exec
(
code
,
globals_dict
,
random_seed
=
None
,
python_path
=
None
):
"""Exec python code safely.
"""Exec python code safely.
"""
"""
code_prolog
=
CODE_PROLOG
%
random_seed
code_prolog
=
CODE_PROLOG
%
random_seed
codejail
.
safe_exec
.
safe_exec
(
codejail
.
safe_exec
.
safe_exec
(
code_prolog
+
code
,
globals_dict
,
locals_dict
,
code_prolog
+
code
,
globals_dict
,
python_path
=
python_path
,
python_path
=
python_path
,
assumed_imports
=
[
assumed_imports
=
[
"numpy"
,
"numpy"
,
...
...
common/lib/capa/capa/tests/test_safe_exec.py
View file @
839c5684
...
@@ -8,39 +8,39 @@ from capa.safe_exec import safe_exec
...
@@ -8,39 +8,39 @@ from capa.safe_exec import safe_exec
class
TestSafeExec
(
unittest
.
TestCase
):
class
TestSafeExec
(
unittest
.
TestCase
):
def
test_set_values
(
self
):
def
test_set_values
(
self
):
g
,
l
=
{},
{}
g
=
{}
safe_exec
(
"a = 17"
,
g
,
l
)
safe_exec
(
"a = 17"
,
g
)
self
.
assertEqual
(
l
[
'a'
],
17
)
self
.
assertEqual
(
g
[
'a'
],
17
)
def
test_division
(
self
):
def
test_division
(
self
):
g
,
l
=
{},
{}
g
=
{}
# Future division: 1/2 is 0.5.
# Future division: 1/2 is 0.5.
safe_exec
(
"a = 1/2"
,
g
,
l
)
safe_exec
(
"a = 1/2"
,
g
)
self
.
assertEqual
(
l
[
'a'
],
0.5
)
self
.
assertEqual
(
g
[
'a'
],
0.5
)
def
test_assumed_imports
(
self
):
def
test_assumed_imports
(
self
):
g
,
l
=
{},
{}
g
=
{}
# Math is always available.
# Math is always available.
safe_exec
(
"a = int(math.pi)"
,
g
,
l
)
safe_exec
(
"a = int(math.pi)"
,
g
)
self
.
assertEqual
(
l
[
'a'
],
3
)
self
.
assertEqual
(
g
[
'a'
],
3
)
def
test_random_seeding
(
self
):
def
test_random_seeding
(
self
):
g
,
l
=
{},
{}
g
=
{}
r
=
random
.
Random
(
17
)
r
=
random
.
Random
(
17
)
rnums
=
[
r
.
randint
(
0
,
999
)
for
_
in
xrange
(
100
)]
rnums
=
[
r
.
randint
(
0
,
999
)
for
_
in
xrange
(
100
)]
# Without a seed, the results are unpredictable
# Without a seed, the results are unpredictable
safe_exec
(
"rnums = [random.randint(0, 999) for _ in xrange(100)]"
,
g
,
l
)
safe_exec
(
"rnums = [random.randint(0, 999) for _ in xrange(100)]"
,
g
)
self
.
assertNotEqual
(
l
[
'rnums'
],
rnums
)
self
.
assertNotEqual
(
g
[
'rnums'
],
rnums
)
# With a seed, the results are predictable
# With a seed, the results are predictable
safe_exec
(
"rnums = [random.randint(0, 999) for _ in xrange(100)]"
,
g
,
l
,
random_seed
=
17
)
safe_exec
(
"rnums = [random.randint(0, 999) for _ in xrange(100)]"
,
g
,
random_seed
=
17
)
self
.
assertEqual
(
l
[
'rnums'
],
rnums
)
self
.
assertEqual
(
g
[
'rnums'
],
rnums
)
def
test_python_lib
(
self
):
def
test_python_lib
(
self
):
pylib
=
os
.
path
.
dirname
(
__file__
)
+
"/test_files/pylib"
pylib
=
os
.
path
.
dirname
(
__file__
)
+
"/test_files/pylib"
g
,
l
=
{},
{}
g
=
{}
safe_exec
(
safe_exec
(
"import constant; a = constant.THE_CONST"
,
"import constant; a = constant.THE_CONST"
,
g
,
l
,
python_path
=
[
pylib
]
g
,
python_path
=
[
pylib
]
)
)
common/lib/codejail/codejail/safe_exec.py
View file @
839c5684
...
@@ -28,19 +28,19 @@ def names_and_modules(assumed_imports):
...
@@ -28,19 +28,19 @@ def names_and_modules(assumed_imports):
yield
modname
,
modname
yield
modname
,
modname
def
safe_exec
(
code
,
globals_dict
,
locals_dict
,
assumed_imports
=
None
,
files
=
None
,
python_path
=
None
):
def
safe_exec
(
code
,
globals_dict
,
assumed_imports
=
None
,
files
=
None
,
python_path
=
None
):
"""Execute code as "exec" does, but safely.
"""Execute code as "exec" does, but safely.
`code` is a string of Python code. `globals_dict`
and `locals_dict` are
`code` is a string of Python code. `globals_dict`
is used as the globals
d
ictionaries to use as the globals and locals. Modifications the cod
e
d
uring execution. Modifications the code makes to `globals_dict` ar
e
makes to `locals_dict` are
reflected in the dictionary on return.
reflected in the dictionary on return.
`assumed_imports` is a list of modules to make available as implicit
`assumed_imports` is a list of modules to make available as implicit
imports for the code. Entries are either a name, "mod", which makes
imports for the code. Entries are either a name, "mod", which makes
"import mod" part of the code, or a pair, ("f", "fooey"), which makes
"import mod" part of the code, or a pair, ("f", "fooey"), which makes
"import fooey as f" part of the code. The module name can be dotted.
"import fooey as f" part of the code. The module name can be dotted.
Returns None. Changes made by `code` are visible in `
loc
als_dict`.
Returns None. Changes made by `code` are visible in `
glob
als_dict`.
"""
"""
the_code
=
[]
the_code
=
[]
...
@@ -49,7 +49,7 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
...
@@ -49,7 +49,7 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
the_code
.
append
(
textwrap
.
dedent
(
"""
\
the_code
.
append
(
textwrap
.
dedent
(
"""
\
import json
import json
import sys
import sys
code, g_dict
, l_dict
= json.load(sys.stdin)
code, g_dict = json.load(sys.stdin)
"""
))
"""
))
for
pydir
in
python_path
or
():
for
pydir
in
python_path
or
():
...
@@ -63,13 +63,14 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
...
@@ -63,13 +63,14 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
the_code
.
append
(
"g_dict['{}'] = LazyModule('{}')
\n
"
.
format
(
name
,
modname
))
the_code
.
append
(
"g_dict['{}'] = LazyModule('{}')
\n
"
.
format
(
name
,
modname
))
the_code
.
append
(
textwrap
.
dedent
(
"""
\
the_code
.
append
(
textwrap
.
dedent
(
"""
\
exec code in g_dict
, l_dict
exec code in g_dict
ok_types = (type(None), int, long, float, str, unicode, list, tuple, dict)
ok_types = (type(None), int, long, float, str, unicode, list, tuple, dict)
l_dict = {k:v for k,v in l_dict.iteritems() if isinstance(v, ok_types)}
bad_keys = ("__builtins__",)
json.dump(l_dict, sys.stdout)
g_dict = {k:v for k,v in g_dict.iteritems() if isinstance(v, ok_types) and k not in bad_keys}
json.dump(g_dict, sys.stdout)
"""
))
"""
))
stdin
=
json
.
dumps
([
code
,
globals_dict
,
locals_dict
])
stdin
=
json
.
dumps
([
code
,
globals_dict
])
jailed_code
=
""
.
join
(
the_code
)
jailed_code
=
""
.
join
(
the_code
)
# Turn this on to see what's being executed.
# Turn this on to see what's being executed.
...
@@ -82,10 +83,10 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
...
@@ -82,10 +83,10 @@ def safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=None,
res
=
jailpy
.
jailpy
(
jailed_code
,
stdin
=
stdin
,
files
=
files
)
res
=
jailpy
.
jailpy
(
jailed_code
,
stdin
=
stdin
,
files
=
files
)
if
res
.
status
!=
0
:
if
res
.
status
!=
0
:
raise
Exception
(
"Couldn't excecute jailed code:
%
s"
%
res
.
stderr
)
raise
Exception
(
"Couldn't excecute jailed code:
%
s"
%
res
.
stderr
)
loc
als_dict
.
update
(
json
.
loads
(
res
.
stdout
))
glob
als_dict
.
update
(
json
.
loads
(
res
.
stdout
))
def
not_safe_exec
(
code
,
globals_dict
,
locals_dict
,
assumed_imports
=
None
,
files
=
None
,
python_path
=
None
):
def
not_safe_exec
(
code
,
globals_dict
,
assumed_imports
=
None
,
files
=
None
,
python_path
=
None
):
"""Another implementation of `safe_exec`, but not safe.
"""Another implementation of `safe_exec`, but not safe.
This can be swapped in for debugging problems in sandboxed Python code.
This can be swapped in for debugging problems in sandboxed Python code.
...
@@ -111,7 +112,6 @@ def not_safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=N
...
@@ -111,7 +112,6 @@ def not_safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=N
return
json
.
loads
(
json
.
dumps
(
jd
))
return
json
.
loads
(
json
.
dumps
(
jd
))
g_dict
=
straw
(
globals_dict
)
g_dict
=
straw
(
globals_dict
)
l_dict
=
straw
(
locals_dict
)
for
name
,
modname
in
names_and_modules
(
assumed_imports
or
()):
for
name
,
modname
in
names_and_modules
(
assumed_imports
or
()):
g_dict
[
name
]
=
lazymod
.
LazyModule
(
modname
)
g_dict
[
name
]
=
lazymod
.
LazyModule
(
modname
)
...
@@ -127,11 +127,11 @@ def not_safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=N
...
@@ -127,11 +127,11 @@ def not_safe_exec(code, globals_dict, locals_dict, assumed_imports=None, files=N
if
python_path
:
if
python_path
:
sys
.
path
.
extend
(
python_path
)
sys
.
path
.
extend
(
python_path
)
try
:
try
:
exec
code
in
g_dict
,
l_dict
exec
code
in
g_dict
finally
:
finally
:
sys
.
path
=
original_path
sys
.
path
=
original_path
locals_dict
.
update
(
straw
(
l
_dict
))
globals_dict
.
update
(
straw
(
g
_dict
))
# Running Python code in the sandbox makes it difficult to debug.
# Running Python code in the sandbox makes it difficult to debug.
# Change 0 to 1 to run the code directly.
# Change 0 to 1 to run the code directly.
...
...
common/lib/codejail/codejail/tests/test_safe_exec.py
View file @
839c5684
...
@@ -10,49 +10,49 @@ from codejail.safe_exec import safe_exec, not_safe_exec
...
@@ -10,49 +10,49 @@ from codejail.safe_exec import safe_exec, not_safe_exec
class
SafeExecTests
(
object
):
class
SafeExecTests
(
object
):
"""The tests for `safe_exec`, will be mixed into specific test classes below."""
"""The tests for `safe_exec`, will be mixed into specific test classes below."""
def
test_set_values
(
self
):
def
test_set_values
(
self
):
g
,
l
=
{},
{}
g
=
{}
self
.
safe_exec
(
"a = 17"
,
g
,
l
)
self
.
safe_exec
(
"a = 17"
,
g
)
self
.
assertEqual
(
l
[
'a'
],
17
)
self
.
assertEqual
(
g
[
'a'
],
17
)
def
test_assumed_imports
(
self
):
def
test_assumed_imports
(
self
):
g
,
l
=
{},
{}
g
=
{}
# Using string without importing it is bad.
# Using string without importing it is bad.
with
self
.
assertRaises
(
Exception
):
with
self
.
assertRaises
(
Exception
):
self
.
safe_exec
(
"a = string.ascii_lowercase[0]"
,
g
,
l
)
self
.
safe_exec
(
"a = string.ascii_lowercase[0]"
,
g
)
# Using string with an assumed import is fine.
# Using string with an assumed import is fine.
self
.
safe_exec
(
"a = string.ascii_lowercase[0]"
,
g
,
l
,
assumed_imports
=
[
"string"
])
self
.
safe_exec
(
"a = string.ascii_lowercase[0]"
,
g
,
assumed_imports
=
[
"string"
])
self
.
assertEqual
(
l
[
'a'
],
'a'
)
self
.
assertEqual
(
g
[
'a'
],
'a'
)
# Can also import with a shorthand.
# Can also import with a shorthand.
self
.
safe_exec
(
"a = op.join('x', 'y')"
,
g
,
l
,
assumed_imports
=
[(
"op"
,
"os.path"
)])
self
.
safe_exec
(
"a = op.join('x', 'y')"
,
g
,
assumed_imports
=
[(
"op"
,
"os.path"
)])
self
.
assertEqual
(
l
[
'a'
][
0
],
'x'
)
self
.
assertEqual
(
g
[
'a'
][
0
],
'x'
)
self
.
assertEqual
(
l
[
'a'
][
-
1
],
'y'
)
self
.
assertEqual
(
g
[
'a'
][
-
1
],
'y'
)
def
test_files_are_copied
(
self
):
def
test_files_are_copied
(
self
):
g
,
l
=
{},
{}
g
=
{}
self
.
safe_exec
(
self
.
safe_exec
(
"a = 'Look: ' + open('hello.txt').read()"
,
g
,
l
,
"a = 'Look: ' + open('hello.txt').read()"
,
g
,
files
=
[
os
.
path
.
dirname
(
__file__
)
+
"/hello.txt"
]
files
=
[
os
.
path
.
dirname
(
__file__
)
+
"/hello.txt"
]
)
)
self
.
assertEqual
(
l
[
'a'
],
'Look: Hello there.
\n
'
)
self
.
assertEqual
(
g
[
'a'
],
'Look: Hello there.
\n
'
)
def
test_python_path
(
self
):
def
test_python_path
(
self
):
g
,
l
=
{},
{}
g
=
{}
self
.
safe_exec
(
self
.
safe_exec
(
"import module; a = module.const"
,
g
,
l
,
"import module; a = module.const"
,
g
,
python_path
=
[
os
.
path
.
dirname
(
__file__
)
+
"/pylib"
]
python_path
=
[
os
.
path
.
dirname
(
__file__
)
+
"/pylib"
]
)
)
self
.
assertEqual
(
l
[
'a'
],
42
)
self
.
assertEqual
(
g
[
'a'
],
42
)
def
test_functions_calling_each_other
(
self
):
def
test_functions_calling_each_other
(
self
):
g
,
l
=
{},
{}
g
=
{}
self
.
safe_exec
(
textwrap
.
dedent
(
"""
\
self
.
safe_exec
(
textwrap
.
dedent
(
"""
\
def f():
def f():
return 1723
return 1723
def g():
def g():
return f()
return f()
x = g()
x = g()
"""
),
g
,
l
)
"""
),
g
)
self
.
assertEqual
(
l
[
'x'
],
1723
)
self
.
assertEqual
(
g
[
'x'
],
1723
)
class
TestSafeExec
(
SafeExecTests
,
unittest
.
TestCase
):
class
TestSafeExec
(
SafeExecTests
,
unittest
.
TestCase
):
...
...
lms/djangoapps/debug/views.py
View file @
839c5684
...
@@ -19,11 +19,11 @@ def run_python(request):
...
@@ -19,11 +19,11 @@ def run_python(request):
c
[
'results'
]
=
None
c
[
'results'
]
=
None
if
request
.
method
==
'POST'
:
if
request
.
method
==
'POST'
:
py_code
=
c
[
'code'
]
=
request
.
POST
.
get
(
'code'
)
py_code
=
c
[
'code'
]
=
request
.
POST
.
get
(
'code'
)
g
,
l
=
{},
{}
g
=
{}
try
:
try
:
safe_exec
(
py_code
,
g
,
l
)
safe_exec
(
py_code
,
g
)
except
Exception
as
e
:
except
Exception
as
e
:
c
[
'results'
]
=
str
(
e
)
c
[
'results'
]
=
str
(
e
)
else
:
else
:
c
[
'results'
]
=
pprint
.
pformat
(
l
)
c
[
'results'
]
=
pprint
.
pformat
(
g
)
return
render_to_response
(
"debug/run_python_form.html"
,
c
)
return
render_to_response
(
"debug/run_python_form.html"
,
c
)
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