Thread: Proposal: template-ify (binary) extensions

Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
Hi,

let me elaborate on an idea I had to streamline extension templates. As
I wrote in my recent review [1], I didn't have the mental model of a
template in mind for extensions, so far.

However, writing the review, I came to think of it. I certainly agree
that extensions which do not carry a binary executable can be considered
templates. The SQL scripts can be deleted after creation of the
extension in the database, because the objects created with them are an
instantiation in the database itself. They do not depend on the template.

That's not the case for compiled, executable code that usually lives in
a shared library on the filesystem. There, the "instantiation" of the
"template" merely consists of a link to the library on the file-system.
If you remove that file, you break the extension.

One way to resolve that - and that seems to be the direction Dimitri's
patch is going - is to make the extension depend on its template. (And
thereby breaking the mental model of a template, IMO. In the spirit of
that mental model, one could argue that code for stored procedures
shouldn't be duplicated, but instead just reference its ancestor.)

The other possible resolution is to make all extensions fit the template
model, i.e. make extensions independent of their templates.

This obviously requires Postgres to internalize the compiled binary code
of the library upon instantiation. (Storing the binary blobs by hash in
a shared catalog could easily prevent unwanted duplication between
databases.)

Advantages:- Consistent mental model: template- Closes the gap between how SQL scripts and binary parts of  an
extensionare handled. (Or between binary and non-binary  extensions.)- Compatibility and co-existence between
file-systemand  system catalog based extension templates is simplified.- Independence of extensions from library files
shippedby  3rd party extensions (those would only ship a template, not  the extension per se).- Paves the way to
uploadingextensions that carry a binary,  executable payload via libpq.
 

Challenges:- CPU Architecture must be taken into account for backups. Restoring  a backup on a different architecture
wouldstill require the  (external) binary code for that specific architecture, because we  cannot possibly store
binariesfor all architectures.- A bit of a mind shift for how binary extensions work.
 


Regards

Markus Wanner




Re: Proposal: template-ify (binary) extensions

From
Robert Haas
Date:
On Fri, Jul 5, 2013 at 4:27 PM, Markus Wanner <markus@bluegap.ch> wrote:
> One way to resolve that - and that seems to be the direction Dimitri's
> patch is going - is to make the extension depend on its template. (And
> thereby breaking the mental model of a template, IMO. In the spirit of
> that mental model, one could argue that code for stored procedures
> shouldn't be duplicated, but instead just reference its ancestor.)

The security problems with this model have been discussed in every
email thread about the extension template feature.  There is a lot of
(well-founded, IMHO) resistance to the idea of letting users install C
code via an SQL connection.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Proposal: template-ify (binary) extensions

From
Andres Freund
Date:
On 2013-07-14 23:49:47 -0400, Robert Haas wrote:
> On Fri, Jul 5, 2013 at 4:27 PM, Markus Wanner <markus@bluegap.ch> wrote:
> > One way to resolve that - and that seems to be the direction Dimitri's
> > patch is going - is to make the extension depend on its template. (And
> > thereby breaking the mental model of a template, IMO. In the spirit of
> > that mental model, one could argue that code for stored procedures
> > shouldn't be duplicated, but instead just reference its ancestor.)
> 
> The security problems with this model have been discussed in every
> email thread about the extension template feature.  There is a lot of
> (well-founded, IMHO) resistance to the idea of letting users install C
> code via an SQL connection.

I still fail how to see that that argument has much merits:
CREATE EXTENSION adminpack;
CREATE OR REPLACE FUNCTION pg_catalog.pg_binary_file_write(text, bytea, boolean)RETURNS bigintLANGUAGE cSTRICT
AS '$libdir/adminpack', $function$pg_file_write$function$

SELECT pg_binary_file_write('some-path.so', 'some-so-as-bytea'::bytea, 1);
LOAD '/var/lib/postgresql/9.2/main/some-path.so';

All done with the default contribs, without even a PL. It's obviously
even more trivial if you have access to plpython or plperlu. You can do
similar nastiness without even contrib installed misusing binary COPY or
possibly even using tuplesort tapes.

A superuser can execute native code as postges user. That's it.


Now, I don't think Markus proposal is a good idea on *other* grounds
though... but that's for another email.

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
Robert,

thanks for answering. I think you responded to the (or some) idea in
general, as I didn't see any relation to the quoted part. (Otherwise
this is a hint that I've not been clear enough.)

On 07/15/2013 05:49 AM, Robert Haas wrote (in a slightly different order):
> There is a lot of
> (well-founded, IMHO) resistance to the idea of letting users install C
> code via an SQL connection.

Nowhere did I propose anything close to that. I'm in full support of the
resistance. Pitchforks and torches ready to rumble. :-)

> The security problems with this model have been discussed in every
> email thread about the extension template feature.

I read through a lot of these discussions, recently, but mostly found
misunderstanding and failure to distinguish between available extension
(template) and created extension (instantiation). I think this is a new
proposal, which I didn't ever see discussed. It does not have much, if
anything, to do with Dimitri's patch, except for it having made the
point obvious to me, as it continues to mix the two mental models.

I don't see much of a difference security wise between loading the DSO
at extension creation time vs. loading it at every backend start. More
details below.

My major gripe with the current way extensions are handled is that SQL
scripts are treated as a template, where as the DSO is only "pointed
to". Changing the SQL scripts in your extension directory has no effect
to the installed extension. Modifying the DSO file certainly has. That's
the inconsistency that I'd like to get rid of.


A security analysis of the proposal follows.

Granted, the "internalization" of the DSO is somewhat critical to
implement. Running as a non-root user, Postgres has less power than that
and can certainly not protect the internalized DSO from modification by
root. It can, however, store the DSO well protected from other users
(e.g. in a directory within $PGDATA).

Relying on the external DSO only exactly once can provide additional
safety. Consider an extensions directory that's accidentally
world-writable. As it stands, an attacker can modify the DSO and gain
control as soon as a new connection loads it. With my proposal, the
attacker would have to wait until CREATE EXTENSION. A point in time
where the newly created extension is more likely to be tested and
cross-checked.

I'm arguing both of these issues are very minor and negligible, security
wise. Baring other issues, I conclude there's no security impact by this
proposal.

Arguably, internalizing the DSO (together with the SQL) protects way
better from accidental modifications (i.e. removing the DSO by
un-installing the extension template via the distribution's packaging
system while some database still has the extension instantiated). That
clearly is a usability and not a security issue, though.

If nothing else (and beneficial in either case): Postgres should
probably check the permissions on the extension directory and at least
emit a warning, if it's world-writable. Or refuse to create (or even
load) an extension, right away.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Andres Freund
Date:
On 2013-07-15 12:12:36 +0200, Markus Wanner wrote:
> Granted, the "internalization" of the DSO is somewhat critical to
> implement. Running as a non-root user, Postgres has less power than that
> and can certainly not protect the internalized DSO from modification by
> root. It can, however, store the DSO well protected from other users
> (e.g. in a directory within $PGDATA).

There's heaps of problems with that though. Think noexec mounts or selinux.

> Relying on the external DSO only exactly once can provide additional
> safety.

Not necessarily. Think of a distribution provided upgrade with a
security fix in an extension. On a machine with dozens of clusters. Now
you need to make sure each and every one of them has the new .so.

> Consider an extensions directory that's accidentally
> world-writable. As it stands, an attacker can modify the DSO and gain
> control as soon as a new connection loads it. With my proposal, the
> attacker would have to wait until CREATE EXTENSION. A point in time
> where the newly created extension is more likely to be tested and
> cross-checked.

I think protecting against the case where such directories are writable
is a rather bad argument. If anything screwed up those the postgres
binaries directory itself quite likely has also been changed and such.

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/15/2013 12:05 PM, Andres Freund wrote:
> A superuser can execute native code as postges user. That's it.

Oh, I though Robert meant postgres users, i.e. non-superusers.

I hereby withdraw my pitchforks: I'm certainly not opposing to simplify
the life of superusers, who already have the power.

> Now, I don't think Markus proposal is a good idea on *other* grounds
> though... but that's for another email.

Separation of concerns, huh? Good thing, thanks :-)

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Andres Freund
Date:
On 2013-07-15 12:20:15 +0200, Markus Wanner wrote:
> On 07/15/2013 12:05 PM, Andres Freund wrote:
> > A superuser can execute native code as postges user. That's it.
> 
> Oh, I though Robert meant postgres users, i.e. non-superusers.

