diff --git a/sepostgresql-policy-8.3.6-2.patch b/sepostgresql-policy-8.3.6-2.patch index 632f5fd..fe5e8f3 100644 --- a/sepostgresql-policy-8.3.6-2.patch +++ b/sepostgresql-policy-8.3.6-2.patch @@ -103,8 +103,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.if sepgs +## There are no interface declaration diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te --- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-02-06 12:55:02.000000000 +0900 -@@ -0,0 +1,124 @@ ++++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-02-26 21:22:49.000000000 +0900 +@@ -0,0 +1,120 @@ +policy_module(sepostgresql-devel, 3.23) + +gen_require(` @@ -143,14 +143,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs + +userdom_unpriv_user_template(sepgsql_test) + -+ifndef(`sepgsql_test_sepgsql_table_t',` -+ # In Fedora 9, userdom_unpriv_user_template internally uses -+ # postgresql_userdom_template(). -+ ifdef(`postgresql_role', ` -+ postgresql_role(sepgsql_test_r, sepgsql_test_t) -+ ',` -+ postgresql_userdom_template(sepgsql_test, sepgsql_test_t, sepgsql_test_r) -+ ') ++ifdef(`postgresql_role', ` ++ postgresql_role(sepgsql_test_r, sepgsql_test_t) ++',` ++ postgresql_userdom_template(sepgsql_test, sepgsql_test_t, sepgsql_test_r) +') + +allow sepgsql_test_t tmpfile : dir search_dir_perms; diff --git a/sepostgresql-sepgsql-8.3.6-2.patch b/sepostgresql-sepgsql-8.3.6-2.patch index b036880..db32fe5 100644 --- a/sepostgresql-sepgsql-8.3.6-2.patch +++ b/sepostgresql-sepgsql-8.3.6-2.patch @@ -2804,7 +2804,7 @@ diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/ex /* diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c --- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/executor/execScan.c 2008-12-28 01:06:59.000000000 +0900 ++++ sepgsql/src/backend/executor/execScan.c 2009-02-25 22:31:25.000000000 +0900 @@ -20,6 +20,7 @@ #include "executor/executor.h" @@ -2813,61 +2813,40 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex #include "utils/memutils.h" -@@ -48,7 +49,7 @@ TupleTableSlot * - ExecScan(ScanState *node, - ExecScanAccessMtd accessMtd) /* function returning a tuple */ - { -- ExprContext *econtext; -+ ExprContext *econtext = node->ps.ps_ExprContext; - List *qual; +@@ -53,6 +54,7 @@ ExecScan(ScanState *node, ProjectionInfo *projInfo; ExprDoneCond isDone; -@@ -65,7 +66,22 @@ ExecScan(ScanState *node, + TupleTableSlot *resultSlot; ++ Scan *scan = (Scan *)node->ps.plan; + + /* + * Fetch data from node +@@ -64,7 +66,7 @@ ExecScan(ScanState *node, + * If we have neither a qual to check nor a projection to do, just skip * all the overhead and return the raw scan tuple. */ - if (!qual && !projInfo) -- return (*accessMtd) (node); -+ { -+ while (true) -+ { -+ resultSlot = (*accessMtd) (node); -+ -+ if (TupIsNull(resultSlot)) -+ break; -+ -+ if (pgaceExecScan((Scan *)node->ps.plan, -+ node->ss_currentRelation, resultSlot)) -+ break; -+ -+ ResetExprContext(econtext); -+ } -+ return resultSlot; -+ } +- if (!qual && !projInfo) ++ if (!qual && !projInfo && !scan->pgaceTuplePerms) + return (*accessMtd) (node); /* - * Check to see if we're still projecting out tuples from a previous scan -@@ -87,7 +103,6 @@ ExecScan(ScanState *node, - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a scan tuple. - */ -- econtext = node->ps.ps_ExprContext; - ResetExprContext(econtext); - - /* -@@ -127,8 +142,11 @@ ExecScan(ScanState *node, +@@ -127,9 +129,14 @@ ExecScan(ScanState *node, * check for non-nil qual here to avoid a function call to ExecQual() * when the qual is nil ... saves only a few cycles, but they add up * ... + * And security check for tuple level access controls at the last. */ - if (!qual || ExecQual(qual, econtext, false)) -+ if ((!qual || ExecQual(qual, econtext, false)) -+ && pgaceExecScan((Scan *)node->ps.plan, -+ node->ss_currentRelation, slot)) ++ if (pgaceExecScan(scan, node->ss_currentRelation, slot, false) ++ && (!qual || ExecQual(qual, econtext, false))) { ++ /* special care for FK checks */ ++ pgaceExecScan(scan, node->ss_currentRelation, slot, true); ++ /* * Found a satisfactory scan tuple. -@@ -197,6 +215,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis + */ +@@ -197,6 +204,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis int numattrs = tupdesc->natts; int attrno; bool hasoid; @@ -2875,7 +2854,7 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex ListCell *tlist_item = list_head(tlist); /* Check the tlist attributes */ -@@ -240,12 +259,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis +@@ -240,12 +248,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis return false; /* tlist too long */ /* @@ -3133,7 +3112,7 @@ diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fss PG_RETURN_INT32(0); diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c --- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/copyfuncs.c 2009-01-21 17:02:57.000000000 +0900 ++++ sepgsql/src/backend/nodes/copyfuncs.c 2009-02-17 13:32:34.000000000 +0900 @@ -24,6 +24,7 @@ #include "nodes/plannodes.h" @@ -3190,7 +3169,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -2998,6 +3005,26 @@ _copyValue(Value *from) +@@ -2998,6 +3005,25 @@ _copyValue(Value *from) return newnode; } @@ -3202,7 +3181,6 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun +_copySelinuxEvalItem(SelinuxEvalItem *from) +{ + SelinuxEvalItem *newnode = makeNode(SelinuxEvalItem); -+ int n; + + COPY_SCALAR_FIELD(relid); + COPY_SCALAR_FIELD(inh); @@ -3217,7 +3195,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun /* * copyObject * -@@ -3600,6 +3627,9 @@ copyObject(void *from) +@@ -3600,6 +3626,9 @@ copyObject(void *from) case T_XmlSerialize: retval = _copyXmlSerialize(from); break; @@ -4891,8 +4869,8 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security +#endif /* HAVE_SELINUX */ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/pgaceHooks.c --- base/src/backend/security/pgaceHooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/pgaceHooks.c 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,1490 @@ ++++ sepgsql/src/backend/security/pgaceHooks.c 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,1462 @@ +/* + * src/backend/security/pgaceHooks.c + * Security hooks in PostgreSQL Access Control Extension (PGACE) @@ -5125,6 +5103,27 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ +} + +/* ++ * pgaceRowlvBehaviorSwitchTo ++ * changes internal state during FK constraint checks ++ */ ++bool ++pgaceRowlvBehaviorSwitchTo(bool new_abort) ++{ ++ switch (pgace_feature) ++ { ++#ifdef HAVE_SELINUX ++ case PGACE_FEATURE_SELINUX: ++ if (sepgsqlIsEnabled()) ++ return sepgsqlRowlvBehaviorSwitchTo(new_abort); ++ break; ++#endif ++ default: ++ break; ++ } ++ return new_abort; ++} ++ ++/* + * pgaceExecScan + * + * This hook is invoked on ExecScan for each tuple fetched. @@ -5140,14 +5139,14 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ + * required to scanned tuples. + */ +bool -+pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) ++pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) +{ + switch (pgace_feature) + { +#ifdef HAVE_SELINUX + case PGACE_FEATURE_SELINUX: + if (sepgsqlIsEnabled()) -+ return sepgsqlExecScan(scan, rel, slot); ++ return sepgsqlExecScan(scan, rel, slot, abort); + break; +#endif + default: @@ -5751,55 +5750,6 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ +} + +/* -+ * pgaceBeginPerformCheckFK -+ * -+ * This hook is invoked just before performing FK constraint checks. -+ * The guest can change its internal state during the checks. -+ * The major purpose of this function is to prevent violation of -+ * integrity consistentency violation due to row-level access control. -+ * If the guest requires an opaque data, it should be returned then -+ * it will be delivered via pgaceEndPerformCheckFK(). -+ */ -+void -+pgaceBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid, -+ Datum *pgace_private) -+{ -+ switch (pgace_feature) -+ { -+#ifdef HAVE_SELINUX -+ case PGACE_FEATURE_SELINUX: -+ if (sepgsqlIsEnabled()) -+ *pgace_private = sepgsqlBeginPerformCheckFK(rel, is_primary, save_userid); -+ break; -+#endif -+ default: -+ break; -+ } -+} -+ -+/* -+ * pgaceEndPerformCheckFK -+ * -+ * This hook is invoked just after performing FK constraint checks. -+ * The guest can restore its internal state using this hook. -+ */ -+void -+pgaceEndPerformCheckFK(Relation rel, Datum pgace_private) -+{ -+ switch (pgace_feature) -+ { -+#ifdef HAVE_SELINUX -+ case PGACE_FEATURE_SELINUX: -+ if (sepgsqlIsEnabled()) -+ sepgsqlEndPerformCheckFK(rel, pgace_private); -+ break; -+#endif -+ default: -+ break; -+ } -+} -+ -+/* + * pgaceAllowInlineFunction + * + * This hook gives guest a chance to make decision just before @@ -8267,8 +8217,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +} diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c --- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-01-22 10:40:54.000000000 +0900 -@@ -0,0 +1,1018 @@ ++++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,1160 @@ +/* + * src/backend/security/sepgsql/hooks.c + * implementations of PGACE framework @@ -8284,10 +8234,19 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +#include "access/skey.h" +#include "catalog/indexing.h" +#include "catalog/pg_aggregate.h" ++#include "catalog/pg_amproc.h" ++#include "catalog/pg_cast.h" ++#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" ++#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" ++#include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_security.h" ++#include "catalog/pg_trigger.h" ++#include "catalog/pg_ts_parser.h" ++#include "catalog/pg_ts_template.h" ++#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "security/pgace.h" @@ -8673,6 +8632,148 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + return true; +} + ++/* ++ * sepgsqlCheckProcedureInstall ++ * checks permission: db_procedure:{install}, when client tries to modify ++ * a system catalog which contains procedure id to invoke it later. ++ * Because these functions are invoked internally, to search a table with ++ * a special index algorithm for example, the security policy has to prevent ++ * malicious user-defined functions to be installed. ++ */ ++static void ++checkProcedureInstall(Oid proc_oid) ++{ ++ if (!OidIsValid(proc_oid)) ++ return; ++ ++ if (IsBootstrapProcessingMode()) ++ { ++ /* ++ * We assume all procedures have same security context ++ * in bootstrap processing mode, because no one can ++ * relabel it. ++ */ ++ Oid proc_sid ++ = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), ++ SECCLASS_DB_PROCEDURE); ++ sepgsqlClientHasPermission(proc_sid, ++ SECCLASS_DB_PROCEDURE, ++ DB_PROCEDURE__INSTALL, ++ NULL); ++ } ++ else ++ { ++ HeapTuple protup; ++ const char *audit_name; ++ ++ protup = SearchSysCache(PROCOID, ++ ObjectIdGetDatum(proc_oid), ++ 0, 0, 0); ++ if (!HeapTupleIsValid(protup)) ++ return; ++ ++ audit_name = sepgsqlTupleName(ProcedureRelationId, protup); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(protup), ++ SECCLASS_DB_PROCEDURE, ++ DB_PROCEDURE__INSTALL, ++ audit_name); ++ ReleaseSysCache(protup); ++ } ++} ++ ++#define CHECK_PROC_INSTALL_HANDLER(catalog,member,newtup,oldtup) \ ++ do { \ ++ if (!HeapTupleIsValid(oldtup)) \ ++ checkProcedureInstall(((Form_##catalog) GETSTRUCT(newtup))->member); \ ++ else if (((Form_##catalog) GETSTRUCT(newtup))->member \ ++ != ((Form_##catalog) GETSTRUCT(oldtup))->member) \ ++ checkProcedureInstall(((Form_##catalog) GETSTRUCT(oldtup))->member); \ ++ } while(0) ++ ++static void ++sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup) ++{ ++ /* ++ * Some of system catalog can be configured to invoke functions ++ * implicitly. It checks permission to prevent implicit invocation ++ * of malicious functions. ++ */ ++ switch (RelationGetRelid(rel)) ++ { ++ case AggregateRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfnoid, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggtransfn, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfinalfn, newtup, oldtup); ++ break; ++ ++ case AccessMethodRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_am, aminsert, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambeginscan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amgettuple, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amgetmulti, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amrescan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amendscan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ammarkpos, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amrestrpos, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambuild, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambulkdelete, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amvacuumcleanup, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amcostestimate, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amoptions, newtup, oldtup); ++ break; ++ ++ case AccessMethodProcedureRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_amproc, amproc, newtup, oldtup); ++ break; ++ ++ case CastRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_cast, castfunc, newtup, oldtup); ++ break; ++ ++ case ConversionRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_conversion, conproc, newtup, oldtup); ++ break; ++ ++ case LanguageRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_language, lanplcallfoid, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_language, lanvalidator, newtup, oldtup); ++ break; ++ ++ case OperatorRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprcode, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprrest, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprjoin, newtup, oldtup); ++ break; ++ ++ case TriggerRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_trigger, tgfoid, newtup, oldtup); ++ break; ++ ++ case TSParserRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsstart, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prstoken, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsend, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsheadline, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prslextype, newtup, oldtup); ++ break; ++ ++ case TSTemplateRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmplinit, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmpllexize, newtup, oldtup); ++ break; ++ ++ case TypeRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typinput, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typoutput, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typreceive, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typsend, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodin, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodout, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typanalyze, newtup, oldtup); ++ break; ++ } ++} ++ +/******************************************************************************* + * LOAD shared library module hook + *******************************************************************************/ @@ -8942,11 +9043,24 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +static bool abort_on_violated_tuple = false; + +bool -+sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) ++sepgsqlRowlvBehaviorSwitchTo(bool new_abort) ++{ ++ bool old_abort = abort_on_violated_tuple; ++ ++ abort_on_violated_tuple = new_abort; ++ ++ return old_abort; ++} ++ ++bool ++sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) +{ + HeapTuple tuple; + uint32 perms = (scan->pgaceTuplePerms & SEPGSQL_PERMS_MASK); + ++ if (abort_on_violated_tuple != abort) ++ return true; /* no need to do here */ ++ + if (perms == 0) + return true; + @@ -8956,32 +9070,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + abort_on_violated_tuple); +} + -+/* ---------------------------------------------------------- -+ * special cases for Foreign Key constraint -+ * ---------------------------------------------------------- */ -+Datum -+sepgsqlBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid) -+{ -+ Datum save_pgace = BoolGetDatum(abort_on_violated_tuple); -+ -+ /* -+ * NOTE: when a tuple is inserted/updated on FK relation, all we should -+ * do is simply filtering violated tuples on PK relation, as normal -+ * row-level access controls doing. -+ * At the result, INSERT/UPDATE with invisible tuple will be failed. -+ */ -+ if (is_primary) -+ abort_on_violated_tuple = true; -+ -+ return save_pgace; -+} -+ -+void -+sepgsqlEndPerformCheckFK(Relation rel, Datum save_pgace) -+{ -+ abort_on_violated_tuple = DatumGetBool(save_pgace); -+} -+ +/******************************************************************************* + * security_label hooks + *******************************************************************************/ @@ -9186,9 +9274,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + uint32 perms; + -+ /* -+ * default context for no explicit labeled tuple -+ */ ++ sepgsqlCheckProcedureInstall(rel, tuple, NULL); ++ + if (!OidIsValid(HeapTupleGetSecLabel(tuple))) + { + /* @@ -9220,12 +9307,14 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + Oid relid = RelationGetRelid(rel); + HeapTuple oldtup; -+ uint32 perms; ++ uint32 perms = 0; + bool rc = true; + bool relabel = false; + + oldtup = getHeapTupleFromItemPointer(rel, otid); + ++ sepgsqlCheckProcedureInstall(rel, newtup, oldtup); ++ + if (!OidIsValid(HeapTupleGetSecLabel(newtup))) + { + /* @@ -9251,7 +9340,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + sepgsqlTupleObjectClass(relid, newtup) != sepgsqlTupleObjectClass(relid, oldtup)) + relabel = true; + -+ perms = SEPGSQL_PERMS_UPDATE; ++ if (is_internal) ++ perms |= SEPGSQL_PERMS_UPDATE; + if (relabel) + perms |= SEPGSQL_PERMS_RELABELFROM; + rc = sepgsqlCheckTuplePerms(rel, oldtup, newtup, perms, is_internal); @@ -9275,11 +9365,13 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + bool is_internal, bool with_returning) +{ + HeapTuple oldtup; -+ uint32 perms = SEPGSQL_PERMS_DELETE; ++ uint32 perms = 0; + bool rc; + + if (isTrustedRelation(rel, is_internal)) + return true; ++ if (is_internal) ++ perms |= SEPGSQL_PERMS_DELETE; + + oldtup = getHeapTupleFromItemPointer(rel, otid); + rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal); @@ -9289,8 +9381,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +} diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/security/sepgsql/permissions.c --- base/src/backend/security/sepgsql/permissions.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-01-22 14:28:10.000000000 +0900 -@@ -0,0 +1,794 @@ ++++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,636 @@ + +/* + * src/backend/security/sepgsql/permissions.c @@ -9305,23 +9397,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +#include "access/heapam.h" +#include "access/genam.h" +#include "catalog/indexing.h" -+#include "catalog/pg_aggregate.h" -+#include "catalog/pg_am.h" -+#include "catalog/pg_amproc.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_authid.h" -+#include "catalog/pg_cast.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" +#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" -+#include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" -+#include "catalog/pg_security.h" -+#include "catalog/pg_trigger.h" -+#include "catalog/pg_ts_parser.h" -+#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "security/pgace.h" @@ -9638,148 +9717,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + return result; +} + -+/* -+ * sepgsqlCheckProcedureInstall -+ * checks permission: db_procedure:{install}, when client tries to modify -+ * a system catalog which contains procedure id to invoke it later. -+ * Because these functions are invoked internally, to search a table with -+ * a special index algorithm for example, the security policy has to prevent -+ * malicious user-defined functions to be installed. -+ */ -+static void -+checkProcedureInstall(Oid proc_oid) -+{ -+ if (!OidIsValid(proc_oid)) -+ return; -+ -+ if (IsBootstrapProcessingMode()) -+ { -+ /* -+ * We assume all procedures have same security context -+ * in bootstrap processing mode, because no one can -+ * relabel it. -+ */ -+ Oid proc_sid -+ = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_PROCEDURE); -+ sepgsqlClientHasPermission(proc_sid, -+ SECCLASS_DB_PROCEDURE, -+ DB_PROCEDURE__INSTALL, -+ NULL); -+ } -+ else -+ { -+ HeapTuple protup; -+ const char *audit_name; -+ -+ protup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(proc_oid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(protup)) -+ return; -+ -+ audit_name = sepgsqlTupleName(ProcedureRelationId, protup); -+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(protup), -+ SECCLASS_DB_PROCEDURE, -+ DB_PROCEDURE__INSTALL, -+ audit_name); -+ ReleaseSysCache(protup); -+ } -+} -+ -+#define CHECK_PROC_INSTALL_HANDLER(catalog,member,tuple,newtup) \ -+ do { \ -+ if (!HeapTupleIsValid(newtup)) \ -+ checkProcedureInstall(((CppConcat(Form_,catalog)) GETSTRUCT(tuple))->member); \ -+ else if (((CppConcat(Form_,catalog)) GETSTRUCT(tuple))->member \ -+ != ((CppConcat(Form_,catalog)) GETSTRUCT(newtup))->member) \ -+ checkProcedureInstall(((CppConcat(Form_,catalog)) GETSTRUCT(newtup))->member); \ -+ } while(0) -+ -+static void -+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple tuple, HeapTuple newtup) -+{ -+ /* -+ * Some of system catalog can be configured to invoke functions -+ * implicitly. It checks permission to prevent implicit invocation -+ * of malicious functions. -+ */ -+ switch (RelationGetRelid(rel)) -+ { -+ case AggregateRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfnoid, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggtransfn, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfinalfn, tuple, newtup); -+ break; -+ -+ case AccessMethodRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_am, aminsert, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambeginscan, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amgettuple, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amgetmulti, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amrescan, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amendscan, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, ammarkpos, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amrestrpos, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambuild, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambulkdelete, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amvacuumcleanup, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amcostestimate, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_am, amoptions, tuple, newtup); -+ break; -+ -+ case AccessMethodProcedureRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_amproc, amproc, tuple, newtup); -+ break; -+ -+ case CastRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_cast, castfunc, tuple, newtup); -+ break; -+ -+ case ConversionRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_conversion, conproc, tuple, newtup); -+ break; -+ -+ case LanguageRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_language, lanplcallfoid, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_language, lanvalidator, tuple, newtup); -+ break; -+ -+ case OperatorRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprcode, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprrest, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprjoin, tuple, newtup); -+ break; -+ -+ case TriggerRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_trigger, tgfoid, tuple, newtup); -+ break; -+ -+ case TSParserRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsstart, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prstoken, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsend, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsheadline, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prslextype, tuple, newtup); -+ break; -+ -+ case TSTemplateRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmplinit, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmpllexize, tuple, newtup); -+ break; -+ -+ case TypeRelationId: -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typinput, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typoutput, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typreceive, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typsend, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodin, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodout, tuple, newtup); -+ CHECK_PROC_INSTALL_HANDLER(pg_type, typanalyze, tuple, newtup); -+ break; -+ } -+} -+ +bool +sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup, + uint32 perms, bool abort) @@ -9790,9 +9727,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + + Assert(HeapTupleIsValid(tuple)); + -+ if ((perms & (SEPGSQL_PERMS_INSERT | SEPGSQL_PERMS_UPDATE)) != 0) -+ sepgsqlCheckProcedureInstall(rel, tuple, newtup); -+ + tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); + + switch (tclass) @@ -10087,8 +10021,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +} diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/security/sepgsql/proxy.c --- base/src/backend/security/sepgsql/proxy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-01-23 13:07:12.000000000 +0900 -@@ -0,0 +1,1074 @@ ++++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,1076 @@ +/* + * src/backend/security/sepgsql/proxy.c + * Proxying the given Query trees via SE-PostgreSQL @@ -10208,6 +10142,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +{ + rte->pgaceTuplePerms |= (perms & DB_TABLE__USE ? SEPGSQL_PERMS_USE : 0); + rte->pgaceTuplePerms |= (perms & DB_TABLE__SELECT ? SEPGSQL_PERMS_SELECT : 0); ++ rte->pgaceTuplePerms |= (perms & DB_TABLE__UPDATE ? SEPGSQL_PERMS_UPDATE : 0); ++ rte->pgaceTuplePerms |= (perms & DB_TABLE__DELETE ? SEPGSQL_PERMS_DELETE : 0); + + return addEvalRelation(selist, rte->relid, rte->inh, perms); +} @@ -11252,7 +11188,7 @@ diff -rpNU3 base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c /* diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c --- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/utils/adt/ri_triggers.c 2008-12-28 01:06:59.000000000 +0900 ++++ sepgsql/src/backend/utils/adt/ri_triggers.c 2009-02-25 22:31:25.000000000 +0900 @@ -37,6 +37,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_relation.h" @@ -11265,7 +11201,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a int spi_result; Oid save_userid; bool save_secdefcxt; -+ Datum pgace_private = 0; ++ bool save_pgace; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; @@ -11278,7 +11214,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a - vals, nulls, - test_snapshot, crosscheck_snapshot, - false, false, limit); -+ pgaceBeginPerformCheckFK(query_rel, detectNewRows, save_userid, &pgace_private); ++ save_pgace = pgaceRowlvBehaviorSwitchTo(detectNewRows); + PG_TRY(); + { + /* Finally we can run the query. */ @@ -11289,11 +11225,11 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a + } + PG_CATCH(); + { -+ pgaceEndPerformCheckFK(query_rel, pgace_private); ++ pgaceRowlvBehaviorSwitchTo(save_pgace); + PG_RE_THROW(); + } + PG_END_TRY(); -+ pgaceEndPerformCheckFK(query_rel, pgace_private); ++ pgaceRowlvBehaviorSwitchTo(save_pgace); /* Restore UID */ SetUserIdAndContext(save_userid, save_secdefcxt); @@ -12182,8 +12118,8 @@ diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h --- base/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/pgace.h 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,194 @@ ++++ sepgsql/src/include/security/pgace.h 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,192 @@ +/* + * include/security/pgace.h + * headers for PostgreSQL Access Control Extension (PGACE) @@ -12246,7 +12182,8 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +/* + * HeapTuple input/output hooks + */ -+extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot); ++extern bool pgaceRowlvBehaviorSwitchTo(bool new_abort); ++extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort); +extern bool pgaceHeapTupleInsert(Relation rel, HeapTuple tuple, + bool is_internal, bool with_returning); +extern bool pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, @@ -12272,9 +12209,6 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +extern void pgaceCallFunction(FmgrInfo *finfo); +extern void pgaceCallAggFunction(HeapTuple aggTuple); +extern bool pgaceCallTriggerFunction(TriggerData *tgdata); -+extern void pgaceBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid, -+ Datum *pgace_private); -+extern void pgaceEndPerformCheckFK(Relation rel, Datum pgace_private); +extern bool pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple); + +/* @@ -12380,8 +12314,8 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#endif // PGACE_H diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h --- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/sepgsql.h 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,244 @@ ++++ sepgsql/src/include/security/sepgsql.h 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,242 @@ +/* + * src/include/security/sepgsql.h + * headers for Security-Enhanced PostgreSQL (SE-PostgreSQL) @@ -12449,7 +12383,9 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +extern void sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel); + +/* ExecScan hooks */ -+extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot); ++extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort); ++ ++extern bool sepgsqlRowlvBehaviorSwitchTo(bool new_abort); + +/* HeapTuple modification hooks */ +extern bool sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple, @@ -12492,10 +12428,6 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep + +extern bool sepgsqlCallTriggerFunction(TriggerData *tgdata); + -+extern Datum sepgsqlBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid); -+ -+extern void sepgsqlEndPerformCheckFK(Relation rel, Datum save_pgace); -+ +extern bool sepgsqlAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple); + +/* TABLE related hooks */ diff --git a/sepostgresql.init b/sepostgresql.init index ec094e9..dfa42e4 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -9,7 +9,7 @@ PGVERSION="8.3.6" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="2.1523" +SEPGVERSION="2.1634" # source function library . /etc/rc.d/init.d/functions diff --git a/sepostgresql.spec b/sepostgresql.spec index b52ac49..cccb86e 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -22,7 +22,7 @@ Summary: Security Enhanced PostgreSQL Name: sepostgresql Version: 8.3.6 -Release: 2.1523%{?sepgsql_extension}%{?dist} +Release: 2.1634%{?sepgsql_extension}%{?dist} License: BSD Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ @@ -158,8 +158,9 @@ exit 0 %if !%{fedora9} for store in %{selinux_policy_stores} do + # clean up legacy policy module (now it is unnecessary) %{_sbindir}/semodule -s ${store} -r sepostgresql >& /dev/null || : - if %{_sbindir}/semodule -s ${store} -l | grep -Eq "^sepostgresql-devel"; then + if %{_sbindir}/semodule -s ${store} -l 2>/dev/null | grep -Eq "^sepostgresql-devel"; then %{_sbindir}/semodule -s ${store} \ -i %{_datadir}/selinux/${store}/sepostgresql-devel.pp >& /dev/null || : fi @@ -221,7 +222,14 @@ fi %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog -* Fri Feb 6 2009 - 8.3.6-2.1520 +* Thu Feb 26 2009 KaiGai Kohei - 8.3.6-2.1635 +- bugfix: possible information leak by the order of permission checks + in row level permission checks. + +* Wed Feb 25 2009 Fedora Release Engineering - 8.3.6-3.1518 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Feb 6 2009 - 8.3.6-2.1523 - upgrade base PostgreSQL version 8.3.5->8.3.6 - backport features from 8.4devel tree - security policy fix for Fedora 9