PostgreSQL Source Code  git master
hooks.c File Reference
#include "postgres.h"
#include "catalog/dependency.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/seclabel.h"
#include "executor/executor.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "sepgsql.h"
#include "tcop/utility.h"
#include "utils/guc.h"
#include "utils/queryenvironment.h"
Include dependency graph for hooks.c:

Go to the source code of this file.

Data Structures

struct  sepgsql_context_info_t
 

Functions

bool sepgsql_get_permissive (void)
 
bool sepgsql_get_debug_audit (void)
 
static void sepgsql_object_access (ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg)
 
static bool sepgsql_exec_check_perms (List *rangeTbls, List *rteperminfos, bool abort)
 
static void sepgsql_utility_command (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
 
void _PG_init (void)
 

Variables

 PG_MODULE_MAGIC
 
static object_access_hook_type next_object_access_hook = NULL
 
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL
 
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL
 
static sepgsql_context_info_t sepgsql_context_info
 
static bool sepgsql_permissive = false
 
static bool sepgsql_debug_audit = false
 

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 400 of file hooks.c.

401 {
402  /*
403  * We allow to load the SE-PostgreSQL module on single-user-mode or
404  * shared_preload_libraries settings only.
405  */
406  if (IsUnderPostmaster)
407  ereport(ERROR,
408  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
409  errmsg("sepgsql must be loaded via shared_preload_libraries")));
410 
411  /*
412  * Check availability of SELinux on the platform. If disabled, we cannot
413  * activate any SE-PostgreSQL features, and we have to skip rest of
414  * initialization.
415  */
416  if (is_selinux_enabled() < 1)
417  {
419  return;
420  }
421 
422  /*
423  * sepgsql.permissive = (on|off)
424  *
425  * This variable controls performing mode of SE-PostgreSQL on user's
426  * session.
427  */
428  DefineCustomBoolVariable("sepgsql.permissive",
429  "Turn on/off permissive mode in SE-PostgreSQL",
430  NULL,
432  false,
433  PGC_SIGHUP,
435  NULL,
436  NULL,
437  NULL);
438 
439  /*
440  * sepgsql.debug_audit = (on|off)
441  *
442  * This variable allows users to turn on/off audit logs on access control
443  * decisions, independent from auditallow/auditdeny setting in the
444  * security policy. We intend to use this option for debugging purpose.
445  */
446  DefineCustomBoolVariable("sepgsql.debug_audit",
447  "Turn on/off debug audit messages",
448  NULL,
450  false,
451  PGC_USERSET,
453  NULL,
454  NULL,
455  NULL);
456 
457  MarkGUCPrefixReserved("sepgsql");
458 
459  /* Initialize userspace access vector cache */
461 
462  /* Initialize security label of the client and related stuff */
464 
465  /* Security label provider hook */
468 
469  /* Object access hook */
472 
473  /* DML permission check */
476 
477  /* ProcessUtility hook */
480 
481  /* init contextual info */
482  memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
483 }
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook
Definition: execMain.c:71
bool IsUnderPostmaster
Definition: globals.c:117
void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5075
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5222
@ PGC_USERSET
Definition: guc.h:75
@ PGC_SIGHUP
Definition: guc.h:71
#define GUC_NOT_IN_SAMPLE
Definition: guc.h:217
static sepgsql_context_info_t sepgsql_context_info
Definition: hooks.c:55
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook
Definition: hooks.c:38
static ProcessUtility_hook_type next_ProcessUtility_hook
Definition: hooks.c:39
static void sepgsql_object_access(ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg)
Definition: hooks.c:86
static bool sepgsql_debug_audit
Definition: hooks.c:71
static bool sepgsql_permissive
Definition: hooks.c:60
static bool sepgsql_exec_check_perms(List *rangeTbls, List *rteperminfos, bool abort)
Definition: hooks.c:290
static object_access_hook_type next_object_access_hook
Definition: hooks.c:37
static void sepgsql_utility_command(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: hooks.c:313
void sepgsql_init_client_label(void)
Definition: label.c:404
void sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
Definition: label.c:482
object_access_hook_type object_access_hook
Definition: objectaccess.c:22
void register_label_provider(const char *provider_name, check_object_relabel_type hook)
Definition: seclabel.c:570
int sepgsql_set_mode(int new_mode)
Definition: selinux.c:634
#define SEPGSQL_LABEL_TAG
Definition: sepgsql.h:23
#define SEPGSQL_MODE_DISABLED
Definition: sepgsql.h:31
void sepgsql_avc_init(void)
Definition: uavc.c:488
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:70

References DefineCustomBoolVariable(), ereport, errcode(), errmsg(), ERROR, ExecutorCheckPerms_hook, GUC_NOT_IN_SAMPLE, IsUnderPostmaster, MarkGUCPrefixReserved(), next_exec_check_perms_hook, next_object_access_hook, next_ProcessUtility_hook, object_access_hook, PGC_SIGHUP, PGC_USERSET, ProcessUtility_hook, register_label_provider(), sepgsql_avc_init(), sepgsql_context_info, sepgsql_debug_audit, sepgsql_exec_check_perms(), sepgsql_init_client_label(), SEPGSQL_LABEL_TAG, SEPGSQL_MODE_DISABLED, sepgsql_object_access(), sepgsql_object_relabel(), sepgsql_permissive, sepgsql_set_mode(), and sepgsql_utility_command().

◆ sepgsql_exec_check_perms()

static bool sepgsql_exec_check_perms ( List rangeTbls,
List rteperminfos,
bool  abort 
)
static

Definition at line 290 of file hooks.c.

291 {
292  /*
293  * If security provider is stacking and one of them replied 'false' at
294  * least, we don't need to check any more.
295  */
297  !(*next_exec_check_perms_hook) (rangeTbls, rteperminfos, abort))
298  return false;
299 
300  if (!sepgsql_dml_privileges(rangeTbls, rteperminfos, abort))
301  return false;
302 
303  return true;
304 }
bool sepgsql_dml_privileges(List *rangeTbls, List *rteperminfos, bool abort_on_violation)
Definition: dml.c:282

