aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
authorStephen Frost <sfrost@snowman.net>2015-01-12 17:04:11 -0500
committerStephen Frost <sfrost@snowman.net>2015-01-28 12:31:30 -0500
commit804b6b6db4dcfc590a468e7be390738f9f7755fb (patch)
tree334d58ccb1a76d04c9bb61309879d6c8e6a8f7e4 /src/backend/commands
parentacc2b1e843ae04e97025880f33a82f326ab12d59 (diff)
downloadpostgresql-804b6b6db4dcfc590a468e7be390738f9f7755fb.tar.gz
postgresql-804b6b6db4dcfc590a468e7be390738f9f7755fb.zip
Fix column-privilege leak in error-message paths
While building error messages to return to the user, BuildIndexValueDescription, ExecBuildSlotValueDescription and ri_ReportViolation would happily include the entire key or entire row in the result returned to the user, even if the user didn't have access to view all of the columns being included. Instead, include only those columns which the user is providing or which the user has select rights on. If the user does not have any rights to view the table or any of the columns involved then no detail is provided and a NULL value is returned from BuildIndexValueDescription and ExecBuildSlotValueDescription. Note that, for key cases, the user must have access to all of the columns for the key to be shown; a partial key will not be returned. Further, in master only, do not return any data for cases where row security is enabled on the relation and row security should be applied for the user. This required a bit of refactoring and moving of things around related to RLS- note the addition of utils/misc/rls.c. Back-patch all the way, as column-level privileges are now in all supported versions. This has been assigned CVE-2014-8161, but since the issue and the patch have already been publicized on pgsql-hackers, there's no point in trying to hide this commit.
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/copy.c10
-rw-r--r--src/backend/commands/createas.c4
-rw-r--r--src/backend/commands/matview.c7
-rw-r--r--src/backend/commands/trigger.c6
4 files changed, 22 insertions, 5 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0e604b7525b..72abd770f7a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -40,7 +40,6 @@
#include "parser/parse_relation.h"
#include "nodes/makefuncs.h"
#include "rewrite/rewriteHandler.h"
-#include "rewrite/rowsecurity.h"
#include "storage/fd.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
@@ -49,6 +48,7 @@
#include "utils/memutils.h"
#include "utils/portal.h"
#include "utils/rel.h"
+#include "utils/rls.h"
#include "utils/snapmgr.h"
@@ -163,6 +163,7 @@ typedef struct CopyStateData
int *defmap; /* array of default att numbers */
ExprState **defexprs; /* array of default att expressions */
bool volatile_defexprs; /* is any of defexprs volatile? */
+ List *range_table;
/*
* These variables are used to reduce overhead in textual COPY FROM.
@@ -789,6 +790,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
Relation rel;
Oid relid;
Node *query = NULL;
+ RangeTblEntry *rte;
/* Disallow COPY to/from file or program except to superusers. */
if (!pipe && !superuser())
@@ -811,7 +813,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
{
TupleDesc tupDesc;
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
- RangeTblEntry *rte;
List *attnums;
ListCell *cur;
@@ -857,7 +858,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
* If RLS is not enabled for this, then just fall through to the
* normal non-filtering relation handling.
*/
- if (check_enable_rls(rte->relid, InvalidOid) == RLS_ENABLED)
+ if (check_enable_rls(rte->relid, InvalidOid, false) == RLS_ENABLED)
{
SelectStmt *select;
ColumnRef *cr;
@@ -920,6 +921,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
cstate = BeginCopyFrom(rel, stmt->filename, stmt->is_program,
stmt->attlist, stmt->options);
+ cstate->range_table = list_make1(rte);
*processed = CopyFrom(cstate); /* copy from file to database */
EndCopyFrom(cstate);
}
@@ -928,6 +930,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
cstate = BeginCopyTo(rel, query, queryString, relid,
stmt->filename, stmt->is_program,
stmt->attlist, stmt->options);
+ cstate->range_table = list_make1(rte);
*processed = DoCopyTo(cstate); /* copy from database to file */
EndCopyTo(cstate);
}
@@ -2277,6 +2280,7 @@ CopyFrom(CopyState cstate)
estate->es_result_relations = resultRelInfo;
estate->es_num_result_relations = 1;
estate->es_result_relation_info = resultRelInfo;
+ estate->es_range_table = cstate->range_table;
/* Set up a tuple slot too */
myslot = ExecInitExtraTupleSlot(estate);
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index abc0fe8e584..c961429a0f5 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -38,12 +38,12 @@
#include "miscadmin.h"
#include "parser/parse_clause.h"
#include "rewrite/rewriteHandler.h"
-#include "rewrite/rowsecurity.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
+#include "utils/rls.h"
#include "utils/snapmgr.h"
@@ -446,7 +446,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
* be enabled here. We don't actually support that currently, so throw
* our own ereport(ERROR) if that happens.
*/
- if (check_enable_rls(intoRelationId, InvalidOid) == RLS_ENABLED)
+ if (check_enable_rls(intoRelationId, InvalidOid, false) == RLS_ENABLED)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
(errmsg("policies not yet implemented for this command"))));
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 74415b8ba0b..92d90323284 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -596,6 +596,13 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
if (SPI_processed > 0)
{
+ /*
+ * Note that this ereport() is returning data to the user. Generally,
+ * we would want to make sure that the user has been granted access to
+ * this data. However, REFRESH MAT VIEW is only able to be run by the
+ * owner of the mat view (or a superuser) and therefore there is no
+ * need to check for access to data in the mat view.
+ */
ereport(ERROR,
(errcode(ERRCODE_CARDINALITY_VIOLATION),
errmsg("new data for \"%s\" contains duplicate rows without any null columns",
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 4899a278ebf..5c1c1beb2b8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -65,6 +65,12 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
/* How many levels deep into trigger execution are we? */
static int MyTriggerDepth = 0;
+/*
+ * Note that this macro also exists in executor/execMain.c. There does not
+ * appear to be any good header to put it into, given the structures that
+ * it uses, so we let them be duplicated. Be sure to update both if one needs
+ * to be changed, however.
+ */
#define GetModifiedColumns(relinfo, estate) \
(rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)