LCOV - differential code coverage report
Current view: top level - contrib/sepgsql - dml.c (source / functions) Coverage Total Hit UBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 0.0 % 123 0 123
Current Date: 2024-04-14 14:21:10 Functions: 0.0 % 4 0 4
Baseline: 16@8cea358b128 Branches: 0.0 % 90 0 90
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: 0.0 % 123 0 123
Function coverage date bins:
(240..) days: 0.0 % 4 0 4
Branch coverage date bins:
(240..) days: 0.0 % 90 0 90

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* -------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * contrib/sepgsql/dml.c
                                  4                 :                :  *
                                  5                 :                :  * Routines to handle DML permission checks
                                  6                 :                :  *
                                  7                 :                :  * Copyright (c) 2010-2024, PostgreSQL Global Development Group
                                  8                 :                :  *
                                  9                 :                :  * -------------------------------------------------------------------------
                                 10                 :                :  */
                                 11                 :                : #include "postgres.h"
                                 12                 :                : 
                                 13                 :                : #include "access/htup_details.h"
                                 14                 :                : #include "access/sysattr.h"
                                 15                 :                : #include "access/tupdesc.h"
                                 16                 :                : #include "catalog/catalog.h"
                                 17                 :                : #include "catalog/dependency.h"
                                 18                 :                : #include "catalog/heap.h"
                                 19                 :                : #include "catalog/pg_attribute.h"
                                 20                 :                : #include "catalog/pg_class.h"
                                 21                 :                : #include "catalog/pg_inherits.h"
                                 22                 :                : #include "commands/seclabel.h"
                                 23                 :                : #include "commands/tablecmds.h"
                                 24                 :                : #include "executor/executor.h"
                                 25                 :                : #include "nodes/bitmapset.h"
                                 26                 :                : #include "parser/parsetree.h"
                                 27                 :                : #include "sepgsql.h"
                                 28                 :                : #include "utils/lsyscache.h"
                                 29                 :                : #include "utils/syscache.h"
                                 30                 :                : 
                                 31                 :                : /*
                                 32                 :                :  * fixup_whole_row_references
                                 33                 :                :  *
                                 34                 :                :  * When user references a whole-row Var, it is equivalent to referencing
                                 35                 :                :  * all the user columns (not system columns). So, we need to fix up the
                                 36                 :                :  * given bitmapset, if it contains a whole-row reference.
                                 37                 :                :  */
                                 38                 :                : static Bitmapset *
 4830 rhaas@postgresql.org       39                 :UBC           0 : fixup_whole_row_references(Oid relOid, Bitmapset *columns)
                                 40                 :                : {
                                 41                 :                :     Bitmapset  *result;
                                 42                 :                :     HeapTuple   tuple;
                                 43                 :                :     AttrNumber  natts;
                                 44                 :                :     AttrNumber  attno;
                                 45                 :                :     int         index;
                                 46                 :                : 
                                 47                 :                :     /* if no whole-row references, nothing to do */
                                 48                 :              0 :     index = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber;
                                 49         [ #  # ]:              0 :     if (!bms_is_member(index, columns))
                                 50                 :              0 :         return columns;
                                 51                 :                : 
                                 52                 :                :     /* obtain number of attributes */
                                 53                 :              0 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
                                 54         [ #  # ]:              0 :     if (!HeapTupleIsValid(tuple))
                                 55         [ #  # ]:              0 :         elog(ERROR, "cache lookup failed for relation %u", relOid);
                                 56                 :              0 :     natts = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
                                 57                 :              0 :     ReleaseSysCache(tuple);
                                 58                 :                : 
                                 59                 :                :     /* remove bit 0 from column set, add in all the non-dropped columns */
                                 60                 :              0 :     result = bms_copy(columns);
                                 61                 :              0 :     result = bms_del_member(result, index);
                                 62                 :                : 
 4753 bruce@momjian.us           63         [ #  # ]:              0 :     for (attno = 1; attno <= natts; attno++)
                                 64                 :                :     {
 4830 rhaas@postgresql.org       65                 :              0 :         tuple = SearchSysCache2(ATTNUM,
                                 66                 :                :                                 ObjectIdGetDatum(relOid),
                                 67                 :                :                                 Int16GetDatum(attno));
                                 68         [ #  # ]:              0 :         if (!HeapTupleIsValid(tuple))
 1459 tgl@sss.pgh.pa.us          69                 :              0 :             continue;           /* unexpected case, should we error? */
                                 70                 :                : 
                                 71         [ #  # ]:              0 :         if (!((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
                                 72                 :                :         {
                                 73                 :              0 :             index = attno - FirstLowInvalidHeapAttributeNumber;
                                 74                 :              0 :             result = bms_add_member(result, index);
                                 75                 :                :         }
                                 76                 :                : 
 4830 rhaas@postgresql.org       77                 :              0 :         ReleaseSysCache(tuple);
                                 78                 :                :     }
                                 79                 :              0 :     return result;
                                 80                 :                : }
                                 81                 :                : 
                                 82                 :                : /*
                                 83                 :                :  * fixup_inherited_columns
                                 84                 :                :  *
                                 85                 :                :  * When user is querying on a table with children, it implicitly accesses
                                 86                 :                :  * child tables also. So, we also need to check security label of child
                                 87                 :                :  * tables and columns, but there is no guarantee attribute numbers are
                                 88                 :                :  * same between the parent and children.
                                 89                 :                :  * It returns a bitmapset which contains attribute number of the child
                                 90                 :                :  * table based on the given bitmapset of the parent.
                                 91                 :                :  */
                                 92                 :                : static Bitmapset *
                                 93                 :              0 : fixup_inherited_columns(Oid parentId, Oid childId, Bitmapset *columns)
                                 94                 :                : {
                                 95                 :              0 :     Bitmapset  *result = NULL;
                                 96                 :                :     int         index;
                                 97                 :                : 
                                 98                 :                :     /*
                                 99                 :                :      * obviously, no need to do anything here
                                100                 :                :      */
                                101         [ #  # ]:              0 :     if (parentId == childId)
                                102                 :              0 :         return columns;
                                103                 :                : 
 3425 tgl@sss.pgh.pa.us         104                 :              0 :     index = -1;
                                105         [ #  # ]:              0 :     while ((index = bms_next_member(columns, index)) >= 0)
                                106                 :                :     {
                                107                 :                :         /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
                                108                 :              0 :         AttrNumber  attno = index + FirstLowInvalidHeapAttributeNumber;
                                109                 :                :         char       *attname;
                                110                 :                : 
                                111                 :                :         /*
                                112                 :                :          * whole-row-reference shall be fixed-up later
                                113                 :                :          */
 4830 rhaas@postgresql.org      114         [ #  # ]:              0 :         if (attno == InvalidAttrNumber)
                                115                 :                :         {
                                116                 :              0 :             result = bms_add_member(result, index);
                                117                 :              0 :             continue;
                                118                 :                :         }
                                119                 :                : 
 2253 alvherre@alvh.no-ip.      120                 :              0 :         attname = get_attname(parentId, attno, false);
 4830 rhaas@postgresql.org      121                 :              0 :         attno = get_attnum(childId, attname);
                                122         [ #  # ]:              0 :         if (attno == InvalidAttrNumber)
                                123         [ #  # ]:              0 :             elog(ERROR, "cache lookup failed for attribute %s of relation %u",
                                124                 :                :                  attname, childId);
                                125                 :                : 
 3425 tgl@sss.pgh.pa.us         126                 :              0 :         result = bms_add_member(result,
                                127                 :                :                                 attno - FirstLowInvalidHeapAttributeNumber);
                                128                 :                : 
 4830 rhaas@postgresql.org      129                 :              0 :         pfree(attname);
                                130                 :                :     }
                                131                 :                : 
                                132                 :              0 :     return result;
                                133                 :                : }
                                134                 :                : 
                                135                 :                : /*
                                136                 :                :  * check_relation_privileges
                                137                 :                :  *
                                138                 :                :  * It actually checks required permissions on a certain relation
                                139                 :                :  * and its columns.
                                140                 :                :  */
                                141                 :                : static bool
                                142                 :              0 : check_relation_privileges(Oid relOid,
                                143                 :                :                           Bitmapset *selected,
                                144                 :                :                           Bitmapset *inserted,
                                145                 :                :                           Bitmapset *updated,
                                146                 :                :                           uint32 required,
                                147                 :                :                           bool abort_on_violation)
                                148                 :                : {
                                149                 :                :     ObjectAddress object;
                                150                 :                :     char       *audit_name;
                                151                 :                :     Bitmapset  *columns;
                                152                 :                :     int         index;
 4609                           153                 :              0 :     char        relkind = get_rel_relkind(relOid);
 4830                           154                 :              0 :     bool        result = true;
                                155                 :                : 
                                156                 :                :     /*
                                157                 :                :      * Hardwired Policies: SE-PostgreSQL enforces - clients cannot modify
                                158                 :                :      * system catalogs using DMLs - clients cannot reference/modify toast
                                159                 :                :      * relations using DMLs
                                160                 :                :      */
                                161         [ #  # ]:              0 :     if (sepgsql_getenforce() > 0)
                                162                 :                :     {
 1803 tgl@sss.pgh.pa.us         163         [ #  # ]:              0 :         if ((required & (SEPG_DB_TABLE__UPDATE |
                                164                 :                :                          SEPG_DB_TABLE__INSERT |
                                165         [ #  # ]:              0 :                          SEPG_DB_TABLE__DELETE)) != 0 &&
                                166                 :              0 :             IsCatalogRelationOid(relOid))
 4830 rhaas@postgresql.org      167         [ #  # ]:              0 :             ereport(ERROR,
                                168                 :                :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                169                 :                :                      errmsg("SELinux: hardwired security policy violation")));
                                170                 :                : 
                                171         [ #  # ]:              0 :         if (relkind == RELKIND_TOASTVALUE)
                                172         [ #  # ]:              0 :             ereport(ERROR,
                                173                 :                :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                174                 :                :                      errmsg("SELinux: hardwired security policy violation")));
                                175                 :                :     }
                                176                 :                : 
                                177                 :                :     /*
                                178                 :                :      * Check permissions on the relation
                                179                 :                :      */
 4609                           180                 :              0 :     object.classId = RelationRelationId;
                                181                 :              0 :     object.objectId = relOid;
                                182                 :              0 :     object.objectSubId = 0;
 1369 michael@paquier.xyz       183                 :              0 :     audit_name = getObjectIdentity(&object, false);
 4830 rhaas@postgresql.org      184   [ #  #  #  # ]:              0 :     switch (relkind)
                                185                 :                :     {
                                186                 :              0 :         case RELKIND_RELATION:
                                187                 :                :         case RELKIND_PARTITIONED_TABLE:
 4609                           188                 :              0 :             result = sepgsql_avc_check_perms(&object,
                                189                 :                :                                              SEPG_CLASS_DB_TABLE,
                                190                 :                :                                              required,
                                191                 :                :                                              audit_name,
                                192                 :                :                                              abort_on_violation);
 4830                           193                 :              0 :             break;
                                194                 :                : 
                                195                 :              0 :         case RELKIND_SEQUENCE:
                                196         [ #  # ]:              0 :             Assert((required & ~SEPG_DB_TABLE__SELECT) == 0);
                                197                 :                : 
                                198         [ #  # ]:              0 :             if (required & SEPG_DB_TABLE__SELECT)
 4609                           199                 :              0 :                 result = sepgsql_avc_check_perms(&object,
                                200                 :                :                                                  SEPG_CLASS_DB_SEQUENCE,
                                201                 :                :                                                  SEPG_DB_SEQUENCE__GET_VALUE,
                                202                 :                :                                                  audit_name,
                                203                 :                :                                                  abort_on_violation);
 4820                           204                 :              0 :             break;
                                205                 :                : 
 4830                           206                 :              0 :         case RELKIND_VIEW:
 4609                           207                 :              0 :             result = sepgsql_avc_check_perms(&object,
                                208                 :                :                                              SEPG_CLASS_DB_VIEW,
                                209                 :                :                                              SEPG_DB_VIEW__EXPAND,
                                210                 :                :                                              audit_name,
                                211                 :                :                                              abort_on_violation);
 4820                           212                 :              0 :             break;
                                213                 :                : 
 4830                           214                 :              0 :         default:
                                215                 :                :             /* nothing to be checked */
 4820                           216                 :              0 :             break;
                                217                 :                :     }
                                218                 :              0 :     pfree(audit_name);
                                219                 :                : 
                                220                 :                :     /*
                                221                 :                :      * Only columns owned by relations shall be checked
                                222                 :                :      */
 2562 mail@joeconway.com        223   [ #  #  #  # ]:              0 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
 4820 rhaas@postgresql.org      224                 :              0 :         return true;
                                225                 :                : 
                                226                 :                :     /*
                                227                 :                :      * Check permissions on the columns
                                228                 :                :      */
 4830                           229                 :              0 :     selected = fixup_whole_row_references(relOid, selected);
 3264 andres@anarazel.de        230                 :              0 :     inserted = fixup_whole_row_references(relOid, inserted);
                                231                 :              0 :     updated = fixup_whole_row_references(relOid, updated);
                                232                 :              0 :     columns = bms_union(selected, bms_union(inserted, updated));
                                233                 :                : 
  409 tgl@sss.pgh.pa.us         234                 :              0 :     index = -1;
                                235         [ #  # ]:              0 :     while ((index = bms_next_member(columns, index)) >= 0)
                                236                 :                :     {
                                237                 :                :         AttrNumber  attnum;
 4830 rhaas@postgresql.org      238                 :              0 :         uint32      column_perms = 0;
                                239                 :                : 
                                240         [ #  # ]:              0 :         if (bms_is_member(index, selected))
                                241                 :              0 :             column_perms |= SEPG_DB_COLUMN__SELECT;
 3264 andres@anarazel.de        242         [ #  # ]:              0 :         if (bms_is_member(index, inserted))
                                243                 :                :         {
 4830 rhaas@postgresql.org      244         [ #  # ]:              0 :             if (required & SEPG_DB_TABLE__INSERT)
                                245                 :              0 :                 column_perms |= SEPG_DB_COLUMN__INSERT;
                                246                 :                :         }
 3264 andres@anarazel.de        247         [ #  # ]:              0 :         if (bms_is_member(index, updated))
                                248                 :                :         {
                                249         [ #  # ]:              0 :             if (required & SEPG_DB_TABLE__UPDATE)
                                250                 :              0 :                 column_perms |= SEPG_DB_COLUMN__UPDATE;
                                251                 :                :         }
 4830 rhaas@postgresql.org      252         [ #  # ]:              0 :         if (column_perms == 0)
                                253                 :              0 :             continue;
                                254                 :                : 
                                255                 :                :         /* obtain column's permission */
                                256                 :              0 :         attnum = index + FirstLowInvalidHeapAttributeNumber;
                                257                 :                : 
 4820                           258                 :              0 :         object.classId = RelationRelationId;
                                259                 :              0 :         object.objectId = relOid;
                                260                 :              0 :         object.objectSubId = attnum;
 1369 michael@paquier.xyz       261                 :              0 :         audit_name = getObjectDescription(&object, false);
                                262                 :                : 
 4609 rhaas@postgresql.org      263                 :              0 :         result = sepgsql_avc_check_perms(&object,
                                264                 :                :                                          SEPG_CLASS_DB_COLUMN,
                                265                 :                :                                          column_perms,
                                266                 :                :                                          audit_name,
                                267                 :                :                                          abort_on_violation);
 4820                           268                 :              0 :         pfree(audit_name);
                                269                 :                : 
 4830                           270         [ #  # ]:              0 :         if (!result)
                                271                 :              0 :             return result;
                                272                 :                :     }
                                273                 :              0 :     return true;
                                274                 :                : }
                                275                 :                : 
                                276                 :                : /*
                                277                 :                :  * sepgsql_dml_privileges
                                278                 :                :  *
                                279                 :                :  * Entrypoint of the DML permission checks
                                280                 :                :  */
                                281                 :                : bool
  495 alvherre@alvh.no-ip.      282                 :              0 : sepgsql_dml_privileges(List *rangeTbls, List *rteperminfos,
                                283                 :                :                        bool abort_on_violation)
                                284                 :                : {
                                285                 :                :     ListCell   *lr;
                                286                 :                : 
                                287   [ #  #  #  #  :              0 :     foreach(lr, rteperminfos)
                                              #  # ]
                                288                 :                :     {
                                289                 :              0 :         RTEPermissionInfo *perminfo = lfirst_node(RTEPermissionInfo, lr);
 4753 bruce@momjian.us          290                 :              0 :         uint32      required = 0;
                                291                 :                :         List       *tableIds;
                                292                 :                :         ListCell   *li;
                                293                 :                : 
                                294                 :                :         /*
                                295                 :                :          * Find out required permissions
                                296                 :                :          */
  495 alvherre@alvh.no-ip.      297         [ #  # ]:              0 :         if (perminfo->requiredPerms & ACL_SELECT)
 4830 rhaas@postgresql.org      298                 :              0 :             required |= SEPG_DB_TABLE__SELECT;
  495 alvherre@alvh.no-ip.      299         [ #  # ]:              0 :         if (perminfo->requiredPerms & ACL_INSERT)
 4830 rhaas@postgresql.org      300                 :              0 :             required |= SEPG_DB_TABLE__INSERT;
  495 alvherre@alvh.no-ip.      301         [ #  # ]:              0 :         if (perminfo->requiredPerms & ACL_UPDATE)
                                302                 :                :         {
                                303         [ #  # ]:              0 :             if (!bms_is_empty(perminfo->updatedCols))
 4830 rhaas@postgresql.org      304                 :              0 :                 required |= SEPG_DB_TABLE__UPDATE;
                                305                 :                :             else
                                306                 :              0 :                 required |= SEPG_DB_TABLE__LOCK;
                                307                 :                :         }
  495 alvherre@alvh.no-ip.      308         [ #  # ]:              0 :         if (perminfo->requiredPerms & ACL_DELETE)
 4830 rhaas@postgresql.org      309                 :              0 :             required |= SEPG_DB_TABLE__DELETE;
                                310                 :                : 
                                311                 :                :         /*
                                312                 :                :          * Skip, if nothing to be checked
                                313                 :                :          */
                                314         [ #  # ]:              0 :         if (required == 0)
                                315                 :              0 :             continue;
                                316                 :                : 
                                317                 :                :         /*
                                318                 :                :          * If this RangeTblEntry is also supposed to reference inherited
                                319                 :                :          * tables, we need to check security label of the child tables. So, we
                                320                 :                :          * expand rte->relid into list of OIDs of inheritance hierarchy, then
                                321                 :                :          * checker routine will be invoked for each relations.
                                322                 :                :          */
  495 alvherre@alvh.no-ip.      323         [ #  # ]:              0 :         if (!perminfo->inh)
                                324                 :              0 :             tableIds = list_make1_oid(perminfo->relid);
                                325                 :                :         else
                                326                 :              0 :             tableIds = find_all_inheritors(perminfo->relid, NoLock, NULL);
                                327                 :                : 
 4753 bruce@momjian.us          328   [ #  #  #  #  :              0 :         foreach(li, tableIds)
                                              #  # ]
                                329                 :                :         {
 4830 rhaas@postgresql.org      330                 :              0 :             Oid         tableOid = lfirst_oid(li);
                                331                 :                :             Bitmapset  *selectedCols;
                                332                 :                :             Bitmapset  *insertedCols;
                                333                 :                :             Bitmapset  *updatedCols;
                                334                 :                : 
                                335                 :                :             /*
                                336                 :                :              * child table has different attribute numbers, so we need to fix
                                337                 :                :              * up them.
                                338                 :                :              */
  495 alvherre@alvh.no-ip.      339                 :              0 :             selectedCols = fixup_inherited_columns(perminfo->relid, tableOid,
                                340                 :                :                                                    perminfo->selectedCols);
                                341                 :              0 :             insertedCols = fixup_inherited_columns(perminfo->relid, tableOid,
                                342                 :                :                                                    perminfo->insertedCols);
                                343                 :              0 :             updatedCols = fixup_inherited_columns(perminfo->relid, tableOid,
                                344                 :                :                                                   perminfo->updatedCols);
                                345                 :                : 
                                346                 :                :             /*
                                347                 :                :              * check permissions on individual tables
                                348                 :                :              */
 4830 rhaas@postgresql.org      349         [ #  # ]:              0 :             if (!check_relation_privileges(tableOid,
                                350                 :                :                                            selectedCols,
                                351                 :                :                                            insertedCols,
                                352                 :                :                                            updatedCols,
                                353                 :                :                                            required, abort_on_violation))
                                354                 :              0 :                 return false;
                                355                 :                :         }
                                356                 :              0 :         list_free(tableIds);
                                357                 :                :     }
                                358                 :              0 :     return true;
                                359                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622