PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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/heap.h"
#include "catalog/dependency.h"
#include "catalog/pg_attribute.h"
#include "catalog/pg_class.h"
#include "catalog/pg_inherits_fn.h"
#include "commands/seclabel.h"
#include "commands/tablecmds.h"
#include "executor/executor.h"
#include "nodes/bitmapset.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "sepgsql.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

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

Definition at line 146 of file dml.c.

References Assert, bms_first_member(), bms_is_member(), bms_union(), ereport, errcode(), errmsg(), ERROR, FirstLowInvalidHeapAttributeNumber, fixup_whole_row_references(), get_rel_namespace(), get_rel_relkind(), getObjectDescription(), getObjectIdentity(), IsSystemNamespace(), pfree(), RelationRelationId, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, RELKIND_VIEW, 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().

152 {
153  ObjectAddress object;
154  char *audit_name;
155  Bitmapset *columns;
156  int index;
157  char relkind = get_rel_relkind(relOid);
158  bool result = true;
159 
160  /*
161  * Hardwired Policies: SE-PostgreSQL enforces - clients cannot modify
162  * system catalogs using DMLs - clients cannot reference/modify toast
163  * relations using DMLs
164  */
165  if (sepgsql_getenforce() > 0)
166  {
167  Oid relnamespace = get_rel_namespace(relOid);
168 
169  if (IsSystemNamespace(relnamespace) &&
170  (required & (SEPG_DB_TABLE__UPDATE |
172  SEPG_DB_TABLE__DELETE)) != 0)
173  ereport(ERROR,
174  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
175  errmsg("SELinux: hardwired security policy violation")));
176 
177  if (relkind == RELKIND_TOASTVALUE)
178  ereport(ERROR,
179  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
180  errmsg("SELinux: hardwired security policy violation")));
181  }
182 
183  /*
184  * Check permissions on the relation
185  */
186  object.classId = RelationRelationId;
187  object.objectId = relOid;
188  object.objectSubId = 0;
189  audit_name = getObjectIdentity(&object);
190  switch (relkind)
191  {
192  case RELKIND_RELATION:
194  result = sepgsql_avc_check_perms(&object,
196  required,
197  audit_name,
198  abort_on_violation);
199  break;
200 
201  case RELKIND_SEQUENCE:
202  Assert((required & ~SEPG_DB_TABLE__SELECT) == 0);
203 
204  if (required & SEPG_DB_TABLE__SELECT)
205  result = sepgsql_avc_check_perms(&object,
208  audit_name,
209  abort_on_violation);
210  break;
211 
212  case RELKIND_VIEW:
213  result = sepgsql_avc_check_perms(&object,
216  audit_name,
217  abort_on_violation);
218  break;
219 
220  default:
221  /* nothing to be checked */
222  break;
223  }
224  pfree(audit_name);
225 
226  /*
227  * Only columns owned by relations shall be checked
228  */
229  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
230  return true;
231 
232  /*
233  * Check permissions on the columns
234  */
235  selected = fixup_whole_row_references(relOid, selected);
236  inserted = fixup_whole_row_references(relOid, inserted);
237  updated = fixup_whole_row_references(relOid, updated);
238  columns = bms_union(selected, bms_union(inserted, updated));
239 
240  while ((index = bms_first_member(columns)) >= 0)
241  {
242  AttrNumber attnum;
243  uint32 column_perms = 0;
244 
245  if (bms_is_member(index, selected))
246  column_perms |= SEPG_DB_COLUMN__SELECT;
247  if (bms_is_member(index, inserted))
248  {
249  if (required & SEPG_DB_TABLE__INSERT)
250  column_perms |= SEPG_DB_COLUMN__INSERT;
251  }
252  if (bms_is_member(index, updated))
253  {
254  if (required & SEPG_DB_TABLE__UPDATE)
255  column_perms |= SEPG_DB_COLUMN__UPDATE;
256  }
257  if (column_perms == 0)
258  continue;
259 
260  /* obtain column's permission */
261  attnum = index + FirstLowInvalidHeapAttributeNumber;
262 
263  object.classId = RelationRelationId;
264  object.objectId = relOid;
265  object.objectSubId = attnum;
266  audit_name = getObjectDescription(&object);
267 
268  result = sepgsql_avc_check_perms(&object,
270  column_perms,
271  audit_name,
272  abort_on_violation);
273  pfree(audit_name);
274 
275  if (!result)
276  return result;
277  }
278  return true;
279 }
#define SEPG_DB_VIEW__EXPAND
Definition: sepgsql.h:212
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:885
#define SEPG_CLASS_DB_COLUMN
Definition: sepgsql.h:49
static Bitmapset * fixup_whole_row_references(Oid relOid, Bitmapset *columns)
Definition: dml.c:39
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
#define RelationRelationId
Definition: pg_class.h:29
bool sepgsql_avc_check_perms(const ObjectAddress *tobject, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
Definition: uavc.c:428
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1750
#define SEPG_DB_TABLE__DELETE
Definition: sepgsql.h:146
int errcode(int sqlerrcode)
Definition: elog.c:575
bool sepgsql_getenforce(void)
Definition: selinux.c:648
#define SEPG_DB_COLUMN__INSERT
Definition: sepgsql.h:177
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
unsigned int Oid
Definition: postgres_ext.h:31
char * getObjectDescription(const ObjectAddress *object)
#define SEPG_DB_TABLE__SELECT
Definition: sepgsql.h:143
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:949
#define SEPG_CLASS_DB_SEQUENCE
Definition: sepgsql.h:47
#define ERROR
Definition: elog.h:43
#define SEPG_DB_COLUMN__SELECT
Definition: sepgsql.h:175
#define SEPG_DB_SEQUENCE__GET_VALUE
Definition: sepgsql.h:155
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:258
#define ereport(elevel, rest)
Definition: elog.h:122
#define SEPG_DB_COLUMN__UPDATE
Definition: sepgsql.h:176
#define SEPG_CLASS_DB_VIEW
Definition: sepgsql.h:53
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:163
#define SEPG_CLASS_DB_TABLE
Definition: sepgsql.h:46
#define Assert(condition)
Definition: c.h:681
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:218
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RELKIND_VIEW
Definition: pg_class.h:164
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21
static Bitmapset* fixup_inherited_columns ( Oid  parentId,
Oid  childId,
Bitmapset columns 
)
static

Definition at line 94 of file dml.c.

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

Referenced by sepgsql_dml_privileges().

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

Definition at line 39 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(), RELOID, SearchSysCache1(), and SearchSysCache2().

Referenced by check_relation_privileges().

40 {
41  Bitmapset *result;
42  HeapTuple tuple;
43  AttrNumber natts;
44  AttrNumber attno;
45  int index;
46 
47  /* if no whole of row references, do not anything */
49  if (!bms_is_member(index, columns))
50  return columns;
51 
52  /* obtain number of attributes */
53  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
54  if (!HeapTupleIsValid(tuple))
55  elog(ERROR, "cache lookup failed for relation %u", relOid);
56  natts = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
57  ReleaseSysCache(tuple);
58 
59  /* fix up the given columns */
60  result = bms_copy(columns);
61  result = bms_del_member(result, index);
62 
63  for (attno = 1; attno <= natts; attno++)
64  {
65  tuple = SearchSysCache2(ATTNUM,
66  ObjectIdGetDatum(relOid),
67  Int16GetDatum(attno));
68  if (!HeapTupleIsValid(tuple))
69  continue;
70 
71  if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
72  continue;
73 
74  index = attno - FirstLowInvalidHeapAttributeNumber;
75 
76  result = bms_add_member(result, index);
77 
78  ReleaseSysCache(tuple);
79  }
80  return result;
81 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
#define Int16GetDatum(X)
Definition: postgres.h:457
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: type.h:89
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1123
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define InvalidAttrNumber
Definition: attnum.h:23
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define elog
Definition: elog.h:219
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:735
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21
bool sepgsql_dml_privileges ( List rangeTabls,
bool  abort_on_violation 
)

Definition at line 287 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, 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().

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