1 /* -------------------------------------------------------------------------
2  *
3  * contrib/sepgsql/selinux.c
4  *
5  * Interactions between userspace and selinux in kernelspace,
6  * using libselinux api.
7  *
8  * Copyright (c) 2010-2021, PostgreSQL Global Development Group
9  *
10  * -------------------------------------------------------------------------
11  */
12 #include "postgres.h"
13 
14 #include "lib/stringinfo.h"
15 
16 #include "sepgsql.h"
17 
18 /*
19  * selinux_catalog
20  *
21  * This mapping table enables to translate the name of object classes and
22  * access vectors to/from their own codes.
23  * When we ask SELinux whether the required privileges are allowed or not,
24  * we use security_compute_av(3). It needs us to represent object classes
25  * and access vectors using 'external' codes defined in the security policy.
26  * It is determined in the runtime, not build time. So, it needs an internal
27  * service to translate object class/access vectors which we want to check
28  * into the code which kernel want to be given.
29  */
30 static struct
31 {
32 	const char *class_name;
33 	uint16		class_code;
34 	struct
35 	{
36 		const char *av_name;
37 		uint32		av_code;
38 	}			av[32];
39 }			selinux_catalog[] =
40 
41 {
42 	{
43 		"process", SEPG_CLASS_PROCESS,
44 		{
45 			{
46 				"transition", SEPG_PROCESS__TRANSITION
47 			},
48 			{
49 				"dyntransition", SEPG_PROCESS__DYNTRANSITION
50 			},
51 			{
52 				"setcurrent", SEPG_PROCESS__SETCURRENT
53 			},
54 			{
55 				NULL, 0UL
56 			}
57 		}
58 	},
59 	{
60 		"file", SEPG_CLASS_FILE,
61 		{
62 			{
63 				"read", SEPG_FILE__READ
64 			},
65 			{
66 				"write", SEPG_FILE__WRITE
67 			},
68 			{
69 				"create", SEPG_FILE__CREATE
70 			},
71 			{
72 				"getattr", SEPG_FILE__GETATTR
73 			},
74 			{
75 				"unlink", SEPG_FILE__UNLINK
76 			},
77 			{
78 				"rename", SEPG_FILE__RENAME
79 			},
80 			{
81 				"append", SEPG_FILE__APPEND
82 			},
83 			{
84 				NULL, 0UL
85 			}
86 		}
87 	},
88 	{
89 		"dir", SEPG_CLASS_DIR,
90 		{
91 			{
92 				"read", SEPG_DIR__READ
93 			},
94 			{
95 				"write", SEPG_DIR__WRITE
96 			},
97 			{
98 				"create", SEPG_DIR__CREATE
99 			},
100 			{
101 				"getattr", SEPG_DIR__GETATTR
102 			},
103 			{
104 				"unlink", SEPG_DIR__UNLINK
105 			},
106 			{
107 				"rename", SEPG_DIR__RENAME
108 			},
109 			{
110 				"search", SEPG_DIR__SEARCH
111 			},
112 			{
113 				"add_name", SEPG_DIR__ADD_NAME
114 			},
115 			{
116 				"remove_name", SEPG_DIR__REMOVE_NAME
117 			},
118 			{
119 				"rmdir", SEPG_DIR__RMDIR
120 			},
121 			{
122 				"reparent", SEPG_DIR__REPARENT
123 			},
124 			{
125 				NULL, 0UL
126 			}
127 		}
128 	},
129 	{
130 		"lnk_file", SEPG_CLASS_LNK_FILE,
131 		{
132 			{
133 				"read", SEPG_LNK_FILE__READ
134 			},
135 			{
136 				"write", SEPG_LNK_FILE__WRITE
137 			},
138 			{
139 				"create", SEPG_LNK_FILE__CREATE
140 			},
141 			{
142 				"getattr", SEPG_LNK_FILE__GETATTR
143 			},
144 			{
145 				"unlink", SEPG_LNK_FILE__UNLINK
146 			},
147 			{
148 				"rename", SEPG_LNK_FILE__RENAME
149 			},
150 			{
151 				NULL, 0UL
152 			}
153 		}
154 	},
155 	{
156 		"chr_file", SEPG_CLASS_CHR_FILE,
157 		{
158 			{
159 				"read", SEPG_CHR_FILE__READ
160 			},
161 			{
162 				"write", SEPG_CHR_FILE__WRITE
163 			},
164 			{
165 				"create", SEPG_CHR_FILE__CREATE
166 			},
167 			{
168 				"getattr", SEPG_CHR_FILE__GETATTR
169 			},
170 			{
171 				"unlink", SEPG_CHR_FILE__UNLINK
172 			},
173 			{
174 				"rename", SEPG_CHR_FILE__RENAME
175 			},
176 			{
177 				NULL, 0UL
178 			}
179 		}
180 	},
181 	{
182 		"blk_file", SEPG_CLASS_BLK_FILE,
183 		{
184 			{
185 				"read", SEPG_BLK_FILE__READ
186 			},
187 			{
188 				"write", SEPG_BLK_FILE__WRITE
189 			},
190 			{
191 				"create", SEPG_BLK_FILE__CREATE
192 			},
193 			{
194 				"getattr", SEPG_BLK_FILE__GETATTR
195 			},
196 			{
197 				"unlink", SEPG_BLK_FILE__UNLINK
198 			},
199 			{
200 				"rename", SEPG_BLK_FILE__RENAME
201 			},
202 			{
203 				NULL, 0UL
204 			}
205 		}
206 	},
207 	{
208 		"sock_file", SEPG_CLASS_SOCK_FILE,
209 		{
210 			{
211 				"read", SEPG_SOCK_FILE__READ
212 			},
213 			{
214 				"write", SEPG_SOCK_FILE__WRITE
215 			},
216 			{
217 				"create", SEPG_SOCK_FILE__CREATE
218 			},
219 			{
220 				"getattr", SEPG_SOCK_FILE__GETATTR
221 			},
222 			{
223 				"unlink", SEPG_SOCK_FILE__UNLINK
224 			},
225 			{
226 				"rename", SEPG_SOCK_FILE__RENAME
227 			},
228 			{
229 				NULL, 0UL
230 			}
231 		}
232 	},
233 	{
234 		"fifo_file", SEPG_CLASS_FIFO_FILE,
235 		{
236 			{
237 				"read", SEPG_FIFO_FILE__READ
238 			},
239 			{
240 				"write", SEPG_FIFO_FILE__WRITE
241 			},
242 			{
243 				"create", SEPG_FIFO_FILE__CREATE
244 			},
245 			{
246 				"getattr", SEPG_FIFO_FILE__GETATTR
247 			},
248 			{
249 				"unlink", SEPG_FIFO_FILE__UNLINK
250 			},
251 			{
252 				"rename", SEPG_FIFO_FILE__RENAME
253 			},
254 			{
255 				NULL, 0UL
256 			}
257 		}
258 	},
259 	{
260 		"db_database", SEPG_CLASS_DB_DATABASE,
261 		{
262 			{
263 				"create", SEPG_DB_DATABASE__CREATE
264 			},
265 			{
266 				"drop", SEPG_DB_DATABASE__DROP
267 			},
268 			{
269 				"getattr", SEPG_DB_DATABASE__GETATTR
270 			},
271 			{
272 				"setattr", SEPG_DB_DATABASE__SETATTR
273 			},
274 			{
275 				"relabelfrom", SEPG_DB_DATABASE__RELABELFROM
276 			},
277 			{
278 				"relabelto", SEPG_DB_DATABASE__RELABELTO
279 			},
280 			{
281 				"access", SEPG_DB_DATABASE__ACCESS
282 			},
283 			{
284 				"load_module", SEPG_DB_DATABASE__LOAD_MODULE
285 			},
286 			{
287 				NULL, 0UL
288 			},
289 		}
290 	},
291 	{
292 		"db_schema", SEPG_CLASS_DB_SCHEMA,
293 		{
294 			{
295 				"create", SEPG_DB_SCHEMA__CREATE
296 			},
297 			{
298 				"drop", SEPG_DB_SCHEMA__DROP
299 			},
300 			{
301 				"getattr", SEPG_DB_SCHEMA__GETATTR
302 			},
303 			{
304 				"setattr", SEPG_DB_SCHEMA__SETATTR
305 			},
306 			{
307 				"relabelfrom", SEPG_DB_SCHEMA__RELABELFROM
308 			},
309 			{
310 				"relabelto", SEPG_DB_SCHEMA__RELABELTO
311 			},
312 			{
313 				"search", SEPG_DB_SCHEMA__SEARCH
314 			},
315 			{
316 				"add_name", SEPG_DB_SCHEMA__ADD_NAME
317 			},
318 			{
319 				"remove_name", SEPG_DB_SCHEMA__REMOVE_NAME
320 			},
321 			{
322 				NULL, 0UL
323 			},
324 		}
325 	},
326 	{
327 		"db_table", SEPG_CLASS_DB_TABLE,
328 		{
329 			{
330 				"create", SEPG_DB_TABLE__CREATE
331 			},
332 			{
333 				"drop", SEPG_DB_TABLE__DROP
334 			},
335 			{
336 				"getattr", SEPG_DB_TABLE__GETATTR
337 			},
338 			{
339 				"setattr", SEPG_DB_TABLE__SETATTR
340 			},
341 			{
342 				"relabelfrom", SEPG_DB_TABLE__RELABELFROM
343 			},
344 			{
345 				"relabelto", SEPG_DB_TABLE__RELABELTO
346 			},
347 			{
348 				"select", SEPG_DB_TABLE__SELECT
349 			},
350 			{
351 				"update", SEPG_DB_TABLE__UPDATE
352 			},
353 			{
354 				"insert", SEPG_DB_TABLE__INSERT
355 			},
356 			{
357 				"delete", SEPG_DB_TABLE__DELETE
358 			},
359 			{
360 				"lock", SEPG_DB_TABLE__LOCK
361 			},
362 			{
363 				"truncate", SEPG_DB_TABLE__TRUNCATE
364 			},
365 			{
366 				NULL, 0UL
367 			},
368 		}
369 	},
370 	{
371 		"db_sequence", SEPG_CLASS_DB_SEQUENCE,
372 		{
373 			{
374 				"create", SEPG_DB_SEQUENCE__CREATE
375 			},
376 			{
377 				"drop", SEPG_DB_SEQUENCE__DROP
378 			},
379 			{
380 				"getattr", SEPG_DB_SEQUENCE__GETATTR
381 			},
382 			{
383 				"setattr", SEPG_DB_SEQUENCE__SETATTR
384 			},
385 			{
386 				"relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM
387 			},
388 			{
389 				"relabelto", SEPG_DB_SEQUENCE__RELABELTO
390 			},
391 			{
392 				"get_value", SEPG_DB_SEQUENCE__GET_VALUE
393 			},
394 			{
395 				"next_value", SEPG_DB_SEQUENCE__NEXT_VALUE
396 			},
397 			{
398 				"set_value", SEPG_DB_SEQUENCE__SET_VALUE
399 			},
400 			{
401 				NULL, 0UL
402 			},
403 		}
404 	},
405 	{
406 		"db_procedure", SEPG_CLASS_DB_PROCEDURE,
407 		{
408 			{
409 				"create", SEPG_DB_PROCEDURE__CREATE
410 			},
411 			{
412 				"drop", SEPG_DB_PROCEDURE__DROP
413 			},
414 			{
415 				"getattr", SEPG_DB_PROCEDURE__GETATTR
416 			},
417 			{
418 				"setattr", SEPG_DB_PROCEDURE__SETATTR
419 			},
420 			{
421 				"relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM
422 			},
423 			{
424 				"relabelto", SEPG_DB_PROCEDURE__RELABELTO
425 			},
426 			{
427 				"execute", SEPG_DB_PROCEDURE__EXECUTE
428 			},
429 			{
430 				"entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT
431 			},
432 			{
433 				"install", SEPG_DB_PROCEDURE__INSTALL
434 			},
435 			{
436 				NULL, 0UL
437 			},
438 		}
439 	},
440 	{
441 		"db_column", SEPG_CLASS_DB_COLUMN,
442 		{
443 			{
444 				"create", SEPG_DB_COLUMN__CREATE
445 			},
446 			{
447 				"drop", SEPG_DB_COLUMN__DROP
448 			},
449 			{
450 				"getattr", SEPG_DB_COLUMN__GETATTR
451 			},
452 			{
453 				"setattr", SEPG_DB_COLUMN__SETATTR
454 			},
455 			{
456 				"relabelfrom", SEPG_DB_COLUMN__RELABELFROM
457 			},
458 			{
459 				"relabelto", SEPG_DB_COLUMN__RELABELTO
460 			},
461 			{
462 				"select", SEPG_DB_COLUMN__SELECT
463 			},
464 			{
465 				"update", SEPG_DB_COLUMN__UPDATE
466 			},
467 			{
468 				"insert", SEPG_DB_COLUMN__INSERT
469 			},
470 			{
471 				NULL, 0UL
472 			},
473 		}
474 	},
475 	{
476 		"db_tuple", SEPG_CLASS_DB_TUPLE,
477 		{
478 			{
479 				"relabelfrom", SEPG_DB_TUPLE__RELABELFROM
480 			},
481 			{
482 				"relabelto", SEPG_DB_TUPLE__RELABELTO
483 			},
484 			{
485 				"select", SEPG_DB_TUPLE__SELECT
486 			},
487 			{
488 				"update", SEPG_DB_TUPLE__UPDATE
489 			},
490 			{
491 				"insert", SEPG_DB_TUPLE__INSERT
492 			},
493 			{
494 				"delete", SEPG_DB_TUPLE__DELETE
495 			},
496 			{
497 				NULL, 0UL
498 			},
499 		}
500 	},
501 	{
502 		"db_blob", SEPG_CLASS_DB_BLOB,
503 		{
504 			{
505 				"create", SEPG_DB_BLOB__CREATE
506 			},
507 			{
508 				"drop", SEPG_DB_BLOB__DROP
509 			},
510 			{
511 				"getattr", SEPG_DB_BLOB__GETATTR
512 			},
513 			{
514 				"setattr", SEPG_DB_BLOB__SETATTR
515 			},
516 			{
517 				"relabelfrom", SEPG_DB_BLOB__RELABELFROM
518 			},
519 			{
520 				"relabelto", SEPG_DB_BLOB__RELABELTO
521 			},
522 			{
523 				"read", SEPG_DB_BLOB__READ
524 			},
525 			{
526 				"write", SEPG_DB_BLOB__WRITE
527 			},
528 			{
529 				"import", SEPG_DB_BLOB__IMPORT
530 			},
531 			{
532 				"export", SEPG_DB_BLOB__EXPORT
533 			},
534 			{
535 				NULL, 0UL
536 			},
537 		}
538 	},
539 	{
540 		"db_language", SEPG_CLASS_DB_LANGUAGE,
541 		{
542 			{
543 				"create", SEPG_DB_LANGUAGE__CREATE
544 			},
545 			{
546 				"drop", SEPG_DB_LANGUAGE__DROP
547 			},
548 			{
549 				"getattr", SEPG_DB_LANGUAGE__GETATTR
550 			},
551 			{
552 				"setattr", SEPG_DB_LANGUAGE__SETATTR
553 			},
554 			{
555 				"relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM
556 			},
557 			{
558 				"relabelto", SEPG_DB_LANGUAGE__RELABELTO
559 			},
560 			{
561 				"implement", SEPG_DB_LANGUAGE__IMPLEMENT
562 			},
563 			{
564 				"execute", SEPG_DB_LANGUAGE__EXECUTE
565 			},
566 			{
567 				NULL, 0UL
568 			},
569 		}
570 	},
571 	{
572 		"db_view", SEPG_CLASS_DB_VIEW,
573 		{
574 			{
575 				"create", SEPG_DB_VIEW__CREATE
576 			},
577 			{
578 				"drop", SEPG_DB_VIEW__DROP
579 			},
580 			{
581 				"getattr", SEPG_DB_VIEW__GETATTR
582 			},
583 			{
584 				"setattr", SEPG_DB_VIEW__SETATTR
585 			},
586 			{
587 				"relabelfrom", SEPG_DB_VIEW__RELABELFROM
588 			},
589 			{
590 				"relabelto", SEPG_DB_VIEW__RELABELTO
591 			},
592 			{
593 				"expand", SEPG_DB_VIEW__EXPAND
594 			},
595 			{
596 				NULL, 0UL
597 			},
598 		}
599 	},
600 };
601 
602 /*
603  * sepgsql_mode
604  *
605  * SEPGSQL_MODE_DISABLED: Disabled on runtime
606  * SEPGSQL_MODE_DEFAULT: Same as system settings
607  * SEPGSQL_MODE_PERMISSIVE: Always permissive mode
608  * SEPGSQL_MODE_INTERNAL: Same as permissive, except for no audit logs
609  */
610 static int	sepgsql_mode = SEPGSQL_MODE_INTERNAL;
611 
612 /*
613  * sepgsql_is_enabled
614  */
615 bool
sepgsql_is_enabled(void)616 sepgsql_is_enabled(void)
617 {
618 	return (sepgsql_mode != SEPGSQL_MODE_DISABLED ? true : false);
619 }
620 
621 /*
622  * sepgsql_get_mode
623  */
624 int
sepgsql_get_mode(void)625 sepgsql_get_mode(void)
626 {
627 	return sepgsql_mode;
628 }
629 
630 /*
631  * sepgsql_set_mode
632  */
633 int
sepgsql_set_mode(int new_mode)634 sepgsql_set_mode(int new_mode)
635 {
636 	int			old_mode = sepgsql_mode;
637 
638 	sepgsql_mode = new_mode;
639 
640 	return old_mode;
641 }
642 
643 /*
644  * sepgsql_getenforce
645  *
646  * It returns whether the current working mode tries to enforce access
647  * control decision, or not. It shall be enforced when sepgsql_mode is
648  * SEPGSQL_MODE_DEFAULT and system is running in enforcing mode.
649  */
650 bool
sepgsql_getenforce(void)651 sepgsql_getenforce(void)
652 {
653 	if (sepgsql_mode == SEPGSQL_MODE_DEFAULT &&
654 		selinux_status_getenforce() > 0)
655 		return true;
656 
657 	return false;
658 }
659 
660 /*
661  * sepgsql_audit_log
662  *
663  * It generates a security audit record. It writes out audit records
664  * into standard PG's logfile.
665  *
666  * SELinux can control what should be audited and should not using
667  * "auditdeny" and "auditallow" rules in the security policy. In the
668  * default, all the access violations are audited, and all the access
669  * allowed are not audited. But we can set up the security policy, so
670  * we can have exceptions. So, it is necessary to follow the suggestion
671  * come from the security policy. (av_decision.auditallow and auditdeny)
672  *
673  * Security audit is an important feature, because it enables us to check
674  * what was happen if we have a security incident. In fact, ISO/IEC15408
675  * defines several security functionalities for audit features.
676  */
677 void
sepgsql_audit_log(bool denied,const char * scontext,const char * tcontext,uint16 tclass,uint32 audited,const char * audit_name)678 sepgsql_audit_log(bool denied,
679 				  const char *scontext,
680 				  const char *tcontext,
681 				  uint16 tclass,
682 				  uint32 audited,
683 				  const char *audit_name)
684 {
685 	StringInfoData buf;
686 	const char *class_name;
687 	const char *av_name;
688 	int			i;
689 
690 	/* lookup name of the object class */
691 	Assert(tclass < SEPG_CLASS_MAX);
692 	class_name = selinux_catalog[tclass].class_name;
693 
694 	/* lookup name of the permissions */
695 	initStringInfo(&buf);
696 	appendStringInfo(&buf, "%s {",
697 					 (denied ? "denied" : "allowed"));
698 	for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
699 	{
700 		if (audited & (1UL << i))
701 		{
702 			av_name = selinux_catalog[tclass].av[i].av_name;
703 			appendStringInfo(&buf, " %s", av_name);
704 		}
705 	}
706 	appendStringInfoString(&buf, " }");
707 
708 	/*
709 	 * Call external audit module, if loaded
710 	 */
711 	appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s",
712 					 scontext, tcontext, class_name);
713 	if (audit_name)
714 		appendStringInfo(&buf, " name=\"%s\"", audit_name);
715 
716 	ereport(LOG, (errmsg("SELinux: %s", buf.data)));
717 }
718 
719 /*
720  * sepgsql_compute_avd
721  *
722  * It actually asks SELinux what permissions are allowed on a pair of
723  * the security contexts and object class. It also returns what permissions
724  * should be audited on access violation or allowed.
725  * In most cases, subject's security context (scontext) is a client, and
726  * target security context (tcontext) is a database object.
727  *
728  * The access control decision shall be set on the given av_decision.
729  * The av_decision.allowed has a bitmask of SEPG_<class>__<perms>
730  * to suggest a set of allowed actions in this object class.
731  */
732 void
sepgsql_compute_avd(const char * scontext,const char * tcontext,uint16 tclass,struct av_decision * avd)733 sepgsql_compute_avd(const char *scontext,
734 					const char *tcontext,
735 					uint16 tclass,
736 					struct av_decision *avd)
737 {
738 	const char *tclass_name;
739 	security_class_t tclass_ex;
740 	struct av_decision avd_ex;
741 	int			i,
742 				deny_unknown = security_deny_unknown();
743 
744 	/* Get external code of the object class */
745 	Assert(tclass < SEPG_CLASS_MAX);
746 	Assert(tclass == selinux_catalog[tclass].class_code);
747 
748 	tclass_name = selinux_catalog[tclass].class_name;
749 	tclass_ex = string_to_security_class(tclass_name);
750 
751 	if (tclass_ex == 0)
752 	{
753 		/*
754 		 * If the current security policy does not support permissions
755 		 * corresponding to database objects, we fill up them with dummy data.
756 		 * If security_deny_unknown() returns positive value, undefined
757 		 * permissions should be denied. Otherwise, allowed
758 		 */
759 		avd->allowed = (security_deny_unknown() > 0 ? 0 : ~0);
760 		avd->auditallow = 0U;
761 		avd->auditdeny = ~0U;
762 		avd->flags = 0;
763 
764 		return;
765 	}
766 
767 	/*
768 	 * Ask SELinux what is allowed set of permissions on a pair of the
769 	 * security contexts and the given object class.
770 	 */
771 	if (security_compute_av_flags_raw(scontext,
772 									  tcontext,
773 									  tclass_ex, 0, &avd_ex) < 0)
774 		ereport(ERROR,
775 				(errcode(ERRCODE_INTERNAL_ERROR),
776 				 errmsg("SELinux could not compute av_decision: "
777 						"scontext=%s tcontext=%s tclass=%s: %m",
778 						scontext, tcontext, tclass_name)));
779 
780 	/*
781 	 * SELinux returns its access control decision as a set of permissions
782 	 * represented in external code which depends on run-time environment. So,
783 	 * we need to translate it to the internal representation before returning
784 	 * results for the caller.
785 	 */
786 	memset(avd, 0, sizeof(struct av_decision));
787 
788 	for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
789 	{
790 		access_vector_t av_code_ex;
791 		const char *av_name = selinux_catalog[tclass].av[i].av_name;
792 		uint32		av_code = selinux_catalog[tclass].av[i].av_code;
793 
794 		av_code_ex = string_to_av_perm(tclass_ex, av_name);
795 		if (av_code_ex == 0)
796 		{
797 			/* fill up undefined permissions */
798 			if (!deny_unknown)
799 				avd->allowed |= av_code;
800 			avd->auditdeny |= av_code;
801 
802 			continue;
803 		}
804 
805 		if (avd_ex.allowed & av_code_ex)
806 			avd->allowed |= av_code;
807 		if (avd_ex.auditallow & av_code_ex)
808 			avd->auditallow |= av_code;
809 		if (avd_ex.auditdeny & av_code_ex)
810 			avd->auditdeny |= av_code;
811 	}
812 }
813 
814 /*
815  * sepgsql_compute_create
816  *
817  * It returns a default security context to be assigned on a new database
818  * object. SELinux compute it based on a combination of client, upper object
819  * which owns the new object and object class.
820  *
821  * For example, when a client (staff_u:staff_r:staff_t:s0) tries to create
822  * a new table within a schema (system_u:object_r:sepgsql_schema_t:s0),
823  * SELinux looks-up its security policy. If it has a special rule on the
824  * combination of these security contexts and object class (db_table),
825  * it returns the security context suggested by the special rule.
826  * Otherwise, it returns the security context of schema, as is.
827  *
828  * We expect the caller already applies sanity/validation checks on the
829  * given security context.
830  *
831  * scontext: security context of the subject (mostly, peer process).
832  * tcontext: security context of the upper database object.
833  * tclass: class code (SEPG_CLASS_*) of the new object in creation
834  */
835 char *
sepgsql_compute_create(const char * scontext,const char * tcontext,uint16 tclass,const char * objname)836 sepgsql_compute_create(const char *scontext,
837 					   const char *tcontext,
838 					   uint16 tclass,
839 					   const char *objname)
840 {
841 	char	   *ncontext;
842 	security_class_t tclass_ex;
843 	const char *tclass_name;
844 	char	   *result;
845 
846 	/* Get external code of the object class */
847 	Assert(tclass < SEPG_CLASS_MAX);
848 
849 	tclass_name = selinux_catalog[tclass].class_name;
850 	tclass_ex = string_to_security_class(tclass_name);
851 
852 	/*
853 	 * Ask SELinux what is the default context for the given object class on a
854 	 * pair of security contexts
855 	 */
856 	if (security_compute_create_name_raw(scontext,
857 										 tcontext,
858 										 tclass_ex,
859 										 objname,
860 										 &ncontext) < 0)
861 		ereport(ERROR,
862 				(errcode(ERRCODE_INTERNAL_ERROR),
863 				 errmsg("SELinux could not compute a new context: "
864 						"scontext=%s tcontext=%s tclass=%s: %m",
865 						scontext, tcontext, tclass_name)));
866 
867 	/*
868 	 * libselinux returns malloc()'ed string, so we need to copy it on the
869 	 * palloc()'ed region.
870 	 */
871 	PG_TRY();
872 	{
873 		result = pstrdup(ncontext);
874 	}
875 	PG_FINALLY();
876 	{
877 		freecon(ncontext);
878 	}
879 	PG_END_TRY();
880 
881 	return result;
882 }
883 
884 /*
885  * sepgsql_check_perms
886  *
887  * It makes access control decision without userspace caching mechanism.
888  * If SELinux denied the required accesses on the pair of security labels,
889  * it raises an error or returns false.
890  *
891  * scontext: security label of the subject (mostly, peer process)
892  * tcontext: security label of the object being referenced
893  * tclass: class code (SEPG_CLASS_*) of the object being referenced
894  * required: a mask of required permissions (SEPG_<class>__<perm>)
895  * audit_name: a human-readable object name for audit logs, or NULL.
896  * abort_on_violation: true, if error shall be raised on access violation
897  */
898 bool
sepgsql_check_perms(const char * scontext,const char * tcontext,uint16 tclass,uint32 required,const char * audit_name,bool abort_on_violation)899 sepgsql_check_perms(const char *scontext,
900 					const char *tcontext,
901 					uint16 tclass,
902 					uint32 required,
903 					const char *audit_name,
904 					bool abort_on_violation)
905 {
906 	struct av_decision avd;
907 	uint32		denied;
908 	uint32		audited;
909 	bool		result = true;
910 
911 	sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
912 
913 	denied = required & ~avd.allowed;
914 
915 	if (sepgsql_get_debug_audit())
916 		audited = (denied ? denied : required);
917 	else
918 		audited = (denied ? (denied & avd.auditdeny)
919 				   : (required & avd.auditallow));
920 
921 	if (denied &&
922 		sepgsql_getenforce() > 0 &&
923 		(avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) == 0)
924 		result = false;
925 
926 	/*
927 	 * It records a security audit for the request, if needed. But, when
928 	 * SE-PgSQL performs 'internal' mode, it needs to keep silent.
929 	 */
930 	if (audited && sepgsql_mode != SEPGSQL_MODE_INTERNAL)
931 	{
932 		sepgsql_audit_log(denied,
933 						  scontext,
934 						  tcontext,
935 						  tclass,
936 						  audited,
937 						  audit_name);
938 	}
939 
940 	if (!result && abort_on_violation)
941 		ereport(ERROR,
942 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
943 				 errmsg("SELinux: security policy violation")));
944 	return result;
945 }
946