PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
label.c
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  *
3  * contrib/sepgsql/label.c
4  *
5  * Routines to support SELinux labels (security context)
6  *
7  * Copyright (c) 2010-2017, PostgreSQL Global Development Group
8  *
9  * -------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12 
13 #include <selinux/label.h>
14 
15 /*
16  * <selinux/label.h> includes <stdbool.h>, which creates an incompatible
17  * #define for bool. Get rid of that so we can use our own typedef.
18  * (We don't care if <stdbool.h> redefines "true"/"false"; those are close
19  * enough.)
20  */
21 #undef bool
22 
23 #include "access/heapam.h"
24 #include "access/htup_details.h"
25 #include "access/genam.h"
26 #include "access/xact.h"
27 #include "catalog/catalog.h"
28 #include "catalog/dependency.h"
29 #include "catalog/indexing.h"
30 #include "catalog/pg_attribute.h"
31 #include "catalog/pg_class.h"
32 #include "catalog/pg_database.h"
33 #include "catalog/pg_namespace.h"
34 #include "catalog/pg_proc.h"
35 #include "commands/dbcommands.h"
36 #include "commands/seclabel.h"
37 #include "libpq/auth.h"
38 #include "libpq/libpq-be.h"
39 #include "miscadmin.h"
40 #include "utils/builtins.h"
41 #include "utils/fmgroids.h"
42 #include "utils/guc.h"
43 #include "utils/lsyscache.h"
44 #include "utils/memutils.h"
45 #include "utils/rel.h"
46 #include "utils/tqual.h"
47 
48 #include "sepgsql.h"
49 
50 /*
51  * Saved hook entries (if stacked)
52  */
56 
57 /*
58  * client_label_*
59  *
60  * security label of the database client. Initially the client security label
61  * is equal to client_label_peer, and can be changed by one or more calls to
62  * sepgsql_setcon(), and also be temporarily overridden during execution of a
63  * trusted-procedure.
64  *
65  * sepgsql_setcon() is a transaction-aware operation; a (sub-)transaction
66  * rollback should also rollback the current client security label. Therefore
67  * we use the list client_label_pending of pending_label to keep track of which
68  * labels were set during the (sub-)transactions.
69  */
70 static char *client_label_peer = NULL; /* set by getpeercon(3) */
71 static List *client_label_pending = NIL; /* pending list being set by
72  * sepgsql_setcon() */
73 static char *client_label_committed = NULL; /* set by sepgsql_setcon(), and
74  * already committed */
75 static char *client_label_func = NULL; /* set by trusted procedure */
76 
77 typedef struct
78 {
80  char *label;
82 
83 /*
84  * sepgsql_get_client_label
85  *
86  * Returns the current security label of the client. All code should use this
87  * routine to get the current label, instead of referring to the client_label_*
88  * variables above.
89  */
90 char *
92 {
93  /* trusted procedure client label override */
95  return client_label_func;
96 
97  /* uncommitted sepgsql_setcon() value */
98  if (client_label_pending)
99  {
100  pending_label *plabel = llast(client_label_pending);
101 
102  if (plabel->label)
103  return plabel->label;
104  }
105  else if (client_label_committed)
106  return client_label_committed; /* set by sepgsql_setcon() committed */
107 
108  /* default label */
110  return client_label_peer;
111 }
112 
113 /*
114  * sepgsql_set_client_label
115  *
116  * This routine tries to switch the current security label of the client, and
117  * checks related permissions. The supplied new label shall be added to the
118  * client_label_pending list, then saved at transaction-commit time to ensure
119  * transaction-awareness.
120  */
121 static void
122 sepgsql_set_client_label(const char *new_label)
123 {
124  const char *tcontext;
125  MemoryContext oldcxt;
126  pending_label *plabel;
127 
128  /* Reset to the initial client label, if NULL */
129  if (!new_label)
130  tcontext = client_label_peer;
131  else
132  {
133  if (security_check_context_raw((security_context_t) new_label) < 0)
134  ereport(ERROR,
135  (errcode(ERRCODE_INVALID_NAME),
136  errmsg("SELinux: invalid security label: \"%s\"",
137  new_label)));
138  tcontext = new_label;
139  }
140 
141  /* Check process:{setcurrent} permission. */
145  NULL,
146  true);
147  /* Check process:{dyntransition} permission. */
151  NULL,
152  true);
153 
154  /*
155  * Append the supplied new_label on the pending list until the current
156  * transaction is committed.
157  */
159 
160  plabel = palloc0(sizeof(pending_label));
161  plabel->subid = GetCurrentSubTransactionId();
162  if (new_label)
163  plabel->label = pstrdup(new_label);
164  client_label_pending = lappend(client_label_pending, plabel);
165 
166  MemoryContextSwitchTo(oldcxt);
167 }
168 
169 /*
170  * sepgsql_xact_callback
171  *
172  * A callback routine of transaction commit/abort/prepare. Commit or abort
173  * changes in the client_label_pending list.
174  */
175 static void
177 {
178  if (event == XACT_EVENT_COMMIT)
179  {
180  if (client_label_pending != NIL)
181  {
182  pending_label *plabel = llast(client_label_pending);
183  char *new_label;
184 
185  if (plabel->label)
187  plabel->label);
188  else
189  new_label = NULL;
190 
193 
194  client_label_committed = new_label;
195 
196  /*
197  * XXX - Note that items of client_label_pending are allocated on
198  * CurTransactionContext, thus, all acquired memory region shall
199  * be released implicitly.
200  */
201  client_label_pending = NIL;
202  }
203  }
204  else if (event == XACT_EVENT_ABORT)
205  client_label_pending = NIL;
206 }
207 
208 /*
209  * sepgsql_subxact_callback
210  *
211  * A callback routine of sub-transaction start/abort/commit. Releases all
212  * security labels that are set within the sub-transaction that is aborted.
213  */
214 static void
216  SubTransactionId parentSubid, void *arg)
217 {
218  ListCell *cell;
219  ListCell *prev;
220  ListCell *next;
221 
222  if (event == SUBXACT_EVENT_ABORT_SUB)
223  {
224  prev = NULL;
225  for (cell = list_head(client_label_pending); cell; cell = next)
226  {
227  pending_label *plabel = lfirst(cell);
228 
229  next = lnext(cell);
230 
231  if (plabel->subid == mySubid)
232  client_label_pending
233  = list_delete_cell(client_label_pending, cell, prev);
234  else
235  prev = cell;
236  }
237  }
238 }
239 
240 /*
241  * sepgsql_client_auth
242  *
243  * Entrypoint of the client authentication hook.
244  * It switches the client label according to getpeercon(), and the current
245  * performing mode according to the GUC setting.
246  */
247 static void
249 {
251  (*next_client_auth_hook) (port, status);
252 
253  /*
254  * In the case when authentication failed, the supplied socket shall be
255  * closed soon, so we don't need to do anything here.
256  */
257  if (status != STATUS_OK)
258  return;
259 
260  /*
261  * Getting security label of the peer process using API of libselinux.
262  */
263  if (getpeercon_raw(port->sock, &client_label_peer) < 0)
264  ereport(FATAL,
265  (errcode(ERRCODE_INTERNAL_ERROR),
266  errmsg("SELinux: unable to get peer label: %m")));
267 
268  /*
269  * Switch the current performing mode from INTERNAL to either DEFAULT or
270  * PERMISSIVE.
271  */
274  else
276 }
277 
278 /*
279  * sepgsql_needs_fmgr_hook
280  *
281  * It informs the core whether the supplied function is trusted procedure,
282  * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and
283  * abort time of function invocation.
284  */
285 static bool
287 {
288  ObjectAddress object;
289 
290  if (next_needs_fmgr_hook &&
291  (*next_needs_fmgr_hook) (functionId))
292  return true;
293 
294  /*
295  * SELinux needs the function to be called via security_definer wrapper,
296  * if this invocation will take a domain-transition. We call these
297  * functions as trusted-procedure, if the security policy has a rule that
298  * switches security label of the client on execution.
299  */
300  if (sepgsql_avc_trusted_proc(functionId) != NULL)
301  return true;
302 
303  /*
304  * Even if not a trusted-procedure, this function should not be inlined
305  * unless the client has db_procedure:{execute} permission. Please note
306  * that it shall be actually failed later because of same reason with
307  * ACL_EXECUTE.
308  */
309  object.classId = ProcedureRelationId;
310  object.objectId = functionId;
311  object.objectSubId = 0;
312  if (!sepgsql_avc_check_perms(&object,
316  SEPGSQL_AVC_NOAUDIT, false))
317  return true;
318 
319  return false;
320 }
321 
322 /*
323  * sepgsql_fmgr_hook
324  *
325  * It switches security label of the client on execution of trusted
326  * procedures.
327  */
328 static void
330  FmgrInfo *flinfo, Datum *private)
331 {
332  struct
333  {
334  char *old_label;
335  char *new_label;
336  Datum next_private;
337  } *stack;
338 
339  switch (event)
340  {
341  case FHET_START:
342  stack = (void *) DatumGetPointer(*private);
343  if (!stack)
344  {
345  MemoryContext oldcxt;
346 
347  oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
348  stack = palloc(sizeof(*stack));
349  stack->old_label = NULL;
350  stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
351  stack->next_private = 0;
352 
353  MemoryContextSwitchTo(oldcxt);
354 
355  /*
356  * process:transition permission between old and new label,
357  * when user tries to switch security label of the client on
358  * execution of trusted procedure.
359  *
360  * Also, db_procedure:entrypoint permission should be checked
361  * whether this procedure can perform as an entrypoint of the
362  * trusted procedure, or not. Note that db_procedure:execute
363  * permission shall be checked individually.
364  */
365  if (stack->new_label)
366  {
367  ObjectAddress object;
368 
369  object.classId = ProcedureRelationId;
370  object.objectId = flinfo->fn_oid;
371  object.objectSubId = 0;
372  sepgsql_avc_check_perms(&object,
375  getObjectDescription(&object),
376  true);
377 
378  sepgsql_avc_check_perms_label(stack->new_label,
381  NULL, true);
382  }
383  *private = PointerGetDatum(stack);
384  }
385  Assert(!stack->old_label);
386  if (stack->new_label)
387  {
388  stack->old_label = client_label_func;
389  client_label_func = stack->new_label;
390  }
391  if (next_fmgr_hook)
392  (*next_fmgr_hook) (event, flinfo, &stack->next_private);
393  break;
394 
395  case FHET_END:
396  case FHET_ABORT:
397  stack = (void *) DatumGetPointer(*private);
398 
399  if (next_fmgr_hook)
400  (*next_fmgr_hook) (event, flinfo, &stack->next_private);
401 
402  if (stack->new_label)
403  {
404  client_label_func = stack->old_label;
405  stack->old_label = NULL;
406  }
407  break;
408 
409  default:
410  elog(ERROR, "unexpected event type: %d", (int) event);
411  break;
412  }
413 }
414 
415 /*
416  * sepgsql_init_client_label
417  *
418  * Initializes the client security label and sets up related hooks for client
419  * label management.
420  */
421 void
423 {
424  /*
425  * Set up dummy client label.
426  *
427  * XXX - note that PostgreSQL launches background worker process like
428  * autovacuum without authentication steps. So, we initialize sepgsql_mode
429  * with SEPGSQL_MODE_INTERNAL, and client_label with the security context
430  * of server process. Later, it also launches background of user session.
431  * In this case, the process is always hooked on post-authentication, and
432  * we can initialize the sepgsql_mode and client_label correctly.
433  */
434  if (getcon_raw(&client_label_peer) < 0)
435  ereport(ERROR,
436  (errcode(ERRCODE_INTERNAL_ERROR),
437  errmsg("SELinux: failed to get server security label: %m")));
438 
439  /* Client authentication hook */
442 
443  /* Trusted procedure hooks */
446 
449 
450  /* Transaction/Sub-transaction callbacks */
453 }
454 
455 /*
456  * sepgsql_get_label
457  *
458  * It returns a security context of the specified database object.
459  * If unlabeled or incorrectly labeled, the system "unlabeled" label
460  * shall be returned.
461  */
462 char *
463 sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
464 {
465  ObjectAddress object;
466  char *label;
467 
468  object.classId = classId;
469  object.objectId = objectId;
470  object.objectSubId = subId;
471 
472  label = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
473  if (!label || security_check_context_raw((security_context_t) label))
474  {
475  security_context_t unlabeled;
476 
477  if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
478  ereport(ERROR,
479  (errcode(ERRCODE_INTERNAL_ERROR),
480  errmsg("SELinux: failed to get initial security label: %m")));
481  PG_TRY();
482  {
483  label = pstrdup(unlabeled);
484  }
485  PG_CATCH();
486  {
487  freecon(unlabeled);
488  PG_RE_THROW();
489  }
490  PG_END_TRY();
491 
492  freecon(unlabeled);
493  }
494  return label;
495 }
496 
497 /*
498  * sepgsql_object_relabel
499  *
500  * An entrypoint of SECURITY LABEL statement
501  */
502 void
503 sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
504 {
505  /*
506  * validate format of the supplied security label, if it is security
507  * context of selinux.
508  */
509  if (seclabel &&
510  security_check_context_raw((security_context_t) seclabel) < 0)
511  ereport(ERROR,
512  (errcode(ERRCODE_INVALID_NAME),
513  errmsg("SELinux: invalid security label: \"%s\"", seclabel)));
514 
515  /*
516  * Do actual permission checks for each object classes
517  */
518  switch (object->classId)
519  {
520  case DatabaseRelationId:
521  sepgsql_database_relabel(object->objectId, seclabel);
522  break;
523 
524  case NamespaceRelationId:
525  sepgsql_schema_relabel(object->objectId, seclabel);
526  break;
527 
528  case RelationRelationId:
529  if (object->objectSubId == 0)
531  seclabel);
532  else
534  object->objectSubId,
535  seclabel);
536  break;
537 
538  case ProcedureRelationId:
539  sepgsql_proc_relabel(object->objectId, seclabel);
540  break;
541 
542  default:
543  ereport(ERROR,
544  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
545  errmsg("sepgsql provider does not support labels on %s",
546  getObjectTypeDescription(object))));
547  break;
548  }
549 }
550 
551 /*
552  * TEXT sepgsql_getcon(VOID)
553  *
554  * It returns the security label of the client.
555  */
557 Datum
559 {
560  char *client_label;
561 
562  if (!sepgsql_is_enabled())
563  PG_RETURN_NULL();
564 
565  client_label = sepgsql_get_client_label();
566 
567  PG_RETURN_TEXT_P(cstring_to_text(client_label));
568 }
569 
570 /*
571  * BOOL sepgsql_setcon(TEXT)
572  *
573  * It switches the security label of the client.
574  */
576 Datum
578 {
579  const char *new_label;
580 
581  if (PG_ARGISNULL(0))
582  new_label = NULL;
583  else
584  new_label = TextDatumGetCString(PG_GETARG_DATUM(0));
585 
586  sepgsql_set_client_label(new_label);
587 
588  PG_RETURN_BOOL(true);
589 }
590 
591 /*
592  * TEXT sepgsql_mcstrans_in(TEXT)
593  *
594  * It translate the given qualified MLS/MCS range into raw format
595  * when mcstrans daemon is working.
596  */
598 Datum
600 {
602  char *raw_label;
603  char *result;
604 
605  if (!sepgsql_is_enabled())
606  ereport(ERROR,
607  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
608  errmsg("sepgsql is not enabled")));
609 
610  if (selinux_trans_to_raw_context(text_to_cstring(label),
611  &raw_label) < 0)
612  ereport(ERROR,
613  (errcode(ERRCODE_INTERNAL_ERROR),
614  errmsg("SELinux: could not translate security label: %m")));
615 
616  PG_TRY();
617  {
618  result = pstrdup(raw_label);
619  }
620  PG_CATCH();
621  {
622  freecon(raw_label);
623  PG_RE_THROW();
624  }
625  PG_END_TRY();
626  freecon(raw_label);
627 
629 }
630 
631 /*
632  * TEXT sepgsql_mcstrans_out(TEXT)
633  *
634  * It translate the given raw MLS/MCS range into qualified format
635  * when mcstrans daemon is working.
636  */
638 Datum
640 {
642  char *qual_label;
643  char *result;
644 
645  if (!sepgsql_is_enabled())
646  ereport(ERROR,
647  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
648  errmsg("sepgsql is not currently enabled")));
649 
650  if (selinux_raw_to_trans_context(text_to_cstring(label),
651  &qual_label) < 0)
652  ereport(ERROR,
653  (errcode(ERRCODE_INTERNAL_ERROR),
654  errmsg("SELinux: could not translate security label: %m")));
655 
656  PG_TRY();
657  {
658  result = pstrdup(qual_label);
659  }
660  PG_CATCH();
661  {
662  freecon(qual_label);
663  PG_RE_THROW();
664  }
665  PG_END_TRY();
666  freecon(qual_label);
667 
669 }
670 
671 /*
672  * quote_object_names
673  *
674  * It tries to quote the supplied identifiers
675  */
676 static char *
677 quote_object_name(const char *src1, const char *src2,
678  const char *src3, const char *src4)
679 {
681  const char *temp;
682 
683  initStringInfo(&result);
684 
685  if (src1)
686  {
687  temp = quote_identifier(src1);
688  appendStringInfo(&result, "%s", temp);
689  if (src1 != temp)
690  pfree((void *) temp);
691  }
692  if (src2)
693  {
694  temp = quote_identifier(src2);
695  appendStringInfo(&result, ".%s", temp);
696  if (src2 != temp)
697  pfree((void *) temp);
698  }
699  if (src3)
700  {
701  temp = quote_identifier(src3);
702  appendStringInfo(&result, ".%s", temp);
703  if (src3 != temp)
704  pfree((void *) temp);
705  }
706  if (src4)
707  {
708  temp = quote_identifier(src4);
709  appendStringInfo(&result, ".%s", temp);
710  if (src4 != temp)
711  pfree((void *) temp);
712  }
713  return result.data;
714 }
715 
716 /*
717  * exec_object_restorecon
718  *
719  * This routine is a helper called by sepgsql_restorecon; it set up
720  * initial security labels of database objects within the supplied
721  * catalog OID.
722  */
723 static void
724 exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
725 {
726  Relation rel;
727  SysScanDesc sscan;
728  HeapTuple tuple;
729  char *database_name = get_database_name(MyDatabaseId);
730  char *namespace_name;
731  Oid namespace_id;
732  char *relation_name;
733 
734  /*
735  * Open the target catalog. We don't want to allow writable accesses by
736  * other session during initial labeling.
737  */
738  rel = heap_open(catalogId, AccessShareLock);
739 
740  sscan = systable_beginscan(rel, InvalidOid, false,
741  NULL, 0, NULL);
742  while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
743  {
744  Form_pg_database datForm;
745  Form_pg_namespace nspForm;
746  Form_pg_class relForm;
747  Form_pg_attribute attForm;
748  Form_pg_proc proForm;
749  char *objname;
750  int objtype = 1234;
751  ObjectAddress object;
752  security_context_t context;
753 
754  /*
755  * The way to determine object name depends on object classes. So, any
756  * branches set up `objtype', `objname' and `object' here.
757  */
758  switch (catalogId)
759  {
760  case DatabaseRelationId:
761  datForm = (Form_pg_database) GETSTRUCT(tuple);
762 
763  objtype = SELABEL_DB_DATABASE;
764 
765  objname = quote_object_name(NameStr(datForm->datname),
766  NULL, NULL, NULL);
767 
768  object.classId = DatabaseRelationId;
769  object.objectId = HeapTupleGetOid(tuple);
770  object.objectSubId = 0;
771  break;
772 
773  case NamespaceRelationId:
774  nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
775 
776  objtype = SELABEL_DB_SCHEMA;
777 
778  objname = quote_object_name(database_name,
779  NameStr(nspForm->nspname),
780  NULL, NULL);
781 
782  object.classId = NamespaceRelationId;
783  object.objectId = HeapTupleGetOid(tuple);
784  object.objectSubId = 0;
785  break;
786 
787  case RelationRelationId:
788  relForm = (Form_pg_class) GETSTRUCT(tuple);
789 
790  if (relForm->relkind == RELKIND_RELATION ||
791  relForm->relkind == RELKIND_PARTITIONED_TABLE)
792  objtype = SELABEL_DB_TABLE;
793  else if (relForm->relkind == RELKIND_SEQUENCE)
794  objtype = SELABEL_DB_SEQUENCE;
795  else if (relForm->relkind == RELKIND_VIEW)
796  objtype = SELABEL_DB_VIEW;
797  else
798  continue; /* no need to assign security label */
799 
800  namespace_name = get_namespace_name(relForm->relnamespace);
801  objname = quote_object_name(database_name,
802  namespace_name,
803  NameStr(relForm->relname),
804  NULL);
805  pfree(namespace_name);
806 
807  object.classId = RelationRelationId;
808  object.objectId = HeapTupleGetOid(tuple);
809  object.objectSubId = 0;
810  break;
811 
812  case AttributeRelationId:
813  attForm = (Form_pg_attribute) GETSTRUCT(tuple);
814 
815  if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION &&
816  get_rel_relkind(attForm->attrelid) != RELKIND_PARTITIONED_TABLE)
817  continue; /* no need to assign security label */
818 
819  objtype = SELABEL_DB_COLUMN;
820 
821  namespace_id = get_rel_namespace(attForm->attrelid);
822  namespace_name = get_namespace_name(namespace_id);
823  relation_name = get_rel_name(attForm->attrelid);
824  objname = quote_object_name(database_name,
825  namespace_name,
826  relation_name,
827  NameStr(attForm->attname));
828  pfree(namespace_name);
829  pfree(relation_name);
830 
831  object.classId = RelationRelationId;
832  object.objectId = attForm->attrelid;
833  object.objectSubId = attForm->attnum;
834  break;
835 
836  case ProcedureRelationId:
837  proForm = (Form_pg_proc) GETSTRUCT(tuple);
838 
839  objtype = SELABEL_DB_PROCEDURE;
840 
841  namespace_name = get_namespace_name(proForm->pronamespace);
842  objname = quote_object_name(database_name,
843  namespace_name,
844  NameStr(proForm->proname),
845  NULL);
846  pfree(namespace_name);
847 
848  object.classId = ProcedureRelationId;
849  object.objectId = HeapTupleGetOid(tuple);
850  object.objectSubId = 0;
851  break;
852 
853  default:
854  elog(ERROR, "unexpected catalog id: %u", catalogId);
855  objname = NULL; /* for compiler quiet */
856  break;
857  }
858 
859  if (selabel_lookup_raw(sehnd, &context, objname, objtype) == 0)
860  {
861  PG_TRY();
862  {
863  /*
864  * Check SELinux permission to relabel the fetched object,
865  * then do the actual relabeling.
866  */
867  sepgsql_object_relabel(&object, context);
868 
869  SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, context);
870  }
871  PG_CATCH();
872  {
873  freecon(context);
874  PG_RE_THROW();
875  }
876  PG_END_TRY();
877  freecon(context);
878  }
879  else if (errno == ENOENT)
881  (errmsg("SELinux: no initial label assigned for %s (type=%d), skipping",
882  objname, objtype)));
883  else
884  ereport(ERROR,
885  (errcode(ERRCODE_INTERNAL_ERROR),
886  errmsg("SELinux: could not determine initial security label for %s (type=%d): %m", objname, objtype)));
887 
888  pfree(objname);
889  }
890  systable_endscan(sscan);
891 
892  heap_close(rel, NoLock);
893 }
894 
895 /*
896  * BOOL sepgsql_restorecon(TEXT specfile)
897  *
898  * This function tries to assign initial security labels on all the object
899  * within the current database, according to the system setting.
900  * It is typically invoked by sepgsql-install script just after initdb, to
901  * assign initial security labels.
902  *
903  * If @specfile is not NULL, it uses explicitly specified specfile, instead
904  * of the system default.
905  */
907 Datum
909 {
910  struct selabel_handle *sehnd;
911  struct selinux_opt seopts;
912 
913  /*
914  * SELinux has to be enabled on the running platform.
915  */
916  if (!sepgsql_is_enabled())
917  ereport(ERROR,
918  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
919  errmsg("sepgsql is not currently enabled")));
920 
921  /*
922  * Check DAC permission. Only superuser can set up initial security
923  * labels, like root-user in filesystems
924  */
925  if (!superuser())
926  ereport(ERROR,
927  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
928  errmsg("SELinux: must be superuser to restore initial contexts")));
929 
930  /*
931  * Open selabel_lookup(3) stuff. It provides a set of mapping between an
932  * initial security label and object class/name due to the system setting.
933  */
934  if (PG_ARGISNULL(0))
935  {
936  seopts.type = SELABEL_OPT_UNUSED;
937  seopts.value = NULL;
938  }
939  else
940  {
941  seopts.type = SELABEL_OPT_PATH;
942  seopts.value = TextDatumGetCString(PG_GETARG_DATUM(0));
943  }
944  sehnd = selabel_open(SELABEL_CTX_DB, &seopts, 1);
945  if (!sehnd)
946  ereport(ERROR,
947  (errcode(ERRCODE_INTERNAL_ERROR),
948  errmsg("SELinux: failed to initialize labeling handle: %m")));
949  PG_TRY();
950  {
956  }
957  PG_CATCH();
958  {
959  selabel_close(sehnd);
960  PG_RE_THROW();
961  }
962  PG_END_TRY();
963 
964  selabel_close(sehnd);
965 
966  PG_RETURN_BOOL(true);
967 }
#define NIL
Definition: pg_list.h:69
bool sepgsql_avc_check_perms_label(const char *tcontext, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
Definition: uavc.c:346
Datum sepgsql_getcon(PG_FUNCTION_ARGS)
Definition: label.c:558
XactEvent
Definition: xact.h:98
Definition: fmgr.h:56
#define SEPG_DB_PROCEDURE__EXECUTE
Definition: sepgsql.h:165
static char * client_label_func
Definition: label.c:75
#define NamespaceRelationId
Definition: pg_namespace.h:34
bool(* needs_fmgr_hook_type)(Oid fn_oid)
Definition: fmgr.h:720
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
FormData_pg_namespace * Form_pg_namespace
Definition: pg_namespace.h:51
static int32 next
Definition: blutils.c:210
MemoryContext fn_mcxt
Definition: fmgr.h:65
void SetSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
Definition: seclabel.c:327
void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
Definition: schema.c:144
char * getObjectTypeDescription(const ObjectAddress *object)
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10383
#define SEPG_PROCESS__DYNTRANSITION
Definition: sepgsql.h:60
Datum sepgsql_restorecon(PG_FUNCTION_ARGS)
Definition: label.c:908
Datum sepgsql_mcstrans_in(PG_FUNCTION_ARGS)
Definition: label.c:599
static char * client_label_committed
Definition: label.c:73
FormData_pg_database * Form_pg_database
Definition: pg_database.h:57
#define PointerGetDatum(X)
Definition: postgres.h:562
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
#define ProcedureRelationId
Definition: pg_proc.h:33
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define DatabaseRelationId
Definition: pg_database.h:29
#define RelationRelationId
Definition: pg_class.h:29
static void exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
Definition: label.c:724
char * sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
Definition: label.c:463
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 llast(l)
Definition: pg_list.h:131
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
void sepgsql_init_client_label(void)
Definition: label.c:422
MemoryContext CurTransactionContext
Definition: mcxt.c:49
void(* ClientAuthentication_hook_type)(Port *, int)
Definition: auth.h:26
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: libpq-be.h:116
bool superuser(void)
Definition: superuser.c:47
static void sepgsql_xact_callback(XactEvent event, void *arg)
Definition: label.c:176
return result
Definition: formatting.c:1633
uint32 SubTransactionId
Definition: c.h:401
#define heap_close(r, l)
Definition: heapam.h:97
#define SEPG_PROCESS__TRANSITION
Definition: sepgsql.h:59
unsigned int Oid
Definition: postgres_ext.h:31
static ClientAuthentication_hook_type next_client_auth_hook
Definition: label.c:53
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define SEPGSQL_AVC_NOAUDIT
Definition: sepgsql.h:255
char * getObjectDescription(const ObjectAddress *object)
void sepgsql_database_relabel(Oid databaseId, const char *seclabel)
Definition: database.c:188
signed int int32
Definition: c.h:256
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define SEPG_CLASS_PROCESS
Definition: sepgsql.h:36
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
static char * quote_object_name(const char *src1, const char *src2, const char *src3, const char *src4)
Definition: label.c:677
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
static bool sepgsql_needs_fmgr_hook(Oid functionId)
Definition: label.c:286
#define ERROR
Definition: elog.h:43
char * GetSecurityLabel(const ObjectAddress *object, const char *provider)
Definition: seclabel.c:195
#define FATAL
Definition: elog.h:52
char * sepgsql_avc_trusted_proc(Oid functionId)
Definition: uavc.c:453
int sepgsql_set_mode(int new_mode)
Definition: selinux.c:631
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
#define NoLock
Definition: lockdefs.h:34
FmgrHookEventType
Definition: fmgr.h:713
#define SEPG_CLASS_DB_PROCEDURE
Definition: sepgsql.h:48
ClientAuthentication_hook_type ClientAuthentication_hook
Definition: auth.c:235
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define SEPGSQL_LABEL_TAG
Definition: sepgsql.h:23
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
Definition: fmgr.h:716
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Datum sepgsql_mcstrans_out(PG_FUNCTION_ARGS)
Definition: label.c:639
#define STATUS_OK
Definition: c.h:976
static void sepgsql_client_auth(Port *port, int status)
Definition: label.c:248
MemoryContext TopMemoryContext
Definition: mcxt.c:43
static int port
Definition: pg_regress.c:89
List * lappend(List *list, void *datum)
Definition: list.c:128
char * label
Definition: label.c:80
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define WARNING
Definition: elog.h:40
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
void(* fmgr_hook_type)(FmgrHookEventType event, FmgrInfo *flinfo, Datum *arg)
Definition: fmgr.h:722
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
SubXactEvent
Definition: xact.h:112
#define TextDatumGetCString(d)
Definition: builtins.h:92
static needs_fmgr_hook_type next_needs_fmgr_hook
Definition: label.c:54
void * palloc0(Size size)
Definition: mcxt.c:878
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
void RegisterSubXactCallback(SubXactCallback callback, void *arg)
Definition: xact.c:3363
static char * label
Definition: pg_basebackup.c:81
Oid MyDatabaseId
Definition: globals.c:77
static List * client_label_pending
Definition: label.c:71
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
PGDLLIMPORT fmgr_hook_type fmgr_hook
Definition: fmgr.c:37
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook
Definition: fmgr.c:36
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
#define SEPGSQL_MODE_DEFAULT
Definition: sepgsql.h:28
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:330
SubTransactionId subid
Definition: label.c:79
#define PG_CATCH()
Definition: elog.h:293
#define SEPG_DB_PROCEDURE__ENTRYPOINT
Definition: sepgsql.h:166
bool sepgsql_is_enabled(void)
Definition: selinux.c:613
text * cstring_to_text(const char *s)
Definition: varlena.c:149
static void sepgsql_subxact_callback(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: label.c:215
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
#define SEPGSQL_MODE_PERMISSIVE
Definition: sepgsql.h:29
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:649
void RegisterXactCallback(XactCallback callback, void *arg)
Definition: xact.c:3308
static char * client_label_peer
Definition: label.c:70
void sepgsql_relation_relabel(Oid relOid, const char *seclabel)
Definition: relation.c:526
#define PG_RE_THROW()
Definition: elog.h:314
char * sepgsql_get_client_label(void)
Definition: label.c:91
#define DatumGetPointer(X)
Definition: postgres.h:555
bool sepgsql_get_permissive(void)
Definition: hooks.c:65
Datum sepgsql_setcon(PG_FUNCTION_ARGS)
Definition: label.c:577
#define SEPG_PROCESS__SETCURRENT
Definition: sepgsql.h:61
void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, const char *seclabel)
Definition: relation.c:167
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
char * text_to_cstring(const text *t)
Definition: varlena.c:182
static void sepgsql_fmgr_hook(FmgrHookEventType event, FmgrInfo *flinfo, Datum *private)
Definition: label.c:329
void sepgsql_proc_relabel(Oid functionId, const char *seclabel)
Definition: proc.c:200
void sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
Definition: label.c:503
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1064
#define RELKIND_VIEW
Definition: pg_class.h:164
#define NameStr(name)
Definition: c.h:499
void * arg
Definition: c.h:439
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
static fmgr_hook_type next_fmgr_hook
Definition: label.c:55
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
#define PG_TRY()
Definition: elog.h:284
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
PG_FUNCTION_INFO_V1(sepgsql_getcon)
#define PG_RETURN_NULL()
Definition: fmgr.h:305
#define PG_END_TRY()
Definition: elog.h:300
static void sepgsql_set_client_label(const char *new_label)
Definition: label.c:122