Oh, I am talking about *postgres* superusers ;). The example provided
upthread doesn't require 'root' permissions but only database level
superuser permissions.


> I hereby withdraw my pitchforks: I'm certainly not opposing to simplify
> the life of superusers, who already have the power.

I think what dimitri has in mind could easily be delegating the
"dangerous" work to a suid binary which does policy checking and the
real install...

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/15/2013 12:19 PM, Andres Freund wrote:
> On 2013-07-15 12:12:36 +0200, Markus Wanner wrote:
>> Granted, the "internalization" of the DSO is somewhat critical to
>> implement. Running as a non-root user, Postgres has less power than that
>> and can certainly not protect the internalized DSO from modification by
>> root. It can, however, store the DSO well protected from other users
>> (e.g. in a directory within $PGDATA).
> 
> There's heaps of problems with that though. Think noexec mounts or selinux.

Good point.

Note, however, that "internalize" doesn't necessarily mean exactly that
approach. It could be yet another directory, even system wide, which any
distribution should well be able to prepare.

I intentionally left the "internalizing" somewhat undefined. It could
even be more equivalent to what is done with the SQL stuff, i.e. some
system catalog. But that just poses other implementation issues.
(Loading a DSO from memory doesn't sound very portable to me.)

>> Relying on the external DSO only exactly once can provide additional
>> safety.
> 
> Not necessarily. Think of a distribution provided upgrade with a
> security fix in an extension.

Ugh.. only to figure out the patched DSO is incompatible to the old
version of the SQL scripts? And therefore having to re-create the
extension, anyways? That only highlights why this difference in
treatment of SQL and DSO is troublesome.

> On a machine with dozens of clusters. Now
> you need to make sure each and every one of them has the new .so.

Agreed.

So this sounds like the other approach to unification may be more
useful: Linking the SQL scripts better and make them (re-)load from the
extensions directory, just like the DSOs.

> I think protecting against the case where such directories are writable
> is a rather bad argument.

I agree. That's why I'm neglecting he security implications and stated
there are none.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
Robert,

On 07/15/2013 12:12 PM, Markus Wanner wrote:
> On 07/15/2013 05:49 AM, Robert Haas wrote (in a slightly different order):
>> There is a lot of
>> (well-founded, IMHO) resistance to the idea of letting users install C
>> code via an SQL connection.
> 
> Nowhere did I propose anything close to that. I'm in full support of the
> resistance. Pitchforks and torches ready to rumble. :-)

To clarify: In the above agreement, I had the Postgres level ordinary
users in mind, who certainly shouldn't ever be able to upload and run
arbitrary native code.