References next_exec_check_perms_hook, and sepgsql_dml_privileges().

Referenced by _PG_init().

◆ sepgsql_get_debug_audit()

bool sepgsql_get_debug_audit ( void  )

Definition at line 74 of file hooks.c.

75 {
76  return sepgsql_debug_audit;
77 }

References sepgsql_debug_audit.

Referenced by sepgsql_avc_check_perms_label().

◆ sepgsql_get_permissive()

bool sepgsql_get_permissive ( void  )

Definition at line 63 of file hooks.c.

64 {
65  return sepgsql_permissive;
66 }

References sepgsql_permissive.

Referenced by sepgsql_client_auth().

◆ sepgsql_object_access()

static void sepgsql_object_access ( ObjectAccessType  access,
Oid  classId,
Oid  objectId,
int  subId,
void *  arg 
)
static

Definition at line 86 of file hooks.c.

91 {
93  (*next_object_access_hook) (access, classId, objectId, subId, arg);
94 
95  switch (access)
96  {
97  case OAT_POST_CREATE:
98  {
99  ObjectAccessPostCreate *pc_arg = arg;
100  bool is_internal;
101 
102  is_internal = pc_arg ? pc_arg->is_internal : false;
103 
104  switch (classId)
105  {
106  case DatabaseRelationId:
107  Assert(!is_internal);
110  break;
111 
112  case NamespaceRelationId:
113  Assert(!is_internal);
114  sepgsql_schema_post_create(objectId);
115  break;
116 
117  case RelationRelationId:
118  if (subId == 0)
119  {
120  /*
121  * The cases in which we want to apply permission
122  * checks on creation of a new relation correspond
123  * to direct user invocation. For internal uses,
124  * that is creation of toast tables, index rebuild
125  * or ALTER TABLE commands, we need neither
126  * assignment of security labels nor permission
127  * checks.
128  */
129  if (is_internal)
130  break;
131 
133  }
134  else
135  sepgsql_attribute_post_create(objectId, subId);
136  break;
137 
138  case ProcedureRelationId:
139  Assert(!is_internal);
140  sepgsql_proc_post_create(objectId);
141  break;
142 
143  default:
144  /* Ignore unsupported object classes */
145  break;
146  }
147  }
148  break;
149 
150  case OAT_DROP:
151  {
152  ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
153 
154  /*
155  * No need to apply permission checks on object deletion due
156  * to internal cleanups; such as removal of temporary database
157  * object on session closed.
158  */
159  if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
160  break;
161 
162  switch (classId)
163  {
164  case DatabaseRelationId:
165  sepgsql_database_drop(objectId);
166  break;
167 
168  case NamespaceRelationId:
169  sepgsql_schema_drop(objectId);
170  break;
171 
172  case RelationRelationId:
173  if (subId == 0)
174  sepgsql_relation_drop(objectId);
175  else
176  sepgsql_attribute_drop(objectId, subId);
177  break;
178 
179  case ProcedureRelationId:
180  sepgsql_proc_drop(objectId);
181  break;
182 
183  default:
184  /* Ignore unsupported object classes */
185  break;
186  }
187  }
188  break;
189 
190  case OAT_TRUNCATE:
191  {
192  switch (classId)
193  {
194  case RelationRelationId:
195  sepgsql_relation_truncate(objectId);
196  break;
197  default:
198  /* Ignore unsupported object classes */
199  break;
200  }
201  }
202  break;
203 
204  case OAT_POST_ALTER:
205  {
206  ObjectAccessPostAlter *pa_arg = arg;
207  bool is_internal = pa_arg->is_internal;
208 
209  switch (classId)
210  {
211  case DatabaseRelationId:
212  Assert(!is_internal);
213  sepgsql_database_setattr(objectId);
214  break;
215 
216  case NamespaceRelationId:
217  Assert(!is_internal);
218  sepgsql_schema_setattr(objectId);
219  break;
220 
221  case RelationRelationId:
222  if (subId == 0)
223  {
224  /*
225  * A case when we don't want to apply permission
226  * check is that relation is internally altered
227  * without user's intention. E.g, no need to check
228  * on toast table/index to be renamed at end of
229  * the table rewrites.
230  */
231  if (is_internal)
232  break;
233 
234  sepgsql_relation_setattr(objectId);
235  }
236  else
237  sepgsql_attribute_setattr(objectId, subId);
238  break;
239 
240  case ProcedureRelationId:
241  Assert(!is_internal);
242  sepgsql_proc_setattr(objectId);
243  break;
244 
245  default:
246  /* Ignore unsupported object classes */
247  break;
248  }
249  }
250  break;
251 
253  {
255 
256  /*
257  * If stacked extension already decided not to allow users to
258  * search this schema, we just stick with that decision.
259  */
260  if (!ns_arg->result)
261  break;
262 
263  Assert(classId == NamespaceRelationId);
264  Assert(ns_arg->result);
265  ns_arg->result
266  = sepgsql_schema_search(objectId,
267  ns_arg->ereport_on_violation);
268  }
269  break;
270 
272  {
273  Assert(classId == ProcedureRelationId);
274  sepgsql_proc_execute(objectId);
275  }
276  break;
277 
278  default:
279  elog(ERROR, "unexpected object access type: %d", (int) access);
280  break;
281  }
282 }
#define Assert(condition)
Definition: c.h:858
void sepgsql_proc_post_create(Oid functionId)
Definition: proc.c:37
void sepgsql_proc_setattr(Oid functionId)
Definition: proc.c:235
void sepgsql_proc_drop(Oid functionId)
Definition: proc.c:155
void sepgsql_proc_execute(Oid functionId)
Definition: proc.c:315
void sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
Definition: relation.c:209
void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
Definition: relation.c:43
void sepgsql_relation_post_create(Oid relOid)
Definition: relation.c:240
void sepgsql_relation_truncate(Oid relOid)
Definition: relation.c:524
void sepgsql_relation_setattr(Oid relOid)
Definition: relation.c:615
void sepgsql_relation_drop(Oid relOid)
Definition: relation.c:416
void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
Definition: relation.c:133
void sepgsql_database_post_create(Oid databaseId, const char *dtemplate)
Definition: database.c:33
void sepgsql_database_drop(Oid databaseId)
Definition: database.c:133
void sepgsql_database_setattr(Oid databaseId)
Definition: database.c:160
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:85
#define elog(elevel,...)
Definition: elog.h:224
@ OAT_NAMESPACE_SEARCH
Definition: objectaccess.h:53
@ OAT_FUNCTION_EXECUTE
Definition: objectaccess.h:54
@ OAT_DROP
Definition: objectaccess.h:51
@ OAT_TRUNCATE
Definition: objectaccess.h:55
@ OAT_POST_ALTER
Definition: objectaccess.h:52
@ OAT_POST_CREATE
Definition: objectaccess.h:50
void * arg
short access
Definition: preproc-type.c:36
void sepgsql_schema_post_create(Oid namespaceId)
Definition: schema.c:36
void sepgsql_schema_setattr(Oid namespaceId)
Definition: schema.c:202
bool sepgsql_schema_search(Oid namespaceId, bool abort_on_violation)
Definition: schema.c:209
void sepgsql_schema_drop(Oid namespaceId)
Definition: schema.c:114
const char * createdb_dtemplate
Definition: hooks.c:52

