PostgreSQL Source Code  git master
dml.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/tupdesc.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/pg_attribute.h"
#include "catalog/pg_class.h"
#include "catalog/pg_inherits.h"
#include "commands/seclabel.h"
#include "commands/tablecmds.h"
#include "executor/executor.h"
#include "nodes/bitmapset.h"
#include "sepgsql.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for dml.c:

Go to the source code of this file.

Functions

static Bitmapsetfixup_whole_row_references (Oid relOid, Bitmapset *columns)
 
static Bitmapsetfixup_inherited_columns (Oid parentId, Oid childId, Bitmapset *columns)
 
static bool check_relation_privileges (Oid relOid, Bitmapset *selected, Bitmapset *inserted, Bitmapset *updated, uint32 required, bool abort_on_violation)
 
bool sepgsql_dml_privileges (List *rangeTabls, bool abort_on_violation)
 

Function Documentation

◆ check_relation_privileges()

static bool check_relation_privileges ( Oid  relOid,
Bitmapset selected,
Bitmapset inserted,
Bitmapset updated,
uint32  required,
bool  abort_on_violation 
)
static

Definition at line 142 of file dml.c.

References Assert, attnum, bms_first_member(), bms_is_member(), bms_union(), ereport, errcode(), errmsg(), ERROR, FirstLowInvalidHeapAttributeNumber, fixup_whole_row_references(), get_rel_relkind(), getObjectDescription(), getObjectIdentity(), IsCatalogRelationOid(), pfree(), relkind, SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_SEQUENCE, SEPG_CLASS_DB_TABLE, SEPG_CLASS_DB_VIEW, SEPG_DB_COLUMN__INSERT, SEPG_DB_COLUMN__SELECT, SEPG_DB_COLUMN__UPDATE, SEPG_DB_SEQUENCE__GET_VALUE, SEPG_DB_TABLE__DELETE, SEPG_DB_TABLE__INSERT, SEPG_DB_TABLE__SELECT, SEPG_DB_TABLE__UPDATE, SEPG_DB_VIEW__EXPAND, sepgsql_avc_check_perms(), and sepgsql_getenforce().

Referenced by sepgsql_dml_privileges().

