[pypy-commit] pypy sandbox-2: in-progress
arigo
pypy.commits at gmail.com
Mon Aug 26 08:11:47 EDT 2019
Author: Armin Rigo <arigo at tunes.org>
Branch: sandbox-2
Changeset: r97262:9b6556323472
Date: 2019-08-26 14:11 +0200
http://bitbucket.org/pypy/pypy/changeset/9b6556323472/
Log: in-progress
diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py
--- a/pypy/module/__pypy__/interp_debug.py
+++ b/pypy/module/__pypy__/interp_debug.py
@@ -1,7 +1,13 @@
from pypy.interpreter.gateway import unwrap_spec
from rpython.rlib import debug, jit
from rpython.rlib import rtimer
+from rpython.rlib.objectmodel import sandbox_review
+# In sandbox mode, the debug_start/debug_print functions are disabled,
+# because they could allow the attacker to write arbitrary bytes to stderr
+
+
+ at sandbox_review(abort=True)
@jit.dont_look_inside
@unwrap_spec(category='text', timestamp=bool)
def debug_start(space, category, timestamp=False):
@@ -10,11 +16,13 @@
return space.newint(res)
return space.w_None
+ at sandbox_review(abort=True)
@jit.dont_look_inside
def debug_print(space, args_w):
parts = [space.text_w(space.str(w_item)) for w_item in args_w]
debug.debug_print(' '.join(parts))
+ at sandbox_review(abort=True)
@jit.dont_look_inside
@unwrap_spec(category='text', timestamp=bool)
def debug_stop(space, category, timestamp=False):
@@ -23,6 +31,7 @@
return space.newint(res)
return space.w_None
+ at sandbox_review(abort=True)
@unwrap_spec(category='text')
def debug_print_once(space, category, args_w):
debug_start(space, category)
@@ -34,9 +43,16 @@
def debug_flush(space):
debug.debug_flush()
+
+# In sandbox mode, these two helpers are disabled because they give unlimited
+# access to the real time (if you enable them, note that they use lloperations
+# that must also be white-listed in graphchecker.py)
+
+ at sandbox_review(abort=True)
def debug_read_timestamp(space):
return space.newint(rtimer.read_timestamp())
+ at sandbox_review(abort=True)
def debug_get_timestamp_unit(space):
unit = rtimer.get_timestamp_unit()
if unit == rtimer.UNIT_TSC:
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -1,6 +1,6 @@
from rpython.rlib import jit, rgc, rutf8
from rpython.rlib.buffer import RawBuffer
-from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.rlib.objectmodel import keepalive_until_here, sandbox_review
from rpython.rlib.rarithmetic import ovfcheck, widen, r_uint
from rpython.rlib.unroll import unrolling_iterable
from rpython.rtyper.annlowlevel import llstr
@@ -159,6 +159,7 @@
if self._buffer:
lltype.free(self._buffer, flavor='raw')
+ @sandbox_review(reviewed=True)
def setlen(self, size, zero=False, overallocate=True):
if self._buffer:
delta_memory_pressure = -self.allocated * self.itemsize
@@ -233,6 +234,7 @@
def _charbuf_stop(self):
keepalive_until_here(self)
+ @sandbox_review(reviewed=True)
def delitem(self, space, i, j):
if i < 0:
i += self.len
@@ -378,6 +380,7 @@
self._charbuf_stop()
return self.space.newbytes(s)
+ @sandbox_review(reviewed=True)
def descr_fromstring(self, space, w_s):
""" fromstring(string)
@@ -496,6 +499,7 @@
w_dict = space.w_None
return space.newtuple([space.type(self), space.newtuple(args), w_dict])
+ @sandbox_review(reviewed=True)
def descr_copy(self, space):
""" copy(array)
@@ -510,6 +514,7 @@
)
return w_a
+ @sandbox_review(reviewed=True)
def descr_byteswap(self, space):
""" byteswap()
@@ -602,6 +607,7 @@
def descr_iter(self, space):
return space.newseqiter(self)
+ @sandbox_review(reviewed=True)
def descr_add(self, space, w_other):
if (not isinstance(w_other, W_ArrayBase)
or w_other.typecode != self.typecode):
@@ -625,6 +631,7 @@
keepalive_until_here(a)
return a
+ @sandbox_review(reviewed=True)
def descr_inplace_add(self, space, w_other):
if (not isinstance(w_other, W_ArrayBase)
or w_other.typecode != self.typecode):
@@ -643,6 +650,7 @@
keepalive_until_here(w_other)
return self
+ @sandbox_review(reviewed=True)
def _mul_helper(self, space, w_repeat, is_inplace):
try:
repeat = space.getindex_w(w_repeat, space.w_OverflowError)
@@ -965,6 +973,7 @@
self.space.newtext(msg))
return result
+ @sandbox_review(reviewed=True)
def fromsequence(self, w_seq):
space = self.space
oldlen = self.len
@@ -1013,6 +1022,7 @@
self._fromiterable(w_seq)
+ @sandbox_review(reviewed=True)
def extend(self, w_iterable, accept_different_array=False):
space = self.space
if isinstance(w_iterable, W_Array):
@@ -1070,6 +1080,7 @@
# interface
+ @sandbox_review(reviewed=True)
def descr_append(self, space, w_x):
x = self.item_w(w_x)
index = self.len
@@ -1079,12 +1090,14 @@
# List interface
+ @sandbox_review(reviewed=True)
def descr_reverse(self, space):
b = self.get_buffer()
for i in range(self.len / 2):
b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
keepalive_until_here(self)
+ @sandbox_review(reviewed=True)
def descr_pop(self, space, i):
if i < 0:
i += self.len
@@ -1099,6 +1112,7 @@
self.setlen(self.len - 1)
return w_val
+ @sandbox_review(reviewed=True)
def descr_insert(self, space, idx, w_val):
if idx < 0:
idx += self.len
@@ -1117,6 +1131,7 @@
b[i] = val
keepalive_until_here(self)
+ @sandbox_review(reviewed=True)
def getitem_slice(self, space, w_idx):
start, stop, step, size = space.decode_index4(w_idx, self.len)
w_a = mytype.w_class(self.space)
@@ -1132,6 +1147,7 @@
keepalive_until_here(w_a)
return w_a
+ @sandbox_review(reviewed=True)
def setitem(self, space, w_idx, w_item):
idx, stop, step = space.decode_index(w_idx, self.len)
if step != 0:
@@ -1141,6 +1157,7 @@
self.get_buffer()[idx] = item
keepalive_until_here(self)
+ @sandbox_review(reviewed=True)
def setitem_slice(self, space, w_idx, w_item):
if not isinstance(w_item, W_Array):
raise oefmt(space.w_TypeError,
@@ -1168,6 +1185,7 @@
keepalive_until_here(w_item)
keepalive_until_here(self)
+ @sandbox_review(check_caller=True)
def _repeat_single_item(self, a, start, repeat):
# <a performance hack>
assert isinstance(a, W_Array)
diff --git a/pypy/module/gc/interp_gc.py b/pypy/module/gc/interp_gc.py
--- a/pypy/module/gc/interp_gc.py
+++ b/pypy/module/gc/interp_gc.py
@@ -46,7 +46,8 @@
If they were already enabled, no-op.
If they were disabled even several times, enable them anyway.
"""
- rgc.enable()
+ if not space.config.translation.sandbox: # not available in sandbox
+ rgc.enable()
if not space.user_del_action.enabled_at_app_level:
space.user_del_action.enabled_at_app_level = True
enable_finalizers(space)
@@ -55,7 +56,8 @@
"""Non-recursive version. Disable major collections and finalizers.
Multiple calls to this function are ignored.
"""
- rgc.disable()
+ if not space.config.translation.sandbox: # not available in sandbox
+ rgc.disable()
if space.user_del_action.enabled_at_app_level:
space.user_del_action.enabled_at_app_level = False
disable_finalizers(space)
diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -5,6 +5,7 @@
from rpython.rtyper.lltypesystem import lltype
from rpython.rlib.rarithmetic import intmask
from rpython.rlib import rposix, rtime
+from rpython.rlib.objectmodel import sandbox_review
from rpython.translator.tool.cbuild import ExternalCompilationInfo
import math
import os
@@ -224,6 +225,7 @@
accept2dyear = 1
_set_module_object(space, "accept2dyear", space.newint(accept2dyear))
+ at sandbox_review(reviewed=True)
def _init_timezone(space):
timezone = daylight = altzone = 0
tzname = ["", ""]
@@ -413,6 +415,7 @@
w_time_tuple = space.newtuple(time_tuple)
return space.call_function(w_struct_time, w_time_tuple)
+ at sandbox_review(reviewed=True)
def _gettmarg(space, w_tup, allowNone=True):
if space.is_none(w_tup):
if not allowNone:
@@ -507,6 +510,7 @@
return space.newfloat(pytime.clock())
+ at sandbox_review(reviewed=True)
def ctime(space, w_seconds=None):
"""ctime([seconds]) -> string
@@ -540,6 +544,7 @@
return space.newtext(rffi.charp2str(p)[:-1]) # get rid of new line
+ at sandbox_review(reviewed=True)
def gmtime(space, w_seconds=None):
"""gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,
tm_sec, tm_wday, tm_yday, tm_isdst)
@@ -560,6 +565,7 @@
raise OperationError(space.w_ValueError, space.newtext(_get_error_msg()))
return _tm_to_tuple(space, p)
+ at sandbox_review(reviewed=True)
def localtime(space, w_seconds=None):
"""localtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,
tm_sec, tm_wday, tm_yday, tm_isdst)
@@ -577,6 +583,7 @@
raise OperationError(space.w_ValueError, space.newtext(_get_error_msg()))
return _tm_to_tuple(space, p)
+ at sandbox_review(reviewed=True)
def mktime(space, w_tup):
"""mktime(tuple) -> floating point number
diff --git a/rpython/memory/gc/inspector.py b/rpython/memory/gc/inspector.py
--- a/rpython/memory/gc/inspector.py
+++ b/rpython/memory/gc/inspector.py
@@ -89,7 +89,7 @@
raw_os_write = rffi.llexternal(rposix.UNDERSCORE_ON_WIN32 + 'write',
[rffi.INT, llmemory.Address, rffi.SIZE_T],
rffi.SIZE_T,
- sandboxsafe=True, _nowrapper=True)
+ _nowrapper=True)
AddressStack = get_address_stack()
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -7,6 +7,7 @@
from rpython.rtyper.lltypesystem.rlist import LIST_OF
from rpython.rtyper.annlowlevel import llstr
from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.objectmodel import sandbox_review
from rpython.rlib import jit
from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
nonmoving_raw_ptr_for_resizable_list,
@@ -143,6 +144,7 @@
ptr = self.get_raw_address()
return llop.raw_load(TP, ptr, byte_offset)
+ @sandbox_review(check_caller=True)
@specialize.ll_and_arg(1)
def typed_write(self, TP, byte_offset, value):
"""
@@ -179,6 +181,7 @@
base_ofs = targetcls._get_gc_data_offset()
scale_factor = llmemory.sizeof(lltype.Char)
+ @sandbox_review(check_caller=True)
@specialize.ll_and_arg(1)
def typed_read(self, TP, byte_offset):
if not is_alignment_correct(TP, byte_offset):
@@ -188,6 +191,7 @@
return llop.gc_load_indexed(TP, lldata, byte_offset,
scale_factor, base_ofs)
+ @sandbox_review(check_caller=True)
@specialize.ll_and_arg(1)
def typed_write(self, TP, byte_offset, value):
if self.readonly or not is_alignment_correct(TP, byte_offset):
@@ -362,10 +366,12 @@
ptr = self.buffer.get_raw_address()
return rffi.ptradd(ptr, self.offset)
+ @sandbox_review(check_caller=True)
@specialize.ll_and_arg(1)
def typed_read(self, TP, byte_offset):
return self.buffer.typed_read(TP, byte_offset + self.offset)
+ @sandbox_review(check_caller=True)
@specialize.ll_and_arg(1)
def typed_write(self, TP, byte_offset, value):
return self.buffer.typed_write(TP, byte_offset + self.offset, value)
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -248,7 +248,7 @@
"""
assert reviewed + check_caller + abort == 1
def wrap(func):
- assert not hasattr(func, '_sandbox_review_')
+ assert not hasattr(func, '_sandbox_review_') or abort
if reviewed:
func._sandbox_review_ = 'reviewed'
if check_caller:
@@ -379,6 +379,10 @@
# XXX this can be made more efficient in the future
return bytearray(str(i))
+def sandboxed_translation():
+ config = fetch_translated_config()
+ return config is not None and config.translation.sandbox
+
def fetch_translated_config():
"""Returns the config that is current when translating.
Returns None if not translated.
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -6,7 +6,7 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import we_are_translated, enforceargs, specialize
from rpython.rlib.objectmodel import CDefinedIntSymbolic, not_rpython
-from rpython.rlib.objectmodel import sandbox_review
+from rpython.rlib.objectmodel import sandbox_review, sandboxed_translation
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.rtyper.lltypesystem import lltype, llmemory
@@ -359,15 +359,23 @@
return True
return False
+ at not_rpython
+def _ll_arraycopy_of_nongc_not_for_sandboxed():
+ pass
@jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)')
@enforceargs(None, None, int, int, int)
- at sandbox_review(check_caller=True)
+ at sandbox_review(reviewed=True)
@specialize.ll()
def ll_arraycopy(source, dest, source_start, dest_start, length):
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib.objectmodel import keepalive_until_here
+ TP = lltype.typeOf(source).TO
+ assert TP == lltype.typeOf(dest).TO
+ if not lltype_is_gc(TP) and sandboxed_translation():
+ _ll_arraycopy_of_nongc_not_for_sandboxed()
+
# XXX: Hack to ensure that we get a proper effectinfo.write_descrs_arrays
# and also, maybe, speed up very small cases
if length <= 1:
@@ -381,9 +389,6 @@
assert (source_start + length <= dest_start or
dest_start + length <= source_start)
- TP = lltype.typeOf(source).TO
- assert TP == lltype.typeOf(dest).TO
-
slowpath = False
if must_split_gc_address_space():
slowpath = True
@@ -1094,6 +1099,7 @@
hop.exception_cannot_occur()
return hop.genop('gc_gcflag_extra', vlist, resulttype = hop.r_result)
+ at specialize.memo()
def lltype_is_gc(TP):
return getattr(getattr(TP, "TO", None), "_gckind", "?") == 'gc'
@@ -1417,7 +1423,7 @@
return _ResizableListSupportingRawPtr(lst)
def nonmoving_raw_ptr_for_resizable_list(lst):
- if must_split_gc_address_space():
+ if must_split_gc_address_space() or sandboxed_translation():
raise ValueError
return _nonmoving_raw_ptr_for_resizable_list(lst)
@@ -1499,6 +1505,7 @@
@jit.dont_look_inside
+ at sandbox_review(check_caller=True)
def ll_nonmovable_raw_ptr_for_resizable_list(ll_list):
"""
WARNING: dragons ahead.
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -10,7 +10,8 @@
_CYGWIN, _MACRO_ON_POSIX, UNDERSCORE_ON_WIN32, _WIN32,
_prefer_unicode, _preferred_traits, _preferred_traits2)
from rpython.rlib.objectmodel import (
- specialize, enforceargs, register_replacement_for, NOT_CONSTANT)
+ specialize, enforceargs, register_replacement_for, NOT_CONSTANT,
+ sandbox_review)
from rpython.rlib.rarithmetic import intmask, widen
from rpython.rlib.signature import signature
from rpython.tool.sourcetools import func_renamer
@@ -988,6 +989,7 @@
[rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
rffi.PID_T, _nowrapper = True)
+ at sandbox_review(abort=True)
@replace_os_function('fork')
@jit.dont_look_inside
def fork():
@@ -1017,6 +1019,7 @@
lltype.free(master_p, flavor='raw')
lltype.free(slave_p, flavor='raw')
+ at sandbox_review(abort=True)
@replace_os_function('forkpty')
@jit.dont_look_inside
def forkpty():
@@ -1058,6 +1061,7 @@
[rffi.PID_T, rffi.INTP, rffi.INT], rffi.PID_T,
save_err=rffi.RFFI_SAVE_ERRNO)
+ at sandbox_review(reviewed=True)
@replace_os_function('waitpid')
def waitpid(pid, options):
status_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
@@ -1743,6 +1747,7 @@
finally:
lltype.free(groups, flavor='raw')
+ at sandbox_review(reviewed=True)
@replace_os_function('setgroups')
def setgroups(gids):
n = len(gids)
diff --git a/rpython/rlib/rstack.py b/rpython/rlib/rstack.py
--- a/rpython/rlib/rstack.py
+++ b/rpython/rlib/rstack.py
@@ -16,7 +16,7 @@
def llexternal(name, args, res, _callable=None):
return rffi.llexternal(name, args, res,
- sandboxsafe=True, _nowrapper=True,
+ sandboxsafe='check_caller', _nowrapper=True,
_callable=_callable)
_stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed,
diff --git a/rpython/rlib/rstruct/standardfmttable.py b/rpython/rlib/rstruct/standardfmttable.py
--- a/rpython/rlib/rstruct/standardfmttable.py
+++ b/rpython/rlib/rstruct/standardfmttable.py
@@ -7,7 +7,7 @@
import struct
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, sandbox_review
from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
from rpython.rlib.rstruct import ieee
from rpython.rlib.rstruct.error import StructError, StructOverflowError
@@ -30,6 +30,7 @@
Create a fast path packer for TYPE. The packer returns True is it succeded
or False otherwise.
"""
+ @sandbox_review(reviewed=True)
@specialize.argtype(0)
def do_pack_fastpath(fmtiter, value):
size = rffi.sizeof(TYPE)
@@ -39,6 +40,7 @@
raise CannotWrite
#
# typed_write() might raise CannotWrite
+ # (note that we assume the write cannot overflow its buffer)
fmtiter.wbuf.typed_write(TYPE, fmtiter.pos, value)
if not ALLOW_FASTPATH:
# if we are here it means that typed_write did not raise, and thus
@@ -211,6 +213,7 @@
@specialize.memo()
def unpack_fastpath(TYPE):
+ @sandbox_review(reviewed=True)
@specialize.argtype(0)
def do_unpack_fastpath(fmtiter):
size = rffi.sizeof(TYPE)
@@ -289,9 +292,15 @@
# because of alignment issues. So we copy the slice into a new
# string, which is guaranteed to be properly aligned, and read the
# float/double from there
- input = fmtiter.read(size)
- val = StringBuffer(input).typed_read(TYPE, 0)
+ val = read_slowpath(fmtiter)
fmtiter.appendobj(float(val))
+
+ @sandbox_review(reviewed=True)
+ def read_slowpath(fmtiter):
+ size = rffi.sizeof(TYPE)
+ input = fmtiter.read(size)
+ return StringBuffer(input).typed_read(TYPE, 0)
+
return unpack_ieee
@specialize.argtype(0)
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -6,6 +6,7 @@
from rpython.rlib.debug import ll_assert
from rpython.rlib.objectmodel import we_are_translated, specialize
from rpython.rlib.objectmodel import CDefinedIntSymbolic, not_rpython
+from rpython.rlib.objectmodel import sandbox_review
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.tool import rffi_platform
from rpython.rtyper.extregistry import ExtRegistryEntry
@@ -225,7 +226,7 @@
get_stacksize = llexternal('RPyThreadGetStackSize', [], lltype.Signed)
set_stacksize = llexternal('RPyThreadSetStackSize', [lltype.Signed],
- lltype.Signed)
+ lltype.Signed, sandboxsafe='abort')
# ____________________________________________________________
#
diff --git a/rpython/rlib/rtime.py b/rpython/rlib/rtime.py
--- a/rpython/rlib/rtime.py
+++ b/rpython/rlib/rtime.py
@@ -8,7 +8,7 @@
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rtyper.tool import rffi_platform
from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rlib.objectmodel import register_replacement_for
+from rpython.rlib.objectmodel import register_replacement_for, sandbox_review
from rpython.rlib.rarithmetic import intmask, UINT_MAX
from rpython.rlib import rposix
@@ -262,6 +262,7 @@
lltype.Ptr(TIMEVAL)], rffi.INT,
save_err=rffi.RFFI_SAVE_ERRNO)
+ at sandbox_review(reviewed=True)
@replace_time_function('sleep')
def sleep(secs):
if _WIN32:
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -98,6 +98,12 @@
don't bother releasing the GIL. An explicit True or False
overrides this logic.
+ sandboxsafe: if True, the process really calls the C function even if it
+ is sandboxed. If False, it will turn into a stdin/stdout
+ communication with the parent process. If "check_caller",
+ it is like True but we call @sandbox_review(check_caller=True)
+ which means that we need to also check the callers.
+
calling_conv: if 'unknown' or 'win', the C function is not directly seen
by the JIT. If 'c', it can be seen (depending on
releasegil=False). For tests only, or if _nowrapper,
@@ -334,7 +340,13 @@
# for debugging, stick ll func ptr to that
wrapper._ptr = funcptr
wrapper = func_with_new_name(wrapper, name)
- wrapper = sandbox_review(reviewed=True)(wrapper)
+ if sandboxsafe == 'check_caller':
+ wrapper = sandbox_review(check_caller=True)(wrapper)
+ elif sandboxsafe == 'abort':
+ wrapper = sandbox_review(abort=True)(wrapper)
+ else:
+ assert isinstance(sandboxsafe, bool)
+ wrapper = sandbox_review(reviewed=True)(wrapper)
return wrapper
def sandbox_check_type(TYPE):
@@ -1111,6 +1123,7 @@
CCHARPP = lltype.Ptr(lltype.Array(CCHARP, hints={'nolength': True}))
CWCHARPP = lltype.Ptr(lltype.Array(CWCHARP, hints={'nolength': True}))
+ at sandbox_review(reviewed=True)
def liststr2charpp(l):
""" list[str] -> char**, NULL terminated
"""
@@ -1256,6 +1269,7 @@
return v_ptr
+ at sandbox_review(check_caller=True)
def structcopy(pdst, psrc):
"""Copy all the fields of the structure given by 'psrc'
into the structure given by 'pdst'.
@@ -1273,6 +1287,7 @@
if name not in padding]
unrollfields = unrolling_iterable(fields)
+ @sandbox_review(check_caller=True)
def copyfn(pdst, psrc):
for name, TYPE in unrollfields:
if isinstance(TYPE, lltype.ContainerType):
@@ -1286,6 +1301,7 @@
_get_structcopy_fn._annspecialcase_ = 'specialize:memo'
+ at sandbox_review(check_caller=True)
def setintfield(pdst, fieldname, value):
"""Maybe temporary: a helper to set an integer field into a structure,
transparently casting between the various integer types.
@@ -1420,14 +1436,14 @@
lltype.Void,
releasegil=False,
calling_conv='c',
- sandboxsafe=True,
+ sandboxsafe='check_caller',
)
c_memset = llexternal("memset",
[VOIDP, lltype.Signed, SIZE_T],
lltype.Void,
releasegil=False,
calling_conv='c',
- sandboxsafe=True,
+ sandboxsafe='check_caller',
)
diff --git a/rpython/rtyper/lltypesystem/rlist.py b/rpython/rtyper/lltypesystem/rlist.py
--- a/rpython/rtyper/lltypesystem/rlist.py
+++ b/rpython/rtyper/lltypesystem/rlist.py
@@ -10,7 +10,6 @@
ADTIList, ADTIFixedList, dum_nocheck)
from rpython.rtyper.rmodel import Repr, inputconst, externalvsinternal
from rpython.tool.pairtype import pairtype, pair
-from rpython.rlib.objectmodel import sandbox_review
# ____________________________________________________________
@@ -197,7 +196,6 @@
# adapted C code
@jit.look_inside_iff(lambda l, newsize, overallocate: jit.isconstant(len(l.items)) and jit.isconstant(newsize))
- at sandbox_review(reviewed=True)
@signature(types.any(), types.int(), types.bool(), returns=types.none())
def _ll_list_resize_hint_really(l, newsize, overallocate):
"""
diff --git a/rpython/translator/backendopt/inline.py b/rpython/translator/backendopt/inline.py
--- a/rpython/translator/backendopt/inline.py
+++ b/rpython/translator/backendopt/inline.py
@@ -617,8 +617,7 @@
def dont_inline(funcobj):
func = getattr(funcobj, '_callable', None)
if sandbox:
- review = getattr(func, '_sandbox_review_', None)
- if review is not None and review != 'check_caller':
+ if hasattr(func, '_sandbox_review_'):
return True
return getattr(func, '_dont_inline_', False)
return dont_inline
diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py
--- a/rpython/translator/c/node.py
+++ b/rpython/translator/c/node.py
@@ -882,9 +882,9 @@
def new_funcnode(db, T, obj, forcename=None):
from rpython.rtyper.rtyper import llinterp_backend
- if db.sandbox:
- if (getattr(obj, 'external', None) is not None and
- not obj._safe_not_sandboxed):
+ if db.sandbox and getattr(obj, 'external', None) is not None:
+ safe_flag = obj._safe_not_sandboxed
+ if not (safe_flag is True or safe_flag == "check_caller"):
try:
sandbox_mapping = db.sandbox_mapping
except AttributeError:
diff --git a/rpython/translator/sandbox/graphchecker.py b/rpython/translator/sandbox/graphchecker.py
--- a/rpython/translator/sandbox/graphchecker.py
+++ b/rpython/translator/sandbox/graphchecker.py
@@ -19,10 +19,19 @@
safe_operations = set([
'keepalive', 'threadlocalref_get', 'threadlocalref_store',
'malloc', 'malloc_varsize', 'free',
- 'getfield', 'getarrayitem', 'getinteriorfield',
- 'gc_thread_run',
- 'shrink_array', 'gc_pin', 'gc_unpin', 'gc_can_move',
- 'debug_fatalerror',
+ 'getfield', 'getarrayitem', 'getinteriorfield', 'raw_load',
+ 'cast_opaque_ptr', 'cast_ptr_to_int',
+ 'gc_thread_run', 'gc_stack_bottom', 'gc_thread_after_fork',
+ 'shrink_array', 'gc_pin', 'gc_unpin', 'gc_can_move', 'gc_id',
+ 'gc_identityhash', 'weakref_create', 'weakref_deref',
+ 'gc_fq_register', 'gc_fq_next_dead',
+ 'gc_set_max_heap_size', 'gc_ignore_finalizer', 'gc_add_memory_pressure',
+ 'gc_writebarrier', 'gc__collect',
+ 'length_of_simple_gcarray_from_opaque',
+ 'debug_fatalerror', 'debug_print_traceback', 'debug_flush',
+ 'hint', 'debug_start', 'debug_stop', 'debug_print', 'debug_offset',
+ 'jit_force_quasi_immutable', 'jit_force_virtual', 'jit_marker',
+ 'jit_is_virtual',
])
gc_set_operations = set([
'setfield', 'setarrayitem', 'setinteriorfield',
@@ -69,9 +78,13 @@
if hasattr(obj, 'graph'):
g2 = obj.graph
if graph_review(g2) == 'check_caller':
- return "caller has not been checked: %r" % (op,)
- elif getattr(obj, 'sandboxsafe', False):
- pass
+ return ("direct_call to a graph with "
+ "check_caller=True: %r" % (op,))
+ elif getattr(obj, '_safe_not_sandboxed', False) is not False:
+ ss = obj._safe_not_sandboxed
+ if ss is not True:
+ return ("direct_call to llfunc with "
+ "sandboxsafe=%r: %r" % (ss, obj))
elif getattr(obj, 'external', None) is not None:
# either obj._safe_not_sandboxed is True, and then it's
# fine; or obj._safe_not_sandboxed is False, and then
@@ -81,7 +94,15 @@
# not 'external', but no 'graph' either?
return "direct_call to %r" % (obj,)
- elif opname in ('cast_ptr_to_adr', 'force_cast'):
+ elif opname == 'indirect_call':
+ graph_list = op.args[-1].value
+ for g2 in graph_list:
+ if graph_review(g2) == 'check_caller':
+ return ("indirect_call that can go to at least one "
+ "graph with check_caller=True: %r" % (op,))
+
+ elif opname in ('cast_ptr_to_adr', 'force_cast',
+ 'cast_int_to_ptr'):
if is_gc_ptr(op.args[0].concretetype):
return "argument is a GC ptr: %r" % (opname,)
if is_gc_ptr(op.result.concretetype):
diff --git a/rpython/translator/sandbox/rsandbox.py b/rpython/translator/sandbox/rsandbox.py
--- a/rpython/translator/sandbox/rsandbox.py
+++ b/rpython/translator/sandbox/rsandbox.py
@@ -6,7 +6,7 @@
import py
import sys
-from rpython.rlib import types
+from rpython.rlib import types, debug
from rpython.rlib.objectmodel import specialize
from rpython.rlib.signature import signature
from rpython.rlib.unroll import unrolling_iterable
@@ -20,6 +20,7 @@
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
from rpython.tool.ansi_print import AnsiLogger
+from rpython.translator.sandbox.graphchecker import make_abort_graph
log = AnsiLogger("sandbox")
@@ -99,34 +100,43 @@
lltype.typeOf(rpy_sandbox_arg[arg_kind]).TO.ARGS[0])
for arg_kind in arg_kinds])
- result_func = rpy_sandbox_res[result_kind]
- RESTYPE = FUNCTYPE.RESULT
+ if fnobj._safe_not_sandboxed == 'abort':
- try:
- lst = rtyper._sandboxed_functions
- except AttributeError:
- lst = rtyper._sandboxed_functions = []
- name_and_sig = '%s(%s)%s' % (fnname, ''.join(arg_kinds), result_kind)
- lst.append(name_and_sig)
- log(name_and_sig)
- name_and_sig = rffi.str2charp(name_and_sig, track_allocation=False)
+ msg = "sandboxed subprocess aborts on call to %r" % (fnname,)
+ def execute(*args):
+ debug.fatalerror(msg)
- def execute(*args):
- #
- # serialize the arguments
- i = 0
- for arg_kind, func, ARGTYPE in unroll_args:
- if arg_kind == 'v':
- continue
- func(rffi.cast(ARGTYPE, args[i]))
- i = i + 1
- #
- # send the function name and the arguments and wait for an answer
- result = result_func(name_and_sig)
- #
- # result the answer, if any
- if RESTYPE is not lltype.Void:
- return rffi.cast(RESTYPE, result)
+ else:
+
+ result_func = rpy_sandbox_res[result_kind]
+ RESTYPE = FUNCTYPE.RESULT
+
+ try:
+ lst = rtyper._sandboxed_functions
+ except AttributeError:
+ lst = rtyper._sandboxed_functions = []
+ name_and_sig = '%s(%s)%s' % (fnname, ''.join(arg_kinds), result_kind)
+ lst.append(name_and_sig)
+ log(name_and_sig)
+ name_and_sig = rffi.str2charp(name_and_sig, track_allocation=False)
+
+ def execute(*args):
+ #
+ # serialize the arguments
+ i = 0
+ for arg_kind, func, ARGTYPE in unroll_args:
+ if arg_kind == 'v':
+ continue
+ func(rffi.cast(ARGTYPE, args[i]))
+ i = i + 1
+ #
+ # send the function name and the arguments and wait for an answer
+ result = result_func(name_and_sig)
+ #
+ # result the answer, if any
+ if RESTYPE is not lltype.Void:
+ return rffi.cast(RESTYPE, result)
+ #
execute.__name__ = 'sandboxed_%s' % (fnname,)
#
args_s, s_result = sig_ll(fnobj)
diff --git a/rpython/translator/sandbox/test/test_graphchecker.py b/rpython/translator/sandbox/test/test_graphchecker.py
--- a/rpython/translator/sandbox/test/test_graphchecker.py
+++ b/rpython/translator/sandbox/test/test_graphchecker.py
@@ -21,11 +21,11 @@
def check_safe(self, fn, signature=[]):
result = self.graph_is_unsafe(fn, signature)
- assert result is None, repr(fn)
+ assert result is None
def check_unsafe(self, error_substring, fn, signature=[]):
result = self.graph_is_unsafe(fn, signature)
- assert result is not None, repr(fn)
+ assert result is not None
assert error_substring in result
def test_simple(self):
@@ -60,7 +60,7 @@
pass
def f():
g()
- self.check_unsafe("caller has not been checked", f)
+ self.check_unsafe("direct_call to a graph with check_caller=True", f)
def test_direct_call_to_reviewed(self):
@sandbox_review(reviewed=True)
@@ -78,20 +78,46 @@
g()
self.check_safe(f)
+ def test_indirect_call_to_check_caller(self):
+ class A:
+ def meth(self, i):
+ pass
+ class B(A):
+ def meth(self, i):
+ pass
+ class C(A):
+ @sandbox_review(check_caller=True)
+ def meth(self, i):
+ pass
+ def f(i):
+ if i > 5:
+ x = B()
+ else:
+ x = C()
+ x.meth(i)
+ self.check_unsafe("indirect_call that can go to at least one "
+ "graph with check_caller=True", f, [int])
+
def test_direct_call_external(self):
llfn1 = rffi.llexternal("foobar", [], lltype.Void, sandboxsafe=True,
_nowrapper=True)
- self.check_safe(lambda: llfn1)
+ self.check_safe(lambda: llfn1())
#
llfn2 = rffi.llexternal("foobar", [], lltype.Void, sandboxsafe=False,
_nowrapper=True)
- self.check_safe(lambda: llfn2) # will be turned into an I/O stub
+ self.check_safe(lambda: llfn2()) # will be turned into an I/O stub
+ #
+ llfn2b = rffi.llexternal("foobar", [], lltype.Void,
+ sandboxsafe="check_caller",
+ _nowrapper=True)
+ self.check_unsafe("direct_call to llfunc with "
+ "sandboxsafe='check_caller'", lambda: llfn2b())
#
llfn3 = rffi.llexternal("foobar", [], lltype.Void, sandboxsafe=True)
- self.check_safe(lambda: llfn3)
+ self.check_safe(lambda: llfn3())
#
llfn4 = rffi.llexternal("foobar", [], lltype.Void, sandboxsafe=False)
- self.check_safe(lambda: llfn4)
+ self.check_safe(lambda: llfn4())
def test_make_abort_graph(self):
def dummy():
More information about the pypy-commit
mailing list