From: | Jeff Davis <pgsql(at)j-davis(dot)com> |
---|---|
To: | Robert Haas <robertmhaas(at)gmail(dot)com> |
Cc: | Andres Freund <andres(at)anarazel(dot)de>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Noah Misch <noah(at)leadboat(dot)com> |
Subject: | Re: sandboxing untrusted code |
Date: | 2023-09-01 00:57:25 |
Message-ID: | c43bf10e0b8774e54befaad3d616c2eed0028034.camel@j-davis.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-hackers |
On Thu, 2023-08-31 at 11:25 -0400, Robert Haas wrote:
> As a refresher, the scenario I'm talking about is any one in which
> one
> user, who I'll call Bob, does something that results in executing
> code
> provided by another user, who I'll call Alice. The most obvious way
> that this can happen is if Bob performs some operation that targets a
> table owned by Alice. That operation might be DML, like an INSERT or
> UPDATE; or it might be some other kind of maintenance command that
> can
> cause code execution, like REINDEX, which can evaluate index
> expressions.
REINDEX executes index expressions as the table owner. (You are correct
that INSERT executes index expressions as the inserting user.)
> The code being executed might be run either as Alice or
> as Bob, depending on how it's been attached to the table and what
> operation is being performed and maybe whether some function or
> procedure that might contain it is SECURITY INVOKER or SECURITY
> DEFINER. Regardless of the details, our concern is that Alice's code
> might do something that Bob does not like. This is a particularly
> lively concern if the code happens to be running with the privileges
> of Bob, because then Alice might try to do something like access
> objects for which Bob has permissions and Alice does not.
Agreed.
> 1. Compute stuff. There's no restriction on the permissible amount of
> compute; if you call untrusted code, nothing prevents it from running
> forever.
> 2. Call other code. This may be done by a function call or a command
> such as CALL or DO, all subject to the usual permissions checks but
> no
> further restrictions.
> 3. Access the current session state, without modifying it. For
> example, executing SHOW or current_setting() is fine.
> 4. Transiently modify the current session state in ways that are
> necessarily reversed before returning to the caller. For example, an
> EXCEPTION block or a configuration change driven by proconfig is
> fine.
> 5. Produce messages at any log level. This includes any kind of
> ERROR.
Nothing in that list really exercises privileges (except #2?). If those
are the allowed set of things a sandboxed function can do, is a
sandboxed function equivalent to a function running with no privileges
at all?
Please explain #2 in a bit more detail. Whose EXECUTE privileges would
be used (I assume it depende on SECURITY DEFINER/INVOKER)? Would the
called code also be sandboxed?
> In general if we have a great big call stack that involves calling a
> whole bunch of functions either as SECURITY INVOKER or as SECURITY
> DEFINER, changing the session state is blocked unless the session
> user
> trusts the owners of all of those functions.
That clarifies the earlier mechanics you described, thank you.
> And if we got to any of
> those functions by means of code attached directly to tables, like an
> index expression or default expression, changing the session state is
> blocked unless the session user also trusts the owners of those
> tables.
>
> I see a few obvious objections to this line of attack that someone
> might raise, and I'd like to address them now. First, somebody might
> argue that this is too hard to implement.
That seems to be a response to my question above: "Isn't that a hard
problem; maybe impossible?".
Let me qualify that: if the function is written by Alice, and the code
is able to really exercise the privileges of the caller (Bob), then it
seems really hard to make it safe for the caller.
If the function is sandboxed such that it's not really using Bob's
privileges (it's just nominally running as Bob) that's a much more
tractable problem.
I believe there's some nuance to your proposal where some of Bob's
privileges could be used safely, but I'm not clear on exactly which
ones. The difficulty of the implementation would depend on these
details.
> Second, somebody might argue that full sandboxing is such a
> draconian set of restrictions that it will inconvenience users
> greatly
> or that it's pointless to even allow anything to be executed or
> something along those lines. I think that argument has some merit,
> but
> I think the restrictions sound worse than they actually are in
> context.
+100. We should make typical cases easy to secure.
> Even if they do something as
> simple as reading from another table, that's not necessarily going to
> dump and restore properly, even if it's secure, because the table
> ordering dependencies won't be clear to pg_dump.
A good point. A lot of these extraordinary cases are either incredibly
fragile or already broken.
> What if such a function wants to ALTER ROLE ...
> SUPERUSER? I think that's bonkers and should almost certainly be
> categorically denied.
...also agreed, a lot of these extraordinary cases are really just
surface area for attack with no legitimate use case.
One complaint (not an objection, because I don't think we have
the luxury of objecting to viable proposals when it comes to improving
our security model):
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?
Declarative markers are nice because they are easier to test: if Alice
writes a function and declares it as IMMUTABLE, she can test it before
even using it in an index expression and it will fail whatever runtime
protections IMMUTABLE offers. If we instead base it on the session user
and call stack, Alice wouldn't be able to test it effectively, only Bob
can test it.
In other words, there are some consistency aspects to how we run code
that go beyond pure security. A function author typically has
assumptions about the execution context of a function (the user, the
sandbox restrictions, the search_path, etc.) and guiding users towards
a consistent execution context in typical cases is a good thing.
Regards,
Jeff Davis
From | Date | Subject | |
---|---|---|---|
Next Message | Michael Paquier | 2023-09-01 01:18:59 | Re: Show inline comments from pg_hba lines in the pg_hba_file_rules view |
Previous Message | Vik Fearing | 2023-09-01 00:50:43 | Re: More new SQL/JSON item methods |