PostgreSQL Source Code: contrib/sepgsql/label.c Source File

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

AltStyle によって変換されたページ (->オリジナル) /