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