I'm not quite as enthusiastic if you meant the system level user that
happens to have superuser rights on Postgres. As Andres pointed out,
there are some more holes to plug, if you want to lock down a superuser
account. [1]

I'm not quite clear what kind of "user" you meant in your statement above.

Regards

Markus Wanner


[1]: I see the theoretical benefits of providing yet another layer of
security. Closing the existing holes would require restricting LOAD, but
that seems to suffice (given the sysadmin makes sure he doesn't
accidentally provide any of the harmful extensions).

How about the (optional?) ability to restrict LOAD to directories and
files that are only root writable? Is that enough for a root to disallow
the untrusted Postgres superuser to run arbitrary native code? Or does
that still have other holes? How many real use cases does it break? How
many does it fix?



Re: Proposal: template-ify (binary) extensions

From
Robert Haas
Date:
On Mon, Jul 15, 2013 at 9:27 AM, Markus Wanner <markus@bluegap.ch> wrote:
> To clarify: In the above agreement, I had the Postgres level ordinary
> users in mind, who certainly shouldn't ever be able to upload and run
> arbitrary native code.
>
> I'm not quite as enthusiastic if you meant the system level user that
> happens to have superuser rights on Postgres. As Andres pointed out,
> there are some more holes to plug, if you want to lock down a superuser
> account. [1]
>
> I'm not quite clear what kind of "user" you meant in your statement above.

I'm talking about people who are accessing the database via SQL (with
or without superuser privileges) rather than people who are accessing
the database via the file system (regardless of which OS user they
authenticate as).  As things stand today, the only way to get machine
code to run inside the Postgres binary is to have local filesystem
access.  Andres points out that you can install adminpack to obtain
local filesystem access, and that is true.  But the system
administrator can also refuse to allow adminpack, and/or use selinux
or other mechanisms to prevent the postgres binary from writing a file
with execute permissions.

If, however, we change things so that Postgres can grab bits out of a
system catalog and map them, with execute permissions, into its own
memory space, and then jump to that address, we've effectively
installed a backdoor around those types of OS-level security measures.And we've made it quite a lot easier for a bad
guyto install a
 
rootkit within postgres.

Things aren't quite so bad if we write the bits to a file first and
then dynamically load the file.  That way at least noexec or similar
can provide protection.  But it still seems like a pretty dangerous
direction.  I'm inclined to think any such thing would have to be an
extension that administrators could enable at their own risk, rather
than something that we enabled by default.  Insufficient privilege
separation is one of the things that has made security on Microsoft
Windows such a huge problem over the last several decades; I don't
want us to emulate that.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/16/2013 01:27 AM, Robert Haas wrote:
> Andres points out that you can install adminpack to obtain
> local filesystem access, and that is true.  But the system
> administrator can also refuse to allow adminpack, and/or use selinux
> or other mechanisms to prevent the postgres binary from writing a file
> with execute permissions.

I think execute permissions (on the FS) are irrelevant. It's about
loading a shared library. The noexec mount option can prevent that, though.

But okay, you're saying we *have* and *want* a guarantee that even a
superuser cannot execute arbitrary native code via libpq (at least in
default installs w/o extensions).

Andres made two contrib-free suggestions: with COPY TO BINARY, you get a
header prepended, which I think is sufficient to prevent a dlopen() or
LoadLibrary(). Text and CSV formats of COPY escape their output, so it's
hard to write \000 or other control bytes. ESCAPE and DELIMITER also
have pretty restrictive requirements. So COPY doesn't seem quite "good"
enough to write a valid DSO.

His second suggestion was tuplesort tapes. tuplesort.c says: "We require
the first "unsigned int" of a stored tuple to be the total size on-tape
of the tuple...". That's kind of a header as well. Writing a proper DSO
certainly does not sound trivial, either.

From a security perspective, I wouldn't want to rely on that guarantee.
Postgres writes too many files to be sure none of those can be abused to
write a loadable DSO, IMO.

Mounting $PGDATA 'noexec' and allowing the postgres user to write only
to such noexec mounts sounds like a good layer. It's independent, though
- it can be used whether or not the above guarantee holds.

> Things aren't quite so bad if we write the bits to a file first and
> then dynamically load the file.  That way at least noexec or similar
> can provide protection.  But it still seems like a pretty dangerous
> direction.

I agree now. Thanks for elaborating.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Robert Haas
Date:
On Tue, Jul 16, 2013 at 3:14 PM, Markus Wanner <markus@bluegap.ch> wrote:
> But okay, you're saying we *have* and *want* a guarantee that even a
> superuser cannot execute arbitrary native code via libpq (at least in
> default installs w/o extensions).

Yes, that's a good way of summarizing my position.  I think I'd
support having an extension that allows that, although I don't think
I'd want such an extension installed on any machine I administer.  But
I oppose having it be something the server allows by default.  YMMV.
:-)

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Proposal: template-ify (binary) extensions

From
Dimitri Fontaine
Date:
Markus Wanner <markus@bluegap.ch> writes:
> But okay, you're saying we *have* and *want* a guarantee that even a
> superuser cannot execute arbitrary native code via libpq (at least in
> default installs w/o extensions).

There are several problems confused into that sentence already. I think
the next step of this discussion should be about talking about the
problems we have and figuring out *if* we want to solve them, now that
we managed to explicitely say what we want as a project.
 - per-installation (not even per-cluster) DSO availability
   If you install PostGIS 1.5 on a system, then it's just impossible to   bring another cluster (of the same PostgreSQL