148 {
149  ObjectAddress object;
150  char *audit_name;
151  Bitmapset *columns;
152  int index;
153  char relkind = get_rel_relkind(relOid);
154  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  if (sepgsql_getenforce() > 0)
162  {
165  SEPG_DB_TABLE__DELETE)) != 0 &&
166  IsCatalogRelationOid(relOid))
167  ereport(ERROR,
168  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
169  errmsg("SELinux: hardwired security policy violation")));
170 
171  if (relkind == RELKIND_TOASTVALUE)
172  ereport(ERROR,
173  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
174  errmsg("SELinux: hardwired security policy violation")));
175  }
176 
177  /*
178  * Check permissions on the relation
179  */
180  object.classId = RelationRelationId;
181  object.objectId = relOid;
182  object.objectSubId = 0;
183  audit_name = getObjectIdentity(&object);
184  switch (relkind)
185  {
186  case RELKIND_RELATION:
187  case RELKIND_PARTITIONED_TABLE:
188  result = sepgsql_avc_check_perms(&object,
190  required,
191  audit_name,
192  abort_on_violation);
193  break;
194 
195  case RELKIND_SEQUENCE:
197 
199  result = sepgsql_avc_check_perms(&object,
202  audit_name,
203  abort_on_violation);
204  break;
205 
206  case RELKIND_VIEW:
207  result = sepgsql_avc_check_perms(&object,
210  audit_name,
211  abort_on_violation);
212  break;
213 
214  default:
215  /* nothing to be checked */
216  break;
217  }
218  pfree(audit_name);
219 
220  /*
221  * Only columns owned by relations shall be checked
222  */
223  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
224  return true;
225 
226  /*
227  * Check permissions on the columns
228  */
229  selected = fixup_whole_row_references(relOid, selected);
230  inserted = fixup_whole_row_references(relOid, inserted);
231  updated = fixup_whole_row_references(relOid, updated);
232  columns = bms_union(selected, bms_union(inserted, updated));
233 
234  while ((index = bms_first_member(columns)) >= 0)
235  {
237  uint32 column_perms = 0;
238 
239  if (bms_is_member(index, selected))
240  column_perms |= SEPG_DB_COLUMN__SELECT;
241  if (bms_is_member(index, inserted))
242  {
244  column_perms |= SEPG_DB_COLUMN__INSERT;
245  }
246  if (bms_is_member(index, updated))
247  {
249  column_perms |= SEPG_DB_COLUMN__UPDATE;
250  }
251  if (column_perms == 0)
252  continue;
253 
254  /* obtain column's permission */
255  attnum = index + FirstLowInvalidHeapAttributeNumber;
256 
257  object.classId = RelationRelationId;
258  object.objectId = relOid;
259  object.objectSubId = attnum;
260  audit_name = getObjectDescription(&object);
261 
262  result = sepgsql_avc_check_perms(&object,
264  column_perms,
265  audit_name,
266  abort_on_violation);
267  pfree(audit_name);
268 
269  if (!result)
270  return result;
271  }
272  return true;
273 }
#define SEPG_DB_VIEW__EXPAND
Definition: sepgsql.h:213
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:996
#define SEPG_CLASS_DB_COLUMN
Definition: sepgsql.h:49
static Bitmapset * fixup_whole_row_references(Oid relOid, Bitmapset *columns)
Definition: dml.c:38
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
bool sepgsql_avc_check_perms(const ObjectAddress *tobject, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
Definition: uavc.c:419
#define SEPG_DB_TABLE__DELETE
Definition: sepgsql.h:146
int errcode(int sqlerrcode)
Definition: elog.c:608
bool sepgsql_getenforce(void)
Definition: selinux.c:651
#define SEPG_DB_COLUMN__INSERT
Definition: sepgsql.h:178
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
char * getObjectDescription(const ObjectAddress *object)
char relkind
Definition: pg_class.h:81
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:116
#define SEPG_DB_TABLE__SELECT
Definition: sepgsql.h:143
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:1056
#define SEPG_CLASS_DB_SEQUENCE
Definition: sepgsql.h:47
#define ERROR
Definition: elog.h:43
#define SEPG_DB_COLUMN__SELECT
Definition: sepgsql.h:176
#define SEPG_DB_SEQUENCE__GET_VALUE
Definition: sepgsql.h:156
char * getObjectIdentity(const ObjectAddress *object)
#define SEPG_DB_TABLE__UPDATE
Definition: sepgsql.h:144
#define SEPG_DB_TABLE__INSERT
Definition: sepgsql.h:145
unsigned int uint32
Definition: c.h:359
#define ereport(elevel, rest)
Definition: elog.h:141
#define SEPG_DB_COLUMN__UPDATE
Definition: sepgsql.h:177
#define SEPG_CLASS_DB_VIEW
Definition: sepgsql.h:53
int16 attnum
Definition: pg_attribute.h:79
#define SEPG_CLASS_DB_TABLE
Definition: sepgsql.h:46
#define Assert(condition)
Definition: c.h:739
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21

◆ fixup_inherited_columns()

static Bitmapset* fixup_inherited_columns ( Oid  parentId,
Oid  childId,
Bitmapset columns 
)
static

Definition at line 93 of file dml.c.

References attname, bms_add_member(), bms_next_member(), elog, ERROR, FirstLowInvalidHeapAttributeNumber, get_attname(), get_attnum(), InvalidAttrNumber, and pfree().

Referenced by sepgsql_dml_privileges().

94 {
95  Bitmapset *result = NULL;
96  int index;
97 
98  /*
99  * obviously, no need to do anything here
100  */
101  if (parentId == childId)
102  return columns;
103 
104  index = -1;
105  while ((index = bms_next_member(columns, index)) >= 0)
106  {
107  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
109  char *attname;
110 
111  /*
112  * whole-row-reference shall be fixed-up later
113  */
114  if (attno == InvalidAttrNumber)
115  {
116  result = bms_add_member(result, index);
117  continue;
118  }
119 
120  attname = get_attname(parentId, attno, false);
121  attno = get_attnum(childId, attname);
122  if (attno == InvalidAttrNumber)
123  elog(ERROR, "cache lookup failed for attribute %s of relation %u",
124  attname, childId);
125 
126  result = bms_add_member(result,
127  attno - FirstLowInvalidHeapAttributeNumber);
128 
129  pfree(attname);
130  }
131 
132  return result;
133 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
NameData attname
Definition: pg_attribute.h:40
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:806
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
#define elog(elevel,...)
Definition: elog.h:228
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
int16 AttrNumber
Definition: attnum.h:21

◆ fixup_whole_row_references()

static Bitmapset* fixup_whole_row_references ( Oid  relOid,
Bitmapset columns 
)
static

Definition at line 38 of file dml.c.

References ATTNUM, bms_add_member(), bms_copy(), bms_del_member(), bms_is_member(), elog, ERROR, FirstLowInvalidHeapAttributeNumber, GETSTRUCT, HeapTupleIsValid, Int16GetDatum, InvalidAttrNumber, ObjectIdGetDatum, ReleaseSysCache(), relnatts, RELOID, SearchSysCache1(), and SearchSysCache2().

Referenced by check_relation_privileges().

39 {
40  Bitmapset *result;
41  HeapTuple tuple;
42  AttrNumber natts;
43  AttrNumber attno;
44  int index;
45 
46  /* if no whole of row references, do not anything */
48  if (!bms_is_member(index, columns))
49  return columns;
50 
51  /* obtain number of attributes */
52  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
53  if (!HeapTupleIsValid(tuple))
54  elog(ERROR, "cache lookup failed for relation %u", relOid);
55  natts = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
56  ReleaseSysCache(tuple);
57 
58  /* fix up the given columns */
59  result = bms_copy(columns);
60  result = bms_del_member(result, index);
61 
62  for (attno = 1; attno <= natts; attno++)
63  {
64  tuple = SearchSysCache2(ATTNUM,
65  ObjectIdGetDatum(relOid),
66  Int16GetDatum(attno));
67  if (!HeapTupleIsValid(tuple))
68  continue;
69 
70  if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
71  continue;
72 
73  index = attno - FirstLowInvalidHeapAttributeNumber;
74 
75  result = bms_add_member(result, index);
76 
77  ReleaseSysCache(tuple);
78  }
79  return result;
80 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define Int16GetDatum(X)
Definition: postgres.h:451
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: type.h:89
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
int16 relnatts
Definition: pg_class.h:84
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1127
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define elog(elevel,...)
Definition: elog.h:228
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21

◆ sepgsql_dml_privileges()

bool sepgsql_dml_privileges ( List rangeTabls,
bool  abort_on_violation 
)

Definition at line 281 of file dml.c.

References ACL_DELETE, ACL_INSERT, ACL_SELECT, ACL_UPDATE, bms_is_empty(), check_relation_privileges(), find_all_inheritors(), fixup_inherited_columns(), RangeTblEntry::inh, RangeTblEntry::insertedCols, lfirst, lfirst_oid, list_free(), list_make1_oid, NoLock, RangeTblEntry::relid, generate_unaccent_rules::required, RangeTblEntry::requiredPerms, RTE_RELATION, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, SEPG_DB_TABLE__DELETE, SEPG_DB_TABLE__INSERT, SEPG_DB_TABLE__LOCK, SEPG_DB_TABLE__SELECT, SEPG_DB_TABLE__UPDATE, and RangeTblEntry::updatedCols.

Referenced by sepgsql_exec_check_perms().

282 {
283  ListCell *lr;
284 
285  foreach(lr, rangeTabls)
286  {
287  RangeTblEntry *rte = lfirst(lr);
288  uint32 required = 0;
289  List *tableIds;
290  ListCell *li;
291 
292  /*
293  * Only regular relations shall be checked
294  */
295  if (rte->rtekind != RTE_RELATION)
296  continue;
297 
298  /*
299  * Find out required permissions
300  */
301  if (rte->requiredPerms & ACL_SELECT)
302  required |= SEPG_DB_TABLE__SELECT;
303  if (rte->requiredPerms & ACL_INSERT)
304  required |= SEPG_DB_TABLE__INSERT;
305  if (rte->requiredPerms & ACL_UPDATE)
306  {
307  if (!bms_is_empty(rte->updatedCols))
308  required |= SEPG_DB_TABLE__UPDATE;
309  else
310  required |= SEPG_DB_TABLE__LOCK;
311  }
312  if (rte->requiredPerms & ACL_DELETE)
313  required |= SEPG_DB_TABLE__DELETE;
314 
315  /*
316  * Skip, if nothing to be checked
317  */
318  if (required == 0)
319  continue;
320 
321  /*
322  * If this RangeTblEntry is also supposed to reference inherited
323  * tables, we need to check security label of the child tables. So, we
324  * expand rte->relid into list of OIDs of inheritance hierarchy, then
325  * checker routine will be invoked for each relations.
326  */
327  if (!rte->inh)
328  tableIds = list_make1_oid(rte->relid);
329  else
330  tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
331 
332  foreach(li, tableIds)
333  {
334  Oid tableOid = lfirst_oid(li);
335  Bitmapset *selectedCols;
336  Bitmapset *insertedCols;
337  Bitmapset *updatedCols;
338 
339  /*
340  * child table has different attribute numbers, so we need to fix
341  * up them.
342  */
343  selectedCols = fixup_inherited_columns(rte->relid, tableOid,
344  rte->selectedCols);
345  insertedCols = fixup_inherited_columns(rte->relid, tableOid,
346  rte->insertedCols);
347  updatedCols = fixup_inherited_columns(rte->relid, tableOid,
348  rte->updatedCols);
349 
350  /*
351  * check permissions on individual tables
352  */
353  if (!check_relation_privileges(tableOid,
354  selectedCols,
355  insertedCols,
356  updatedCols,
357  required, abort_on_violation))
358  return false;
359  }
360  list_free(tableIds);
361  }
362  return true;
363 }
static bool check_relation_privileges(Oid relOid, Bitmapset *selected, Bitmapset *inserted, Bitmapset *updated, uint32 required, bool abort_on_violation)
Definition: dml.c:142
#define SEPG_DB_TABLE__DELETE
Definition: sepgsql.h:146
static Bitmapset * fixup_inherited_columns(Oid parentId, Oid childId, Bitmapset *columns)
Definition: dml.c:93
#define ACL_DELETE
Definition: parsenodes.h:77
AclMode requiredPerms
Definition: parsenodes.h:1096
unsigned int Oid
Definition: postgres_ext.h:31
#define SEPG_DB_TABLE__SELECT
Definition: sepgsql.h:143
Bitmapset * selectedCols
Definition: parsenodes.h:1098
#define SEPG_DB_TABLE__UPDATE
Definition: sepgsql.h:144
#define NoLock
Definition: lockdefs.h:34
#define SEPG_DB_TABLE__INSERT
Definition: sepgsql.h:145
unsigned int uint32
Definition: c.h:359
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define ACL_UPDATE
Definition: parsenodes.h:76
#define ACL_SELECT
Definition: parsenodes.h:75
#define list_make1_oid(x1)
Definition: pg_list.h:249
Bitmapset * updatedCols
Definition: parsenodes.h:1100
#define lfirst(lc)
Definition: pg_list.h:190
#define ACL_INSERT
Definition: parsenodes.h:74
RTEKind rtekind
Definition: parsenodes.h:974
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
void list_free(List *list)
Definition: list.c:1377
Bitmapset * insertedCols
Definition: parsenodes.h:1099
Definition: pg_list.h:50
#define SEPG_DB_TABLE__LOCK
Definition: sepgsql.h:147
#define lfirst_oid(lc)
Definition: pg_list.h:192