On Fri, 2023-09-01 at 09:12 -0400, Robert Haas wrote: > Close but not quite. As you say, #2 does exercise privileges. Also, > even if no privileges are exercised, you could still refer to > CURRENT_ROLE, and I think you could also call a function like > has_table_privilege. Your identity hasn't changed, but you're > restricted from exercising some of your privileges. Really, you still > have them, but they're just not available to you in that situation.
Which privileges are available in a sandboxed environment, exactly? Is it kind of like masking away all privileges except EXECUTE, or are other privileges available, like SELECT? And the distinction that you are drawing between having the privileges but them (mostly) not being available, versus not having the privileges at all, is fairly subtle. Some examples showing why that distinction is important would be helpful. > > > Although your proposal sounds like a good security backstop, it > > feels > > like it's missing the point that there are different _kinds_ of > > functions. We already have the IMMUTABLE marker and we already have > > runtime checks to make sure that immutable functions can't CREATE > > TABLE; why not build on that mechanism or create new markers? ... > Here, however, we can't trust the owners > of functions to label those functions accurately. Of course, but observe: =# CREATE FUNCTION f(i INT) RETURNS INT IMMUTABLE LANGUAGE plpgsql AS $$ BEGIN CREATE TABLE x(t TEXT); RETURN 42 + i; END; $$; =# SELECT f(2); ERROR: CREATE TABLE is not allowed in a non-volatile function CONTEXT: SQL statement "CREATE TABLE x(t TEXT)" PL/pgSQL function f(integer) line 3 at SQL statement The function f() is called at the top level, not as part of any index expression or other special context. But it fails to CREATE TABLE simply because that's not an allowed thing for an IMMUTABLE function to do. That tells me right away that my function isn't going to work, and I can rewrite it rather than waiting for some other user to say that it failed when run in a sandbox. > It won't do for > Alice to create a function and then apply the NICE_AND_SAFE marker to > it. You can if you always execute NICE_AND_SAFE functions in a sandbox. The difference is that it's always executed in a sandbox, rather than sometimes, so it will fail consistently. > Now, in the case of a C function, things are a bit different. We > can't > inspect the generated machine code and know what the function does, > because of that pesky halting problem. We could handle that either > through function labeling, since only superusers can create C > functions, or by putting checks directly in the C code. I was > somewhat > inclined toward the latter approach, but I'm not completely sure yet > what makes sense. Thinking about your comments here made me realize > that there are other procedural languages to worry about, too, like > PL/python or PL/perl or PL/sh. Whatever we do for the C functions > will > have to be extended to those cases somehow as well. If we label > functions, then we'll have to allow superusers only to label > functions > in these languages as well and make the default label "this is > unsafe." If we put checks in the C code then I guess any given PL > needs to certify that it knows about sandboxing or have all of its > functions treated as unsafe. I think doing this at the C level would > be better, strictly speaking, because it's more granular. Imagine a > function that only conditionally does some prohibited action - it can > be allowed to work in the cases where it does not attempt the > prohibited operation, and blocked when it does. Labeling is > all-or-nothing. Here I'm getting a little lost in what you mean by "prohibited operation". Most languages mostly use SPI, and whatever sandboxing checks you do should work there, too. Are you talking about completely separate side effects like writing files or opening sockets? Regards, Jeff Davis