majorversion), let   alone database, with PostGIS 2.x, even for migration assessment   purposes. The "By Design™" part
isreally hard to explain even to   security concious users. 
 - hot standby and modules (aka DSO)
   As soon as you use some functions in 'language C' you need to   carefully watch your external dependencies ahead of
time.If you do   CREATE EXTENSION hstore;, create an hstore column and a GiST index   on it, then query the table on
thestandby… no luck. You would tell   me that it's easy enough to do and that it's part of the job, so see   next
point.
 - sysadmin vs dba, or PostgreSQL meets the Cloud
   The current model of operations is intended for places where you   have separate roles: the sysadmin cares about the
OSsetup and will   provide with system packages (compiled extensions and the like), and   DBA are never root on the OS.
Theycan CREATE EXTENSION and maybe   use the 'postgres' system account, but that's about it. 
   Given the current raise of the Cloud environements and the devops   teams, my understanding is that this model is no
longerthe only   one. Depending on who you talk to, in some circles it's not even a   relevant model anymore: user
actionsshould not require the   intervention of a "sysadmin" before hand. 
   While I appreciate that many companies still want the old behavior   that used to be the only relevant model of
operations,I think we   should also provide for the new one as it's pervasive enough now for   us to stop ignoring it
withour "I know better" smiling face. 

Now it should be possible to solve at least some of those items while
still keeping the restriction above, or with an opt-in mechanism to
enable the "works by default, but you have to solve the security
implications yourself" behaviour. A new GUC should do it, boolean,
defaults false:
 runs_in_the_cloud_with_no_security_concerns = false

I don't think the relaxed behaviour we're talking about is currently
possible to develop as an extension, by the way.

> Andres made two contrib-free suggestions: with COPY TO BINARY, you get a

Well, what about using lo_import()?

>> Things aren't quite so bad if we write the bits to a file first and
>> then dynamically load the file.  That way at least noexec or similar
>> can provide protection.  But it still seems like a pretty dangerous
>> direction.
>
> I agree now. Thanks for elaborating.

Yes it's dangerous. It's also solving real world problems that I see no
other way to solve apart from bypassing the need to ever load a DSO
file, that is embedding a retargetable C compiler in the backend.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/17/2013 08:52 PM, Dimitri Fontaine wrote:
> the next step of this discussion should be about talking about the
> problems we have and figuring out *if* we want to solve them, now that
> we managed to explicitely say what we want as a project.
> 
>   - per-installation (not even per-cluster) DSO availability
> 
>     If you install PostGIS 1.5 on a system, then it's just impossible to
>     bring another cluster (of the same PostgreSQL major version), let
>     alone database, with PostGIS 2.x, even for migration assessment
>     purposes. The "By Design™" part is really hard to explain even to
>     security concious users.

On Debian, that should be well possible. Certainly installing Postgres
9.1 w/ postgis-1.5 in parallel to Postgres 9.2 w/ postgis-2.0 is. I
designed it to be.

On distributions that do not allow parallel installation of multiple
Postges major versions, it's certainly not the extension's fault.

I think I'm misunderstanding the problem statement, here.

>   - hot standby and modules (aka DSO)
> 
>     As soon as you use some functions in 'language C' you need to
>     carefully watch your external dependencies ahead of time. If you do
>     CREATE EXTENSION hstore;, create an hstore column and a GiST index
>     on it, then query the table on the standby… no luck. You would tell
>     me that it's easy enough to do and that it's part of the job, so see
>     next point.

Agreed, that's an area where Postgres could do better. I'd argue this
should be possible without relaxing the security guarantees provided,
though. Because there likely are people wanting both.

Can CREATE EXTENSION check if the standbys have the extension installed?
And refuse creation, if they don't?

>   - sysadmin vs dba, or PostgreSQL meets the Cloud
> 
>     The current model of operations is intended for places where you
>     have separate roles: the sysadmin cares about the OS setup and will
>     provide with system packages (compiled extensions and the like), and
>     DBA are never root on the OS. They can CREATE EXTENSION and maybe
>     use the 'postgres' system account, but that's about it.

I'm sure you are aware that even without this clear separation of roles,
the guarantee means we provide an additional level of security against
attackers.

>     Given the current raise of the Cloud environements and the devops
>     teams, my understanding is that this model is no longer the only
>     one. Depending on who you talk to, in some circles it's not even a
>     relevant model anymore: user actions should not require the
>     intervention of a "sysadmin" before hand.
> 
>     While I appreciate that many companies still want the old behavior
>     that used to be the only relevant model of operations, I think we
>     should also provide for the new one as it's pervasive enough now for
>     us to stop ignoring it with our "I know better" smiling face.

I'd even think it's a minority who actually uses the guarantee we're
talking about. Mostly because of the many and wide spread untrusted PLs
(which undermine the guarantee). And thus even before the rise of the cloud.

None the less, the "safe by default" has served us well, I think.

> Now it should be possible to solve at least some of those items while
> still keeping the restriction above, or with an opt-in mechanism to
> enable the "works by default, but you have to solve the security
> implications yourself" behaviour. A new GUC should do it, boolean,
> defaults false:
> 
>   runs_in_the_cloud_with_no_security_concerns = false

[ I usually associate "cloud" with (increased) "security concerns", but that's an entirely different story. ]

> I don't think the relaxed behaviour we're talking about is currently
> possible to develop as an extension, by the way.

It's extensions that undermine the guarantee, at the moment. But yeah,
it depends a lot on what kind of "relaxed behavior" you have in mind.

>> Andres made two contrib-free suggestions: with COPY TO BINARY, you get a
> 
> Well, what about using lo_import()?

That only reads from the file-system. You probably meant lo_export(),
which is writing. Although not on the server's, but only on the (libpq)
client's file-system. No threat to the server.

> Yes it's dangerous. It's also solving real world problems that I see no
> other way to solve apart from bypassing the need to ever load a DSO
> file, that is embedding a retargetable C compiler in the backend.

If the sysadmin wants to disallow arbitrary execution of native code to
postgres (the process), any kind of embedded compiler likely is equally
unwelcome.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Dimitri Fontaine
Date:
Markus Wanner <markus@bluegap.ch> writes:
>>   - per-installation (not even per-cluster) DSO availability
>>
>>     If you install PostGIS 1.5 on a system, then it's just impossible to
>>     bring another cluster (of the same PostgreSQL major version), let
> On Debian, that should be well possible. Certainly installing Postgres
> 9.1 w/ postgis-1.5 in parallel to Postgres 9.2 w/ postgis-2.0 is. I
> designed it to be.
>
> I think I'm misunderstanding the problem statement, here.

(of the same PostgreSQL major version)

> Can CREATE EXTENSION check if the standbys have the extension installed?
> And refuse creation, if they don't?

No, because we don't register standbies so we don't know who they are,
and also because some things that we see connected and using the
replication protocol could well be pg_basebackup or pg_receivexlog.

Also, it's possible that the standby is only there for High Availability
purposes and runs no user query.

> I'm sure you are aware that even without this clear separation of roles,
> the guarantee means we provide an additional level of security against
> attackers.

Given lo_import() to upload a file from the client to the server then
LOAD with the absolute path where the file ended up imported (or any
untrusted PL really), this argument carries no sensible weight in my
opinion.

> None the less, the "safe by default" has served us well, I think.

That's true. We need to consider carefully the proposal at hand though.

It's all about allowing the backend to automatically load a file that it
finds within its own $PGDATA so that we can have per-cluster and
per-database modules (DSO files).

The only difference with before is the location where the file is read
from, and the main security danger comes from the fact that we used to
only consider root-writable places and now propose to consider postgres
bootstrap user writable places.

Having the modules in different places in the system when it's a
template and when it's instanciated allows us to solve a problem I
forgot to list:
 - upgrading an extension at the OS level
   Once you've done that, any new backend will load the newer module   (DSO file), so you have to be real quick if
installingan hot fix in   production and the SQL definition must be changed to match the new   module version… 

With the ability to "instanciate" the module in a per-cluster
per-database directory within $PGDATA the new version of the DSO module
would only put in place and loaded at ALTER EXTENSION UPDATE time.

I'm still ok with allowing to fix those problems only when a security
option that defaults to 'false' has been switched to 'true', by the way,
so that it's an opt-in, but I will admit having a hard time swallowing
the threat model we're talking about…

>> I don't think the relaxed behaviour we're talking about is currently
>> possible to develop as an extension, by the way.
>
> It's extensions that undermine the guarantee, at the moment. But yeah,
> it depends a lot on what kind of "relaxed behavior" you have in mind.

The ability to load a module from another place than the current
Dynamic_library_path is what we're talking about here, and IIUC Robert
mentioned that maybe it could be down to an extension to allow for
changing the behavior. I didn't look at that in details but I would be
surprised to be able to tweak that without having to patch the backend.

> If the sysadmin wants to disallow arbitrary execution of native code to
> postgres (the process), any kind of embedded compiler likely is equally
> unwelcome.

You already mentioned untrusted PL languages, and I don't see any
difference in between offering PL/pythonu and PL/C on security grounds,
really. I don't think we would consider changing the current model of
the "LANGUAGE C" PL, we would add a new "LANGUAGE PL/C" option, either
untrusted or with a nice sandbox.

The problem of sandboxing PL/C is that it makes it impossible to address
such use cases as uuid or PostGIS extensions even if it still allows for
hstore or other datatypes styles of extensions.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
Salut Dimitri,

On 07/20/2013 01:23 AM, Dimitri Fontaine wrote:
> Markus Wanner <markus@bluegap.ch> writes:
>>>   - per-installation (not even per-cluster) DSO availability
>>>
>>>     If you install PostGIS 1.5 on a system, then it's just impossible to
>>>     bring another cluster (of the same PostgreSQL major version), let
>> On Debian, that should be well possible. Certainly installing Postgres
>> 9.1 w/ postgis-1.5 in parallel to Postgres 9.2 w/ postgis-2.0 is. I
>> designed it to be.
>>
>> I think I'm misunderstanding the problem statement, here.
> 
> (of the same PostgreSQL major version)

Not sure what the issue is, here, but I agree that should be possible.

>> Can CREATE EXTENSION check if the standbys have the extension installed?
>> And refuse creation, if they don't?
> 
> No, because we don't register standbies so we don't know who they are,
> and also because some things that we see connected and using the
> replication protocol could well be pg_basebackup or pg_receivexlog.

Can the standby check? In any case, these seem to be problems we can
solve without affecting security.

> Also, it's possible that the standby is only there for High Availability
> purposes and runs no user query.

Requiring the sysadmin to install the extensions there, too, seems
justified to me. Sounds like good advice, anyways.

>> I'm sure you are aware that even without this clear separation of roles,
>> the guarantee means we provide an additional level of security against
>> attackers.
> 
> Given lo_import() to upload a file from the client to the server then
> LOAD with the absolute path where the file ended up imported (or any
> untrusted PL really), this argument carries no sensible weight in my
> opinion.

lo_import() won't write a file for LOAD to load. An untrusted PL (or any
other extension allowing the superuser to do that) is currently required
to do that.

Or to put it another way: Trusted PLs exist for a good reason. And some
people just value security a lot and want that separation of roles.

>> None the less, the "safe by default" has served us well, I think.
> 
> That's true. We need to consider carefully the proposal at hand though.
> 
> It's all about allowing the backend to automatically load a file that it
> finds within its own $PGDATA so that we can have per-cluster and
> per-database modules (DSO files).

As someone mentioned previously, $PGDATA may well be mounted noexec, so
that seems to be a bad choice.

> The only difference with before is the location where the file is read
> from, and the main security danger comes from the fact that we used to
> only consider root-writable places and now propose to consider postgres
> bootstrap user writable places.

FWIW, I only proposed to let postgres check write permissions on
libraries it loads. IIUC we don't currently do that, yet. And Postgres
happily loads a world-writable library, ATM.

> Having the modules in different places in the system when it's a
> template and when it's instanciated allows us to solve a problem I
> forgot to list:
> 
>   - upgrading an extension at the OS level
> 
>     Once you've done that, any new backend will load the newer module
>     (DSO file), so you have to be real quick if installing an hot fix in
>     production and the SQL definition must be changed to match the new
>     module version…

I agree, that's a problem.

Alternatively, we could solve that problem the other way around: Rather
than template-ify the DSO, we could instead turn the objects created by
the SQL scripts into something that's more linked to the script.
Something that would reload as soon as the file on disk changes.

(Note how this would make out-of-line extensions a lot closer to the
in-line variant your recent patch adds? With the dependency between
"template" and "instantiation"?)

> With the ability to "instanciate" the module in a per-cluster
> per-database directory within $PGDATA the new version of the DSO module
> would only put in place and loaded at ALTER EXTENSION UPDATE time.
> 
> I'm still ok with allowing to fix those problems only when a security
> option that defaults to 'false' has been switched to 'true', by the way,
> so that it's an opt-in,

Okay, good.

For the issues you raised, I'd clearly prefer fixes that maintain
current security standards, though.

> but I will admit having a hard time swallowing
> the threat model we're talking about…

An attacker having access to a libpq connection with superuser rights
cannot currently run arbitrary native code. He can try a DOS by
exhausting system resources, but that's pretty far from being
invisible. Or he can delete valuable data. Maybe other nasty things. But
he should not be able to gain root access and remove its traces.

Dropping this barrier by installing an untrusted PL (or equally insecure
extensions), an attacker with superuser rights can trivially gain
root.

Of course, an attacker shouldn't gain superuser rights in the first
place. But if he did, you better stop him right there with yet another
fence.

>> It's extensions that undermine the guarantee, at the moment. But yeah,
>> it depends a lot on what kind of "relaxed behavior" you have in mind.
> 
> The ability to load a module from another place than the current
> Dynamic_library_path is what we're talking about here, and IIUC Robert
> mentioned that maybe it could be down to an extension to allow for
> changing the behavior. I didn't look at that in details but I would be
> surprised to be able to tweak that without having to patch the backend.

Well, an extension can certainly perform something akin to pg_dlopen().
And thus load pretty much any code it wants. However, I don't think an
extension can hook into CREATE EXTENSION, yet.

>> If the sysadmin wants to disallow arbitrary execution of native code to
>> postgres (the process), any kind of embedded compiler likely is equally
>> unwelcome.
> 
> You already mentioned untrusted PL languages, and I don't see any
> difference in between offering PL/pythonu and PL/C on security grounds,
> really.

I agree. However, this also means that any kind of solution it offers is
not a good one for the security conscious sysadmin.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Hannu Krosing
Date:
On 07/21/2013 10:30 PM, Markus Wanner wrote:
>> but I will admit having a hard time swallowing
>> the threat model we're talking about…
> An attacker having access to a libpq connection with superuser rights
> cannot currently run arbitrary native code. He can try a DOS by
> exhausting system resources, but that's pretty far from being
> invisible. Or he can delete valuable data. Maybe other nasty things. But
> he should not be able to gain root access and remove its traces.
>
> Dropping this barrier by installing an untrusted PL (or equally insecure
> extensions), an attacker with superuser rights can trivially gain
> root.
Could you elaborate ?

This is equivalent to claiming that any linux user can trivially gain root.

>>> If the sysadmin wants to disallow arbitrary execution of native code to
>>> postgres (the process), any kind of embedded compiler likely is equally
>>> unwelcome.
>> You already mentioned untrusted PL languages, and I don't see any
>> difference in between offering PL/pythonu and PL/C on security grounds,
>> really.
> I agree. However, this also means that any kind of solution it offers is
> not a good one for the security conscious sysadmin.
This is usually the case with a "security conscious sysadmin" - they very
seldom want to install anything.

A "cloud style"  solution to this problem is installing the whole
PostgreSQL
host in its own VM and deklegate all security to developers ;)
>
> Regards
>
> Markus Wanner
>
>


-- 
Hannu Krosing
PostgreSQL Consultant
Performance, Scalability and High Availability
2ndQuadrant Nordic OÜ




Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/22/2013 12:11 AM, Hannu Krosing wrote:
>> Dropping this barrier by installing an untrusted PL (or equally insecure
>> extensions), an attacker with superuser rights can trivially gain
>> root.
> Could you elaborate ?
> 
> This is equivalent to claiming that any linux user can trivially gain root.

Uh. Sorry, you're of course right, the attacker can only gain postgres
rights in that case. Thanks for correcting.

The point still holds. It's another layer that an attacker would have to
overcome.

>>> You already mentioned untrusted PL languages, and I don't see any
>>> difference in between offering PL/pythonu and PL/C on security grounds,
>>> really.
>> I agree. However, this also means that any kind of solution it offers is
>> not a good one for the security conscious sysadmin.
> This is usually the case with a "security conscious sysadmin" - they very
> seldom want to install anything.

Exactly. That's why I'm favoring solutions that don't require any
extension and keep the guarantee of preventing arbitrary native code.

Regards

Markus Wanner



Re: Proposal: template-ify (binary) extensions

From
Dimitri Fontaine
Date:
Markus Wanner <markus@bluegap.ch> writes:
>>>>   - per-installation (not even per-cluster) DSO availability
>
> Not sure what the issue is, here, but I agree that should be possible.

For any extension where the new package version is shipping the same .so
file name, you can only have one module on the whole system for a given
PostgreSQL major version. The extensions are per-database, the DSO
modules are per major-version (not even per-cluster).

That's the trade-off we currently need to make to be able to ship with
the current security protections we're talking about.

> Requiring the sysadmin to install the extensions there, too, seems
> justified to me. Sounds like good advice, anyways.

Yes, installing the same extensions on any standby as the ones installed
on the primary should be *required*. My idea to enforce that would be
with using Event Triggers on the standby, but how to be able to run them
when when the standby replay currently isn't opening a session is quite
a problem.

The other way to address that is of course PL/C.

> lo_import() won't write a file for LOAD to load. An untrusted PL (or any
> other extension allowing the superuser to do that) is currently required
> to do that.

Ok, here's the full worked out example:
 ~# select lo_import('/path/to/local/on/the/client/adminpack.so');  lo_import  -----------      82153 (1 row)  ~#
selectlo_export(82153, '/tmp/foo.so');  lo_export  -----------          1 (1 row)  ~# LOAD '/tmp/foo.so'; LOAD  ~#
CREATEFUNCTION pg_catalog.pg_file_write(text, text, bool)    RETURNS bigint AS '/tmp/foo.so', 'pg_file_write'
LANGUAGEC VOLATILE STRICT; CREATE FUNCTION  
> Or to put it another way: Trusted PLs exist for a good reason. And some
> people just value security a lot and want that separation of roles.

Yeah, security is important, but it needs to be addressing real threats
to have any value whatsoever. We'not talking about adding new big holes
as extensions containing modules are using LANGUAGE C in their script
and thus are already restricted to superuser. That part would not
change.

> As someone mentioned previously, $PGDATA may well be mounted noexec, so
> that seems to be a bad choice.

I don't understand. You want good default security policy in place, and
you're saying that using PGDATA allows for a really easy policy to be
implemented by people who don't want the feature. It seems to me to be
exactly what you want, why would that be a bad choice then?

>>   - upgrading an extension at the OS level
>>
>>     Once you've done that, any new backend will load the newer module
>>     (DSO file), so you have to be real quick if installing an hot fix in
>>     production and the SQL definition must be changed to match the new
>>     module version…
>
> I agree, that's a problem.
>
> Alternatively, we could solve that problem the other way around: Rather
> than template-ify the DSO, we could instead turn the objects created by
> the SQL scripts into something that's more linked to the script.
> Something that would reload as soon as the file on disk changes.

I think that's the wrong way to do it, because you generally want more
control over those two steps (preparing the template then instanciating
it) and you're proposing to completely lose the control and have them be
a single step instead.

Use case: shipping a new plproxy bunch of functions to 256 nodes. You
want to push the templates everywhere then just do the extension update
as fast as possible so that it appears to be about 'in sync'.

Pro-tip: you can use a plproxy function that runs the alter extension
update step using RUN ON ALL facility.

> (Note how this would make out-of-line extensions a lot closer to the
> in-line variant your recent patch adds? With the dependency between
> "template" and "instantiation"?)

Those dependencies are almost gone now except for being able to deal
with DROP TEMPLATE FOR EXTENSION and guaranteeing we can actually
pg_restore our pg_dump script.

I've been changing the implementation to be what you proposed because I
think it's making more sense (thanks!), and regression tests are
reflecting that. My github branch is up-to-date with the last changes
and I'm soon to send an updated patch that will be really as ready for
commit as possible without a commiter review.

> An attacker having access to a libpq connection with superuser rights
> cannot currently run arbitrary native code. He can try a DOS by

I think I showed a simple way to do that above in this very email.

> Well, an extension can certainly perform something akin to pg_dlopen().
> And thus load pretty much any code it wants. However, I don't think an
> extension can hook into CREATE EXTENSION, yet.

When you call a function, its MODULE_PATHNAME is getting loaded by the
backend. You would need to ship a dumb DSO module file so that this
works and arrange for the real DSO module file to be loaded via a hook
or an event trigger or something else (e.g. local_preload_libraries).

I don't see a way to be able to do that without changing the extension's
binary package, either replacing MODULE_PATHNAME in the sql script or in
the control file, or changing the DSO file itself and shipping the
genuine one in a new place.

In short, doing something different than the backend is currently doing
with respect to DSO modules looks like a core patch to me, and requires
a community agreement on the way to address the stated problems.

As it's all about security, reaching to an agreement strikes me as the
right thing to do.

> I agree. However, this also means that any kind of solution it offers is
> not a good one for the security conscious sysadmin.

Maybe we'll be able to find a way to offer PL/C in a "trusted" way.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
Dimitri,

On 07/22/2013 08:44 PM, Dimitri Fontaine wrote:
> That's the trade-off we currently need to make to be able to ship with
> the current security protections we're talking about.

Anything wrong with shipping postgis-1.5.so and postgis-2.0.so, as I we
for Debian?

> Ok, here's the full worked out example:
> 
>   ~# select lo_import('/path/to/local/on/the/client/adminpack.so');
>    lo_import 
>   -----------
>        82153
>   (1 row)
>   
>   ~# select lo_export(82153, '/tmp/foo.so');
>    lo_export 
>   -----------
>            1
>   (1 row)
>   
>   ~# LOAD '/tmp/foo.so';
>   LOAD
>   
>   ~# CREATE FUNCTION pg_catalog.pg_file_write(text, text, bool)
>      RETURNS bigint AS '/tmp/foo.so', 'pg_file_write'
>      LANGUAGE C VOLATILE STRICT;
>   CREATE FUNCTION

Good point.

Note that these lo_import() and lo_export() methods - unlike the client
counterparts - read and write to the server's file system.

So, your example is incomplete in that SELECT lo_import() doesn't load
data from the client into the database. But there are many other ways to
do that.

None the less, your point holds: lo_export() is a way for a superuser to
write arbitrary files on the server's file-system via libpq.

>> Or to put it another way: Trusted PLs exist for a good reason. And some
>> people just value security a lot and want that separation of roles.
> 
> Yeah, security is important, but it needs to be addressing real threats
> to have any value whatsoever. We'not talking about adding new big holes
> as extensions containing modules are using LANGUAGE C in their script
> and thus are already restricted to superuser. That part would not
> change.

I agree, it's not a big hole. But with security, every additional layer
counts. I think the next step is to clarify whether or not we want to
provide that guarantee.

>> As someone mentioned previously, $PGDATA may well be mounted noexec, so
>> that seems to be a bad choice.
> 
> I don't understand. You want good default security policy in place, and
> you're saying that using PGDATA allows for a really easy policy to be
> implemented by people who don't want the feature. It seems to me to be
> exactly what you want, why would that be a bad choice then?

I'm just saying that mounting $PGDATA with noexec makes $PGDATA unusable
to load libraries from; i.e. pg_ldopen() just out right fails.

And noexec is another protective layer. Building a solution that
requires $PGDATA to be mounted with exec permissions means that very
solution won't work with that protective layer. Which is a bad thing.

>> Alternatively, we could solve that problem the other way around: Rather
>> than template-ify the DSO, we could instead turn the objects created by
>> the SQL scripts into something that's more linked to the script.
>> Something that would reload as soon as the file on disk changes.
> 
> I think that's the wrong way to do it, because you generally want more
> control over those two steps (preparing the template then instanciating
> it) and you're proposing to completely lose the control and have them be
> a single step instead.

Doesn't versioning take care of that? I.e. if you've version 1.0 created
in your databases and then install 1.1 system wide, that shouldn't
immediately "instantiate".

> Use case: shipping a new plproxy bunch of functions to 256 nodes. You
> want to push the templates everywhere then just do the extension update
> as fast as possible so that it appears to be about 'in sync'.
> 
> Pro-tip: you can use a plproxy function that runs the alter extension
> update step using RUN ON ALL facility.

Contrary use case: you actually *want* to *replace* the created version
installed, as it's a plain security fix that's backwards compatible. A
plain 'apt-get upgrade' would do the job.

Anyways, I think this is bike-shedding: The question of what mental
model fits best doesn't matter too much, here.

I'm concerned about being consistent with whatever mental model we
choose and about an implementation that would work with whatever
security standards we want to adhere to.

>> (Note how this would make out-of-line extensions a lot closer to the
>> in-line variant your recent patch adds? With the dependency between
>> "template" and "instantiation"?)
> 
> Those dependencies are almost gone now except for being able to deal
> with DROP TEMPLATE FOR EXTENSION and guaranteeing we can actually
> pg_restore our pg_dump script.

I appreciate the bug fixes. However, there still is at least one
dependency. And that might be a good thing. Depending on what mental
model you follow.

> I've been changing the implementation to be what you proposed because I
> think it's making more sense (thanks!), and regression tests are
> reflecting that. My github branch is up-to-date with the last changes
> and I'm soon to send an updated patch that will be really as ready for
> commit as possible without a commiter review.

Good, thanks.

>> An attacker having access to a libpq connection with superuser rights
>> cannot currently run arbitrary native code. He can try a DOS by
> 
> I think I showed a simple way to do that above in this very email.

Correct, thanks. I think Robert isn't aware of that, for example.

> As it's all about security, reaching to an agreement strikes me as the
> right thing to do.

Agreed.

Regards

Markus



Re: Proposal: template-ify (binary) extensions

From
Markus Wanner
Date:
On 07/16/2013 09:14 PM, I wrote:
> But okay, you're saying we *have* and *want* a guarantee that even a
> superuser cannot execute arbitrary native code via libpq (at least in
> default installs w/o extensions).

I stand corrected and have to change my position, again. For the record:

We do not have such a guarantee. Nor does it seem reasonable to want
one. On a default install, it's well possible for the superuser to run
arbitrary code via just libpq.

There are various ways to do it, but the simplest one I was shown is:- upload a DSO from the client into a large
object-SELECT lo_export() that LO to a file on the server- LOAD it
 

There are a couple other options, so even if we let LOAD perform
permission checks (as I proposed before in this thread), the superuser
can still fiddle with function definitions. To the point that it doesn't
seem reasonable to try to protect against that.

Thus, the argument against the original proposal based on security
grounds is moot. Put another way: There already are a couple of
"backdoors" a superuser can use. By default. Or with plpgsql removed.

Thanks to Dimitri and Andres for patiently explaining and providing
examples.

Regards

Markus Wanner