LCOV - differential code coverage report
Current view: top level - src/backend/utils/misc - rls.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 96.9 % 32 31 1 31
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 3 3 3
Baseline: 16@8cea358b128 Branches: 87.5 % 24 21 3 21
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 96.9 % 32 31 1 31
Function coverage date bins:
(240..) days: 100.0 % 3 3 3
Branch coverage date bins:
(240..) days: 87.5 % 24 21 3 21

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * rls.c
                                  4                 :                :  *        RLS-related utility functions.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, 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/fmgrprotos.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
 3380 sfrost@snowman.net         52                 :CBC      425848 : check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
                                 53                 :                : {
  501 alvherre@alvh.no-ip.       54         [ +  + ]:         425848 :     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 */
 3023 tgl@sss.pgh.pa.us          62         [ +  + ]:         425848 :     if (relid < (Oid) FirstNormalObjectId)
 3183 mail@joeconway.com         63                 :         109500 :         return RLS_NONE;
                                 64                 :                : 
                                 65                 :                :     /* Fetch relation's relrowsecurity and relforcerowsecurity flags */
 3380 sfrost@snowman.net         66                 :         316348 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                                 67         [ -  + ]:         316348 :     if (!HeapTupleIsValid(tuple))
 3380 sfrost@snowman.net         68                 :UBC           0 :         return RLS_NONE;
 3380 sfrost@snowman.net         69                 :CBC      316348 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                                 70                 :                : 
                                 71                 :         316348 :     relrowsecurity = classform->relrowsecurity;
 3115                            72                 :         316348 :     relforcerowsecurity = classform->relforcerowsecurity;
                                 73                 :                : 
 3380                            74                 :         316348 :     ReleaseSysCache(tuple);
                                 75                 :                : 
                                 76                 :                :     /* Nothing to do if the relation does not have RLS */
                                 77         [ +  + ]:         316348 :     if (!relrowsecurity)
                                 78                 :         314593 :         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                 :                :      */
 3115                            87         [ +  + ]:           1755 :     if (has_bypassrls_privilege(user_id))
 3380                            88                 :            262 :         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                 :                :      */
  518 peter@eisentraut.org       98                 :           1493 :     amowner = object_ownercheck(RelationRelationId, relid, user_id);
 3023 tgl@sss.pgh.pa.us          99         [ +  + ]:           1493 :     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   [ +  +  +  + ]:            196 :         if (!relforcerowsecurity || InNoForceRLSOperation())
 3115 sfrost@snowman.net        117                 :            115 :             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                 :                :      */
 3116 noah@leadboat.com         124   [ +  +  +  - ]:           1378 :     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. */
 3380 sfrost@snowman.net        132                 :           1345 :     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
 3183 mail@joeconway.com        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 */
 2590 noah@leadboat.com         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. */
 3183 mail@joeconway.com        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 2.1-beta2-3-g6141622