References arg, Assert, sepgsql_context_info_t::createdb_dtemplate, ObjectAccessDrop::dropflags, elog, ObjectAccessNamespaceSearch::ereport_on_violation, ERROR, ObjectAccessPostCreate::is_internal, ObjectAccessPostAlter::is_internal, next_object_access_hook, OAT_DROP, OAT_FUNCTION_EXECUTE, OAT_NAMESPACE_SEARCH, OAT_POST_ALTER, OAT_POST_CREATE, OAT_TRUNCATE, PERFORM_DELETION_INTERNAL, ObjectAccessNamespaceSearch::result, sepgsql_attribute_drop(), sepgsql_attribute_post_create(), sepgsql_attribute_setattr(), sepgsql_context_info, sepgsql_database_drop(), sepgsql_database_post_create(), sepgsql_database_setattr(), sepgsql_proc_drop(), sepgsql_proc_execute(), sepgsql_proc_post_create(), sepgsql_proc_setattr(), sepgsql_relation_drop(), sepgsql_relation_post_create(), sepgsql_relation_setattr(), sepgsql_relation_truncate(), sepgsql_schema_drop(), sepgsql_schema_post_create(), sepgsql_schema_search(), and sepgsql_schema_setattr().

Referenced by _PG_init().

◆ sepgsql_utility_command()

static void sepgsql_utility_command ( PlannedStmt pstmt,
const char *  queryString,
bool  readOnlyTree,
ProcessUtilityContext  context,
ParamListInfo  params,
QueryEnvironment queryEnv,
DestReceiver dest,
QueryCompletion qc 
)
static

Definition at line 313 of file hooks.c.

321 {
322  Node *parsetree = pstmt->utilityStmt;
323  sepgsql_context_info_t saved_context_info = sepgsql_context_info;
324  ListCell *cell;
325 
326  PG_TRY();
327  {
328  /*
329  * Check command tag to avoid nefarious operations, and save the
330  * current contextual information to determine whether we should apply
331  * permission checks here, or not.
332  */
333  sepgsql_context_info.cmdtype = nodeTag(parsetree);
334 
335  switch (nodeTag(parsetree))
336  {
337  case T_CreatedbStmt:
338 
339  /*
340  * We hope to reference name of the source database, but it
341  * does not appear in system catalog. So, we save it here.
342  */
343  foreach(cell, ((CreatedbStmt *) parsetree)->options)
344  {
345  DefElem *defel = (DefElem *) lfirst(cell);
346 
347  if (strcmp(defel->defname, "template") == 0)
348  {
350  = strVal(defel->arg);
351  break;
352  }
353  }
354  break;
355 
356  case T_LoadStmt:
357 
358  /*
359  * We reject LOAD command across the board on enforcing mode,
360  * because a binary module can arbitrarily override hooks.
361  */
362  if (sepgsql_getenforce())
363  {
364  ereport(ERROR,
365  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
366  errmsg("SELinux: LOAD is not permitted")));
367  }
368  break;
369  default:
370 
371  /*
372  * Right now we don't check any other utility commands,
373  * because it needs more detailed information to make access
374  * control decision here, but we don't want to have two parse
375  * and analyze routines individually.
376  */
377  break;
378  }
379 
381  (*next_ProcessUtility_hook) (pstmt, queryString, readOnlyTree,
382  context, params, queryEnv,
383  dest, qc);
384  else
385  standard_ProcessUtility(pstmt, queryString, readOnlyTree,
386  context, params, queryEnv,
387  dest, qc);
388  }
389  PG_FINALLY();
390  {
391  sepgsql_context_info = saved_context_info;
392  }
393  PG_END_TRY();
394 }
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define lfirst(lc)
Definition: pg_list.h:172
tree context
Definition: radixtree.h:1829
bool sepgsql_getenforce(void)
Definition: selinux.c:651
char * defname
Definition: parsenodes.h:815
Node * arg
Definition: parsenodes.h:816
Definition: nodes.h:129
Node * utilityStmt
Definition: plannodes.h:95
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:540
#define strVal(v)
Definition: value.h:82

References DefElem::arg, sepgsql_context_info_t::cmdtype, context, sepgsql_context_info_t::createdb_dtemplate, DefElem::defname, generate_unaccent_rules::dest, ereport, errcode(), errmsg(), ERROR, lfirst, next_ProcessUtility_hook, nodeTag, PG_END_TRY, PG_FINALLY, PG_TRY, sepgsql_context_info, sepgsql_getenforce(), standard_ProcessUtility(), strVal, and PlannedStmt::utilityStmt.

Referenced by _PG_init().

Variable Documentation

◆ next_exec_check_perms_hook

ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL
static

Definition at line 38 of file hooks.c.

Referenced by _PG_init(), and sepgsql_exec_check_perms().

◆ next_object_access_hook

object_access_hook_type next_object_access_hook = NULL
static

Definition at line 37 of file hooks.c.

Referenced by _PG_init(), and sepgsql_object_access().

◆ next_ProcessUtility_hook

ProcessUtility_hook_type next_ProcessUtility_hook = NULL
static

Definition at line 39 of file hooks.c.

Referenced by _PG_init(), and sepgsql_utility_command().

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 28 of file hooks.c.

◆ sepgsql_context_info

sepgsql_context_info_t sepgsql_context_info
static

Definition at line 55 of file hooks.c.

Referenced by _PG_init(), sepgsql_object_access(), and sepgsql_utility_command().

◆ sepgsql_debug_audit

bool sepgsql_debug_audit = false
static

Definition at line 71 of file hooks.c.

Referenced by _PG_init(), and sepgsql_get_debug_audit().

◆ sepgsql_permissive

bool sepgsql_permissive = false
static

Definition at line 60 of file hooks.c.

Referenced by _PG_init(), and sepgsql_get_permissive().