Author: Armin Rigo <[email protected]>
Branch: sandbox-2
Changeset: r97295:f4ba641484fa
Date: 2019-08-27 10:33 +0200
http://bitbucket.org/pypy/pypy/changeset/f4ba641484fa/
Log: Write docs about the @sandbox_review() and
llexternal(sandboxsafe=..).
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
@@ -2,8 +2,92 @@
This runs at the start of the database-c step, so it excludes the
graphs produced later, notably for the GC. These are "low-level"
graphs that are assumed to be safe.
+
+Here are again the rules around this check.
+
+- any graph that contains only "safe" lloperations is itself "safe".
+ The "safe" lloperations are the ones marked "tryfold" in
+ rtyper.lltypesystem.lloperation, plus the ones listed explicitly below,
+ plus a few variants of specific operations coded in graph_in_unsafe().
+
+- any graph decorated with @objectmodel.sandbox_review() is "safe".
+ The different flags we can pass to @sandbox_review() are explained next,
+ but the decorated graph is itself always "safe".
+
+- "unsafe" operations are all special rare operations, plus most importantly
+ all *writes* into raw memory. We assume that *reads* from anywhere are
+ OK to ignore: any information that reaches the sandboxed process can be
+ detected and used by anything that runs inside this process (i.e. there
+ is no really "secret" data inside the sandboxed subprocess itself).
+ At worst, random reads will lead to segfaults. But random writes are not
+ safe because that could corrupt memory---e.g. overwrite some GC object
+ header, or even (although I'm not sure how) actually cause the sandboxed
+ process to misbehave in more important ways like doing actual system calls
+ that are supposed to be forbidden.
+
+- the decorator @sandbox_review(check_caller=True) means that the graph is
+ safe, but any call to this graph from somewhere else is an unsafe operation.
+ This forces all callers to also be reviewed and marked with some form of
+ @sandbox_review().
+
+- @sandbox_review(reviewed=True) means that the graph is safe and all
+ calls to this graph are also safe. This should only be used on functions
+ that do internally "unsafe" stuff like writing to raw memory but don't
+ take arguments that could lead them to do bogus things. A typical counter-
+ example is a function that takes a raw pointer and that writes something to
+ it; this should *not* be marked with reviewed=True. On the other hand, many
+ RPython wrappers to external C functions can be reviewed=True because
+ they translate GC-safe information (say an RPython string) to raw memory,
+ do the call, and translate the result back to GC-safe information.
+
+- @sandbox_review(abort=True) is reserved for cases where calling this
+ function at runtime should just immediately abort the subprocess.
+
+Note that all flags above should be considered independently of what the
+actual C function calls are supposed to do. For example, the RPython
+wrapper rposix.system() is something you definitely don't want to allow as-is,
+but the wrapper and the call to the C function are fine. It's up to the
+controlling process to refuse to reply to the system() external call
+(either by having it return ENOSYS or a similar error, or by killing the
+sandboxed process completely).
+
+Like system(), all calls to external C functions are *by default* removed and
+turned into I/O on stdin/stdout, asking the parent controlling process what
+to do. This is controlled in more details by rffi.llexternal(). It takes
+its own argument "sandboxsafe", which can be one of the following values:
+
+- sandboxsafe=False (the default): the external C call is not done but turned
+ into I/O on stdin/stdout. Moreover, *if* the function takes or returns a
+ raw pointer, then it is flagged with @sandbox_review(check_caller=True) to
+ ensure that all callers do something sane with these raw pointers. If
+ the C function only takes and returns integer or float arguments, there is
+ no real need, so in this case we flag @sandbox_review(reviewed=True) instead.
+
+- sandboxsafe=True: means the external call should be done straight from the
+ sandboxed process. Reserved for specific functions like rposix.c_strerror(),
+ or some memory-manipulation functions used by the GC itself.
+
+- sandboxsafe="abort": like @sandbox_review(abort=True).
+
+- sandboxsafe="check_caller": forces @sandbox_review(check_caller=True).
+ Useful for llexternal() functions that appear to return an integer but
+ that's really some address that must be carefully managed.
+
+- sandboxsafe="nowrite": forces @sandbox_review(reviewed=True). This is OK
+ for C functions that have pointer arguments but none of them can point
+ to anything that will be written to (hence the name). The idea is that
+ for the common case of a function that takes a "const char *" argument,
+ we should just mark that function as reviewed=True, because it is safe:
+ the controller process will at most read things from the sandboxed process,
+ namely what the pointer points to, but it should not attempt to do any
+ write into the sandboxed process' memory. Typically the caller itself
+ calls rffi.str2charp() and rffi.free_charp() around the call, but these
+ are also @sandbox_review(reviewed=True) helpers, so such a caller doesn't
+ need to be explicitly reviewed.
+
"""
+
from rpython.flowspace.model import SpaceOperation, Constant
from rpython.rtyper.rmodel import inputconst
from rpython.rtyper.lltypesystem import lltype, llmemory, rstr
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit