Re: Updates of SE-PostgreSQL 8.4devel patches (r1704) - Mailing list pgsql-hackers

From KaiGai Kohei
Subject Re: Updates of SE-PostgreSQL 8.4devel patches (r1704)
Date
Msg-id 49B52DF2.6060108@kaigai.gr.jp
Whole thread Raw
In response to Re: Updates of SE-PostgreSQL 8.4devel patches (r1704)  (Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>)
Responses Re: Updates of SE-PostgreSQL 8.4devel patches (r1704)  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Heikki Linnakangas wrote:
> KaiGai Kohei wrote:
>> As I promised last week, SE-PostgreSQL patches are revised here:
> 
> I think I now understand what sepgsqlCheckProcedureInstall is trying to 
> achieve. It's trying to stop attacks where you trick another user to run 
> your malicious code. We had a serious vulnerability of that kind a while 
> ago (http://archives.postgresql.org//pgsql-hackers/2008-01/msg00268.php) 
> when ANALYZE and VACUUM FULL ran expression and partial index predicates 
> with (typically) superuser privileges.
> 
> It seems that sepgsqlCheckProcedureInstall is trying to provide a more 
> thorough solution to the trojan horse problem than what we did back 
> then. It stops you from installing an untrusted function as a type 
> input/output function, operator implementing function etc. Now that 
> could be useful on its own, quite apart from the rest of the 
> SE-PostgreSQL patch, in which case I'd like to see that implemented as a 
> separate patch, so that you can use the facility even if you're not 
> using SE-PostgreSQL.

Yes, the purpose of sepgsqlCheckProcedureInstall() is to prevent users
to invoke functions installed by other malicious/untrusted one, typically
known as trojan-horse.

Basically, I can agree the vanilla PostgreSQL also provide similar stuff
to prevent to install "untrusted" functions as a part of system internal
codes. If we have such a facility as a basis, we can implement
sepgsqlCheckProcedureInstall() hook more simple and easier to maintenance.

[snip]
>> +     case ConversionRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_conversion, conproc, newtup, 
>> oldtup);
>> +         break;
> 
> This ought to be unnecessary now. Only C-functions can be installed as 
> conversion procs, and a C function can do anything, so there's little 
> point in checking this anymore.

We should not assume only C-functions can be installed on pg_conversion
(and other internal stuff), because a superuser can update system catalog
by hand.
  Example)  postgres=# CREATE OR REPLACE FUNCTION testfn()  postgres-#     RETURNS int LANGUAGE sql AS 'SELECT 1';
CREATEFUNCTION  postgres=# UPDATE pg_conversion SET conproc = 'testfn'::regproc where oid=11276;  UPDATE 1  postgres=#
setclient_encoding = 'sjis';  server closed the connection unexpectedly          This probably means the server
terminatedabnormally          before or while processing the request.  The connection to the server was lost.
Attemptingreset: WARNING:  terminating connection because of crash of another server process  DETAIL:  The postmaster
hascommanded this server process to roll back the current transaction and exit, because another server process exited
abnormallyand possibly corrupted shared memory.  HINT:  In a moment you should be able to reconnect to the database and
repeatyour command.  Failed.  !>
 

SE-PostgreSQL intends to acquire them and apply access control policy
in this case also.

Aside note: sepgsqlCheckDatabaseInstallModule() check permissions on
a newly installed C-library file, to prevent to load a file deployed
by untrusted client.

>> +     case ForeignDataWrapperRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_foreign_data_wrapper, 
>> fdwvalidator, newtup, oldtup);
>> +         break;
> 
> Hmm, calls to fdwvalidator are not at all performance critical, so maybe 
> we should just check execute permission when it's called.

If pg_proc_aclcheck() on its invocation, it is not necessary to check
on the installation time.

[snip]
>> +     case OperatorRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_operator, oprcode, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_operator, oprrest, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_operator, oprjoin, newtup, oldtup);
>> +         break;
> 
> oprcode is checked for execute permission when the operator is used. For 
> oprrest and oprjoin, we could add checks into the planner where they're 
> called. (pg_operator.oprcom and pg_operator.oprnegate are missing?)

If runtime checks are added, it is more desirable.

>> +     case TSParserRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsstart, newtup, 
>> oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_parser, prstoken, newtup, 
>> oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsend, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsheadline, newtup, 
>> oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_parser, prslextype, newtup, 
>> oldtup);
>> +         break;
>> + +     case TSTemplateRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_template, tmplinit, newtup, 
>> oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_ts_template, tmpllexize, newtup, 
>> oldtup);
>> +         break;
> 
> Not sure about these. Maybe we should add checks to where these are called.

I'll check the behavior of them tomorrow.

>> +     case TypeRelationId:
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typinput, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typoutput, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typreceive, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typsend, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typmodin, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typmodout, newtup, oldtup);
>> +         CHECK_PROC_INSTALL_PERM(pg_type, typanalyze, newtup, oldtup);
>> +         break;
> 
> Hmm, input/output functions have to be in C, so I'm not concerned about 
> those. send/receive and typmodin/typmodout are a bit problematic. 
> ANALYZE calls typanalyze as the table owner, so I think that's safe.
> 
> 
> All of these require the victim to willingly (although indirectly) call 
> a non-security definer function created by the attacker, with varying 
> degrees of difficultness in tricking someone to do that. Can't you just 
> create a policy that forbids creating non-security definer functions in 
> the first place? It's much more coarse-grained, but would probably be 
> enough in practice.

I think it is possible, and I welcome the vanilla PostgreSQL also have
such a facility. It also make easier to maintain SE-PostgreSQL code. :-)
The issue it what policy should be applied on the vanilla side.

The following rules may be able to be a draft. - Any installed functions should not security definer. - Any installed
functionsshould be owned by superuser.   (to prevent replacement by normal users.)
 

What is your opinion? I'll try to consider it more...

Thanks,
-- 
KaiGai Kohei <kaigai@kaigai.gr.jp>


pgsql-hackers by date:

Previous
From: Peter Eisentraut
Date:
Subject: Re: Allow on/off as input texts for boolean.
Next
From: Peter Eisentraut
Date:
Subject: Re: [PATCH] Regression test fix for Czech locale