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.
2015-01-12 23:04:11 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* rls.c
|
|
|
|
* RLS-related utility functions.
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/misc/rls.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/htup.h"
|
|
|
|
#include "access/htup_details.h"
|
2015-07-28 22:21:22 +02:00
|
|
|
#include "access/transam.h"
|
|
|
|
#include "catalog/namespace.h"
|
2016-01-04 18:21:31 +01:00
|
|
|
#include "catalog/pg_class.h"
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "utils/acl.h"
|
2015-07-28 22:21:22 +02:00
|
|
|
#include "utils/builtins.h"
|
2016-01-04 18:21:31 +01:00
|
|
|
#include "utils/lsyscache.h"
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
#include "utils/rls.h"
|
|
|
|
#include "utils/syscache.h"
|
2017-01-21 02:29:53 +01:00
|
|
|
#include "utils/varlena.h"
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check_enable_rls
|
|
|
|
*
|
|
|
|
* Determine, based on the relation, row_security setting, and current role,
|
|
|
|
* if RLS is applicable to this query. RLS_NONE_ENV indicates that, while
|
|
|
|
* RLS is not to be added for this query, a change in the environment may change
|
|
|
|
* that. RLS_NONE means that RLS is not on the relation at all and therefore
|
|
|
|
* we don't need to worry about it. RLS_ENABLED means RLS should be implemented
|
|
|
|
* for the table and the plan cache needs to be invalidated if the environment
|
|
|
|
* changes.
|
|
|
|
*
|
2015-10-04 02:19:57 +02:00
|
|
|
* Handle checking as another role via checkAsUser (for views, etc). Pass
|
|
|
|
* InvalidOid to check the current user.
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
*
|
|
|
|
* If noError is set to 'true' then we just return RLS_ENABLED instead of doing
|
|
|
|
* an ereport() if the user has attempted to bypass RLS and they are not
|
|
|
|
* allowed to. This allows users to check if RLS is enabled without having to
|
|
|
|
* deal with the actual error case (eg: error cases which are trying to decide
|
|
|
|
* if the user should get data from the relation back as part of the error).
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
|
|
|
|
{
|
2022-11-30 12:07:03 +01:00
|
|
|
Oid user_id = OidIsValid(checkAsUser) ? checkAsUser : GetUserId();
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
HeapTuple tuple;
|
|
|
|
Form_pg_class classform;
|
|
|
|
bool relrowsecurity;
|
2015-10-05 03:05:08 +02:00
|
|
|
bool relforcerowsecurity;
|
2016-01-04 18:21:31 +01:00
|
|
|
bool amowner;
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
|
2015-07-28 22:21:22 +02:00
|
|
|
/* Nothing to do for built-in relations */
|
2016-01-04 18:21:31 +01:00
|
|
|
if (relid < (Oid) FirstNormalObjectId)
|
2015-07-28 22:21:22 +02:00
|
|
|
return RLS_NONE;
|
|
|
|
|
2016-01-04 18:21:31 +01:00
|
|
|
/* Fetch relation's relrowsecurity and relforcerowsecurity flags */
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
return RLS_NONE;
|
|
|
|
classform = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
relrowsecurity = classform->relrowsecurity;
|
2015-10-05 03:05:08 +02:00
|
|
|
relforcerowsecurity = classform->relforcerowsecurity;
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
/* Nothing to do if the relation does not have RLS */
|
|
|
|
if (!relrowsecurity)
|
|
|
|
return RLS_NONE;
|
|
|
|
|
|
|
|
/*
|
2015-10-05 03:05:08 +02:00
|
|
|
* BYPASSRLS users always bypass RLS. Note that superusers are always
|
|
|
|
* considered to have BYPASSRLS.
|
|
|
|
*
|
|
|
|
* Return RLS_NONE_ENV to indicate that this decision depends on the
|
|
|
|
* environment (in this case, the user_id).
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
*/
|
2015-10-05 03:05:08 +02:00
|
|
|
if (has_bypassrls_privilege(user_id))
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
return RLS_NONE_ENV;
|
|
|
|
|
2015-10-05 03:05:08 +02:00
|
|
|
/*
|
2016-01-04 18:21:31 +01:00
|
|
|
* Table owners generally bypass RLS, except if the table has been set (by
|
|
|
|
* an owner) to FORCE ROW SECURITY, and this is not a referential
|
|
|
|
* integrity check.
|
2015-10-05 03:05:08 +02:00
|
|
|
*
|
|
|
|
* Return RLS_NONE_ENV to indicate that this decision depends on the
|
|
|
|
* environment (in this case, the user_id).
|
|
|
|
*/
|
2022-11-13 08:11:17 +01:00
|
|
|
amowner = object_ownercheck(RelationRelationId, relid, user_id);
|
2016-01-04 18:21:31 +01:00
|
|
|
if (amowner)
|
2015-10-05 03:05:08 +02:00
|
|
|
{
|
|
|
|
/*
|
2016-01-04 18:21:31 +01:00
|
|
|
* If FORCE ROW LEVEL SECURITY has been set on the relation then we
|
|
|
|
* should return RLS_ENABLED to indicate that RLS should be applied.
|
|
|
|
* If not, or if we are in an InNoForceRLSOperation context, we return
|
|
|
|
* RLS_NONE_ENV.
|
2015-10-05 03:05:08 +02:00
|
|
|
*
|
2016-01-04 18:21:31 +01:00
|
|
|
* InNoForceRLSOperation indicates that we should not apply RLS even
|
|
|
|
* if the table has FORCE RLS set - IF the current user is the owner.
|
|
|
|
* This is specifically to ensure that referential integrity checks
|
|
|
|
* are able to still run correctly.
|
2015-10-05 03:05:08 +02:00
|
|
|
*
|
|
|
|
* This is intentionally only done after we have checked that the user
|
|
|
|
* is the table owner, which should always be the case for referential
|
|
|
|
* integrity checks.
|
|
|
|
*/
|
2016-01-04 18:21:31 +01:00
|
|
|
if (!relforcerowsecurity || InNoForceRLSOperation())
|
2015-10-05 03:05:08 +02:00
|
|
|
return RLS_NONE_ENV;
|
|
|
|
}
|
|
|
|
|
2016-01-04 18:21:31 +01:00
|
|
|
/*
|
|
|
|
* We should apply RLS. However, the user may turn off the row_security
|
|
|
|
* GUC to get a forced error instead.
|
|
|
|
*/
|
2015-10-04 02:19:57 +02:00
|
|
|
if (!row_security && !noError)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2016-01-04 18:21:31 +01:00
|
|
|
errmsg("query would be affected by row-level security policy for table \"%s\"",
|
|
|
|
get_rel_name(relid)),
|
|
|
|
amowner ? errhint("To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.") : 0));
|
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.
2015-01-12 23:04:11 +01:00
|
|
|
|
|
|
|
/* RLS should be fully enabled for this relation. */
|
|
|
|
return RLS_ENABLED;
|
|
|
|
}
|
2015-07-28 22:21:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* row_security_active
|
|
|
|
*
|
|
|
|
* check_enable_rls wrapped as a SQL callable function except
|
|
|
|
* RLS_NONE_ENV and RLS_NONE are the same for this purpose.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
row_security_active(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* By OID */
|
|
|
|
Oid tableoid = PG_GETARG_OID(0);
|
|
|
|
int rls_status;
|
|
|
|
|
|
|
|
rls_status = check_enable_rls(tableoid, InvalidOid, true);
|
|
|
|
PG_RETURN_BOOL(rls_status == RLS_ENABLED);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
row_security_active_name(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* By qualified name */
|
2017-03-13 00:35:34 +01:00
|
|
|
text *tablename = PG_GETARG_TEXT_PP(0);
|
2015-07-28 22:21:22 +02:00
|
|
|
RangeVar *tablerel;
|
|
|
|
Oid tableoid;
|
|
|
|
int rls_status;
|
|
|
|
|
|
|
|
/* Look up table name. Can't lock it - we might not have privileges. */
|
|
|
|
tablerel = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
|
|
|
|
tableoid = RangeVarGetRelid(tablerel, NoLock, false);
|
|
|
|
|
|
|
|
rls_status = check_enable_rls(tableoid, InvalidOid, true);
|
|
|
|
PG_RETURN_BOOL(rls_status == RLS_ENABLED);
|
|
|
|
}
|