LCOV - differential code coverage report
Current view: top level - src/backend/utils/misc - rls.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.9 % 32 31 1 2 29 2
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 3 3 1 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (240..) days: 96.7 % 30 29 1 29
Function coverage date bins:
(240..) days: 100.0 % 3 3 1 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * rls.c
                                  4                 :  *        RLS-related utility functions.
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *        src/backend/utils/misc/rls.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 : */
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include "access/htup.h"
                                 18                 : #include "access/htup_details.h"
                                 19                 : #include "access/transam.h"
                                 20                 : #include "catalog/namespace.h"
                                 21                 : #include "catalog/pg_class.h"
                                 22                 : #include "miscadmin.h"
                                 23                 : #include "utils/acl.h"
                                 24                 : #include "utils/builtins.h"
                                 25                 : #include "utils/lsyscache.h"
                                 26                 : #include "utils/rls.h"
                                 27                 : #include "utils/syscache.h"
                                 28                 : #include "utils/varlena.h"
                                 29                 : 
                                 30                 : 
                                 31                 : /*
                                 32                 :  * check_enable_rls
                                 33                 :  *
                                 34                 :  * Determine, based on the relation, row_security setting, and current role,
                                 35                 :  * if RLS is applicable to this query.  RLS_NONE_ENV indicates that, while
                                 36                 :  * RLS is not to be added for this query, a change in the environment may change
                                 37                 :  * that.  RLS_NONE means that RLS is not on the relation at all and therefore
                                 38                 :  * we don't need to worry about it.  RLS_ENABLED means RLS should be implemented
                                 39                 :  * for the table and the plan cache needs to be invalidated if the environment
                                 40                 :  * changes.
                                 41                 :  *
                                 42                 :  * Handle checking as another role via checkAsUser (for views, etc).  Pass
                                 43                 :  * InvalidOid to check the current user.
                                 44                 :  *
                                 45                 :  * If noError is set to 'true' then we just return RLS_ENABLED instead of doing
                                 46                 :  * an ereport() if the user has attempted to bypass RLS and they are not
                                 47                 :  * allowed to.  This allows users to check if RLS is enabled without having to
                                 48                 :  * deal with the actual error case (eg: error cases which are trying to decide
                                 49                 :  * if the user should get data from the relation back as part of the error).
                                 50                 :  */
                                 51                 : int
 3009 sfrost                     52 CBC      421562 : check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
                                 53                 : {
  130 alvherre                   54 GNC      421562 :     Oid         user_id = OidIsValid(checkAsUser) ? checkAsUser : GetUserId();
                                 55                 :     HeapTuple   tuple;
                                 56                 :     Form_pg_class classform;
                                 57                 :     bool        relrowsecurity;
                                 58                 :     bool        relforcerowsecurity;
                                 59                 :     bool        amowner;
                                 60                 : 
                                 61                 :     /* Nothing to do for built-in relations */
 2652 tgl                        62 CBC      421562 :     if (relid < (Oid) FirstNormalObjectId)
 2812 mail                       63          116837 :         return RLS_NONE;
                                 64                 : 
                                 65                 :     /* Fetch relation's relrowsecurity and relforcerowsecurity flags */
 3009 sfrost                     66          304725 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                                 67          304725 :     if (!HeapTupleIsValid(tuple))
 3009 sfrost                     68 UBC           0 :         return RLS_NONE;
 3009 sfrost                     69 CBC      304725 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                                 70                 : 
                                 71          304725 :     relrowsecurity = classform->relrowsecurity;
 2744                            72          304725 :     relforcerowsecurity = classform->relforcerowsecurity;
                                 73                 : 
 3009                            74          304725 :     ReleaseSysCache(tuple);
                                 75                 : 
                                 76                 :     /* Nothing to do if the relation does not have RLS */
                                 77          304725 :     if (!relrowsecurity)
                                 78          303093 :         return RLS_NONE;
                                 79                 : 
                                 80                 :     /*
                                 81                 :      * BYPASSRLS users always bypass RLS.  Note that superusers are always
                                 82                 :      * considered to have BYPASSRLS.
                                 83                 :      *
                                 84                 :      * Return RLS_NONE_ENV to indicate that this decision depends on the
                                 85                 :      * environment (in this case, the user_id).
                                 86                 :      */
 2744                            87            1632 :     if (has_bypassrls_privilege(user_id))
 3009                            88             252 :         return RLS_NONE_ENV;
                                 89                 : 
                                 90                 :     /*
                                 91                 :      * Table owners generally bypass RLS, except if the table has been set (by
                                 92                 :      * an owner) to FORCE ROW SECURITY, and this is not a referential
                                 93                 :      * integrity check.
                                 94                 :      *
                                 95                 :      * Return RLS_NONE_ENV to indicate that this decision depends on the
                                 96                 :      * environment (in this case, the user_id).
                                 97                 :      */
  147 peter                      98 GNC        1380 :     amowner = object_ownercheck(RelationRelationId, relid, user_id);
 2652 tgl                        99 CBC        1380 :     if (amowner)
                                100                 :     {
                                101                 :         /*
                                102                 :          * If FORCE ROW LEVEL SECURITY has been set on the relation then we
                                103                 :          * should return RLS_ENABLED to indicate that RLS should be applied.
                                104                 :          * If not, or if we are in an InNoForceRLSOperation context, we return
                                105                 :          * RLS_NONE_ENV.
                                106                 :          *
                                107                 :          * InNoForceRLSOperation indicates that we should not apply RLS even
                                108                 :          * if the table has FORCE RLS set - IF the current user is the owner.
                                109                 :          * This is specifically to ensure that referential integrity checks
                                110                 :          * are able to still run correctly.
                                111                 :          *
                                112                 :          * This is intentionally only done after we have checked that the user
                                113                 :          * is the table owner, which should always be the case for referential
                                114                 :          * integrity checks.
                                115                 :          */
                                116             195 :         if (!relforcerowsecurity || InNoForceRLSOperation())
 2744 sfrost                    117             114 :             return RLS_NONE_ENV;
                                118                 :     }
                                119                 : 
                                120                 :     /*
                                121                 :      * We should apply RLS.  However, the user may turn off the row_security
                                122                 :      * GUC to get a forced error instead.
                                123                 :      */
 2745 noah                      124            1266 :     if (!row_security && !noError)
                                125              33 :         ereport(ERROR,
                                126                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                127                 :                  errmsg("query would be affected by row-level security policy for table \"%s\"",
                                128                 :                         get_rel_name(relid)),
                                129                 :                  amowner ? errhint("To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.") : 0));
                                130                 : 
                                131                 :     /* RLS should be fully enabled for this relation. */
 3009 sfrost                    132            1233 :     return RLS_ENABLED;
                                133                 : }
                                134                 : 
                                135                 : /*
                                136                 :  * row_security_active
                                137                 :  *
                                138                 :  * check_enable_rls wrapped as a SQL callable function except
                                139                 :  * RLS_NONE_ENV and RLS_NONE are the same for this purpose.
                                140                 :  */
                                141                 : Datum
 2812 mail                      142               6 : row_security_active(PG_FUNCTION_ARGS)
                                143                 : {
                                144                 :     /* By OID */
                                145               6 :     Oid         tableoid = PG_GETARG_OID(0);
                                146                 :     int         rls_status;
                                147                 : 
                                148               6 :     rls_status = check_enable_rls(tableoid, InvalidOid, true);
                                149               6 :     PG_RETURN_BOOL(rls_status == RLS_ENABLED);
                                150                 : }
                                151                 : 
                                152                 : Datum
                                153               6 : row_security_active_name(PG_FUNCTION_ARGS)
                                154                 : {
                                155                 :     /* By qualified name */
 2219 noah                      156               6 :     text       *tablename = PG_GETARG_TEXT_PP(0);
                                157                 :     RangeVar   *tablerel;
                                158                 :     Oid         tableoid;
                                159                 :     int         rls_status;
                                160                 : 
                                161                 :     /* Look up table name.  Can't lock it - we might not have privileges. */
 2812 mail                      162               6 :     tablerel = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
                                163               6 :     tableoid = RangeVarGetRelid(tablerel, NoLock, false);
                                164                 : 
                                165               6 :     rls_status = check_enable_rls(tableoid, InvalidOid, true);
                                166               6 :     PG_RETURN_BOOL(rls_status == RLS_ENABLED);
                                167                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a