PostgreSQL Source Code  git master
uavc.c
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  *
3  * contrib/sepgsql/uavc.c
4  *
5  * Implementation of userspace access vector cache; that enables to cache
6  * access control decisions recently used, and reduce number of kernel
7  * invocations to avoid unnecessary performance hit.
8  *
9  * Copyright (c) 2011-2019, PostgreSQL Global Development Group
10  *
11  * -------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "catalog/pg_proc.h"
16 #include "commands/seclabel.h"
17 #include "storage/ipc.h"
18 #include "utils/guc.h"
19 #include "utils/hashutils.h"
20 #include "utils/memutils.h"
21 
22 #include "sepgsql.h"
23 
24 /*
25  * avc_cache
26  *
27  * It enables to cache access control decision (and behavior on execution of
28  * trusted procedure, db_procedure class only) for a particular pair of
29  * security labels and object class in userspace.
30  */
31 typedef struct
32 {
33  uint32 hash; /* hash value of this cache entry */
34  char *scontext; /* security context of the subject */
35  char *tcontext; /* security context of the target */
36  uint16 tclass; /* object class of the target */
37 
38  uint32 allowed; /* permissions to be allowed */
39  uint32 auditallow; /* permissions to be audited on allowed */
40  uint32 auditdeny; /* permissions to be audited on denied */
41 
42  bool permissive; /* true, if permissive rule */
43  bool hot_cache; /* true, if recently referenced */
45  /* true, if tcontext is valid */
46  char *ncontext; /* temporary scontext on execution of trusted
47  * procedure, or NULL elsewhere */
48 } avc_cache;
49 
50 /*
51  * Declaration of static variables
52  */
53 #define AVC_NUM_SLOTS 512
54 #define AVC_NUM_RECLAIM 16
55 #define AVC_DEF_THRESHOLD 384
56 
58 static List *avc_slots[AVC_NUM_SLOTS]; /* avc's hash buckets */
59 static int avc_num_caches; /* number of caches currently used */
60 static int avc_lru_hint; /* index of the buckets to be reclaimed next */
61 static int avc_threshold; /* threshold to launch cache-reclaiming */
62 static char *avc_unlabeled; /* system 'unlabeled' label */
63 
64 /*
65  * Hash function
66  */
67 static uint32
68 sepgsql_avc_hash(const char *scontext, const char *tcontext, uint16 tclass)
69 {
70  return hash_any((const unsigned char *) scontext, strlen(scontext))
71  ^ hash_any((const unsigned char *) tcontext, strlen(tcontext))
72  ^ tclass;
73 }
74 
75 /*
76  * Reset all the avc caches
77  */
78 static void
80 {
81  MemoryContextReset(avc_mem_cxt);
82 
83  memset(avc_slots, 0, sizeof(List *) * AVC_NUM_SLOTS);
84  avc_num_caches = 0;
85  avc_lru_hint = 0;
86  avc_unlabeled = NULL;
87 }
88 
89 /*
90  * Reclaim caches recently unreferenced
91  */
92 static void
94 {
95  ListCell *cell;
96  int index;
97 
99  {
100  index = avc_lru_hint;
101 
102  foreach(cell, avc_slots[index])
103  {
104  avc_cache *cache = lfirst(cell);
105 
106  if (!cache->hot_cache)
107  {
108  avc_slots[index]
109  = foreach_delete_current(avc_slots[index], cell);
110 
111  pfree(cache->scontext);
112  pfree(cache->tcontext);
113  if (cache->ncontext)
114  pfree(cache->ncontext);
115  pfree(cache);
116 
117  avc_num_caches--;
118  }
119  else
120  {
121  cache->hot_cache = false;
122  }
123  }
125  }
126 }
127 
128 /* -------------------------------------------------------------------------
129  *
130  * sepgsql_avc_check_valid
131  *
132  * This function checks whether the cached entries are still valid. If
133  * the security policy has been reloaded (or any other events that requires
134  * resetting userspace caches has occurred) since the last reference to
135  * the access vector cache, we must flush the cache.
136  *
137  * Access control decisions must be atomic, but multiple system calls may
138  * be required to make a decision; thus, when referencing the access vector
139  * cache, we must loop until we complete without an intervening cache flush
140  * event. In practice, looping even once should be very rare. Callers should
141  * do something like this:
142  *
143  * sepgsql_avc_check_valid();
144  * do {
145  * :
146  * <reference to uavc>
147  * :
148  * } while (!sepgsql_avc_check_valid())
149  *
150  * -------------------------------------------------------------------------
151  */
152 static bool
154 {
155  if (selinux_status_updated() > 0)
156  {
158 
159  return false;
160  }
161  return true;
162 }
163 
164 /*
165  * sepgsql_avc_unlabeled
166  *
167  * Returns an alternative label to be applied when no label or an invalid
168  * label would otherwise be assigned.
169  */
170 static char *
172 {
173  if (!avc_unlabeled)
174  {
175  security_context_t unlabeled;
176 
177  if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
178  ereport(ERROR,
179  (errcode(ERRCODE_INTERNAL_ERROR),
180  errmsg("SELinux: failed to get initial security label: %m")));
181  PG_TRY();
182  {
183  avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled);
184  }
185  PG_CATCH();
186  {
187  freecon(unlabeled);
188  PG_RE_THROW();
189  }
190  PG_END_TRY();
191 
192  freecon(unlabeled);
193  }
194  return avc_unlabeled;
195 }
196 
197 /*
198  * sepgsql_avc_compute
199  *
200  * A fallback path, when cache mishit. It asks SELinux its access control
201  * decision for the supplied pair of security context and object class.
202  */
203 static avc_cache *
204 sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass)
205 {
206  char *ucontext = NULL;
207  char *ncontext = NULL;
208  MemoryContext oldctx;
209  avc_cache *cache;
210  uint32 hash;
211  int index;
212  struct av_decision avd;
213 
214  hash = sepgsql_avc_hash(scontext, tcontext, tclass);
215  index = hash % AVC_NUM_SLOTS;
216 
217  /*
218  * Validation check of the supplied security context. Because it always
219  * invoke system-call, frequent check should be avoided. Unless security
220  * policy is reloaded, validation status shall be kept, so we also cache
221  * whether the supplied security context was valid, or not.
222  */
223  if (security_check_context_raw((security_context_t) tcontext) != 0)
224  ucontext = sepgsql_avc_unlabeled();
225 
226  /*
227  * Ask SELinux its access control decision
228  */
229  if (!ucontext)
230  sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
231  else
232  sepgsql_compute_avd(scontext, ucontext, tclass, &avd);
233 
234  /*
235  * It also caches a security label to be switched when a client labeled as
236  * 'scontext' executes a procedure labeled as 'tcontext', not only access
237  * control decision on the procedure. The security label to be switched
238  * shall be computed uniquely on a pair of 'scontext' and 'tcontext',
239  * thus, it is reasonable to cache the new label on avc, and enables to
240  * reduce unnecessary system calls. It shall be referenced at
241  * sepgsql_needs_fmgr_hook to check whether the supplied function is a
242  * trusted procedure, or not.
243  */
244  if (tclass == SEPG_CLASS_DB_PROCEDURE)
245  {
246  if (!ucontext)
247  ncontext = sepgsql_compute_create(scontext, tcontext,
248  SEPG_CLASS_PROCESS, NULL);
249  else
250  ncontext = sepgsql_compute_create(scontext, ucontext,
251  SEPG_CLASS_PROCESS, NULL);
252  if (strcmp(scontext, ncontext) == 0)
253  {
254  pfree(ncontext);
255  ncontext = NULL;
256  }
257  }
258 
259  /*
260  * Set up an avc_cache object
261  */
262  oldctx = MemoryContextSwitchTo(avc_mem_cxt);
263 
264  cache = palloc0(sizeof(avc_cache));
265 
266  cache->hash = hash;
267  cache->scontext = pstrdup(scontext);
268  cache->tcontext = pstrdup(tcontext);
269  cache->tclass = tclass;
270 
271  cache->allowed = avd.allowed;
272  cache->auditallow = avd.auditallow;
273  cache->auditdeny = avd.auditdeny;
274  cache->hot_cache = true;
275  if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)
276  cache->permissive = true;
277  if (!ucontext)
278  cache->tcontext_is_valid = true;
279  if (ncontext)
280  cache->ncontext = pstrdup(ncontext);
281 
282  avc_num_caches++;
283 
286 
287  avc_slots[index] = lcons(cache, avc_slots[index]);
288 
289  MemoryContextSwitchTo(oldctx);
290 
291  return cache;
292 }
293 
294 /*
295  * sepgsql_avc_lookup
296  *
297  * Look up a cache entry that matches the supplied security contexts and
298  * object class. If not found, create a new cache entry.
299  */
300 static avc_cache *
301 sepgsql_avc_lookup(const char *scontext, const char *tcontext, uint16 tclass)
302 {
303  avc_cache *cache;
304  ListCell *cell;
305  uint32 hash;
306  int index;
307 
308  hash = sepgsql_avc_hash(scontext, tcontext, tclass);
309  index = hash % AVC_NUM_SLOTS;
310 
311  foreach(cell, avc_slots[index])
312  {
313  cache = lfirst(cell);
314 
315  if (cache->hash == hash &&
316  cache->tclass == tclass &&
317  strcmp(cache->tcontext, tcontext) == 0 &&
318  strcmp(cache->scontext, scontext) == 0)
319  {
320  cache->hot_cache = true;
321  return cache;
322  }
323  }
324  /* not found, so insert a new cache */
325  return sepgsql_avc_compute(scontext, tcontext, tclass);
326 }
327 
328 /*
329  * sepgsql_avc_check_perms(_label)
330  *
331  * It returns 'true', if the security policy suggested to allow the required
332  * permissions. Otherwise, it returns 'false' or raises an error according
333  * to the 'abort_on_violation' argument.
334  * The 'tobject' and 'tclass' identify the target object being referenced,
335  * and 'required' is a bitmask of permissions (SEPG_*__*) defined for each
336  * object classes.
337  * The 'audit_name' is the object name (optional). If SEPGSQL_AVC_NOAUDIT
338  * was supplied, it means to skip all the audit messages.
339  */
340 bool
341 sepgsql_avc_check_perms_label(const char *tcontext,
342  uint16 tclass, uint32 required,
343  const char *audit_name,
344  bool abort_on_violation)
345 {
346  char *scontext = sepgsql_get_client_label();
347  avc_cache *cache;
348  uint32 denied;
349  uint32 audited;
350  bool result;
351 
353  do
354  {
355  result = true;
356 
357  /*
358  * If the target object is unlabeled, we perform the check using the
359  * label supplied by sepgsql_avc_unlabeled().
360  */
361  if (tcontext)
362  cache = sepgsql_avc_lookup(scontext, tcontext, tclass);
363  else
364  cache = sepgsql_avc_lookup(scontext,
365  sepgsql_avc_unlabeled(), tclass);
366 
367  denied = required & ~cache->allowed;
368 
369  /*
370  * Compute permissions to be audited
371  */
373  audited = (denied ? (denied & ~0) : (required & ~0));
374  else
375  audited = denied ? (denied & cache->auditdeny)
376  : (required & cache->auditallow);
377 
378  if (denied)
379  {
380  /*
381  * In permissive mode or permissive domain, violated permissions
382  * shall be audited to the log files at once, and then implicitly
383  * allowed to avoid a flood of access denied logs, because the
384  * purpose of permissive mode/domain is to collect a violation log
385  * that will make it possible to fix up the security policy.
386  */
387  if (!sepgsql_getenforce() || cache->permissive)
388  cache->allowed |= required;
389  else
390  result = false;
391  }
392  } while (!sepgsql_avc_check_valid());
393 
394  /*
395  * In the case when we have something auditable actions here,
396  * sepgsql_audit_log shall be called with text representation of security
397  * labels for both of subject and object. It records this access
398  * violation, so DBA will be able to find out unexpected security problems
399  * later.
400  */
401  if (audited != 0 &&
402  audit_name != SEPGSQL_AVC_NOAUDIT &&
404  {
405  sepgsql_audit_log(denied != 0,
406  cache->scontext,
407  cache->tcontext_is_valid ?
408  cache->tcontext : sepgsql_avc_unlabeled(),
409  cache->tclass,
410  audited,
411  audit_name);
412  }
413 
414  if (abort_on_violation && !result)
415  ereport(ERROR,
416  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
417  errmsg("SELinux: security policy violation")));
418 
419  return result;
420 }
421 
422 bool
424  uint16 tclass, uint32 required,
425  const char *audit_name,
426  bool abort_on_violation)
427 {
428  char *tcontext = GetSecurityLabel(tobject, SEPGSQL_LABEL_TAG);
429  bool rc;
430 
431  rc = sepgsql_avc_check_perms_label(tcontext,
432  tclass, required,
433  audit_name, abort_on_violation);
434  if (tcontext)
435  pfree(tcontext);
436 
437  return rc;
438 }
439 
440 /*
441  * sepgsql_avc_trusted_proc
442  *
443  * If the supplied function OID is configured as a trusted procedure, this
444  * function will return a security label to be used during the execution of
445  * that function. Otherwise, it returns NULL.
446  */
447 char *
449 {
450  char *scontext = sepgsql_get_client_label();
451  char *tcontext;
452  ObjectAddress tobject;
453  avc_cache *cache;
454 
455  tobject.classId = ProcedureRelationId;
456  tobject.objectId = functionId;
457  tobject.objectSubId = 0;
458  tcontext = GetSecurityLabel(&tobject, SEPGSQL_LABEL_TAG);
459 
461  do
462  {
463  if (tcontext)
464  cache = sepgsql_avc_lookup(scontext, tcontext,
466  else
467  cache = sepgsql_avc_lookup(scontext, sepgsql_avc_unlabeled(),
469  } while (!sepgsql_avc_check_valid());
470 
471  return cache->ncontext;
472 }
473 
474 /*
475  * sepgsql_avc_exit
476  *
477  * Clean up userspace AVC on process exit.
478  */
479 static void
481 {
482  selinux_status_close();
483 }
484 
485 /*
486  * sepgsql_avc_init
487  *
488  * Initialize the userspace AVC. This should be called from _PG_init.
489  */
490 void
492 {
493  int rc;
494 
495  /*
496  * All the avc stuff shall be allocated in avc_mem_cxt
497  */
499  "userspace access vector cache",
501  memset(avc_slots, 0, sizeof(avc_slots));
502  avc_num_caches = 0;
503  avc_lru_hint = 0;
505 
506  /*
507  * SELinux allows to mmap(2) its kernel status page in read-only mode to
508  * inform userspace applications its status updating (such as policy
509  * reloading) without system-call invocations. This feature is only
510  * supported in Linux-2.6.38 or later, however, libselinux provides a
511  * fallback mode to know its status using netlink sockets.
512  */
513  rc = selinux_status_open(1);
514  if (rc < 0)
515  ereport(ERROR,
516  (errcode(ERRCODE_INTERNAL_ERROR),
517  errmsg("SELinux: could not open selinux status : %m")));
518  else if (rc > 0)
519  ereport(LOG,
520  (errmsg("SELinux: kernel status page uses fallback mode")));
521 
522  /* Arrange to close selinux status page on process exit. */
524 }
#define SEPGSQL_MODE_INTERNAL
Definition: sepgsql.h:30
static char * avc_unlabeled
Definition: uavc.c:62
#define AllocSetContextCreate
Definition: memutils.h:170
Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.c:148
bool permissive
Definition: uavc.c:42
char * ncontext
Definition: uavc.c:46
#define AVC_DEF_THRESHOLD
Definition: uavc.c:55
static uint32 sepgsql_avc_hash(const char *scontext, const char *tcontext, uint16 tclass)
Definition: uavc.c:68
void on_proc_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:305
static void sepgsql_avc_reset(void)
Definition: uavc.c:79
char * pstrdup(const char *in)
Definition: mcxt.c:1186
void sepgsql_compute_avd(const char *scontext, const char *tcontext, uint16 tclass, struct av_decision *avd)
Definition: selinux.c:730
Definition: uavc.c:31
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:570
bool sepgsql_getenforce(void)
Definition: selinux.c:648
static char * sepgsql_avc_unlabeled(void)
Definition: uavc.c:171
uint32 hash
Definition: uavc.c:33
#define AVC_NUM_RECLAIM
Definition: uavc.c:54
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 allowed
Definition: uavc.c:38
uint32 auditallow
Definition: uavc.c:39
static avc_cache * sepgsql_avc_lookup(const char *scontext, const char *tcontext, uint16 tclass)
Definition: uavc.c:301
#define LOG
Definition: elog.h:26
unsigned int Oid
Definition: postgres_ext.h:31
static avc_cache * sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass)
Definition: uavc.c:204
#define SEPGSQL_AVC_NOAUDIT
Definition: sepgsql.h:255
uint16 tclass
Definition: uavc.c:36
Definition: type.h:89
#define SEPG_CLASS_PROCESS
Definition: sepgsql.h:36
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:368
int sepgsql_get_mode(void)
Definition: selinux.c:622
unsigned short uint16
Definition: c.h:357
void pfree(void *pointer)
Definition: mcxt.c:1056
bool hot_cache
Definition: uavc.c:43
bool tcontext_is_valid
Definition: uavc.c:44
static MemoryContext avc_mem_cxt
Definition: uavc.c:57
#define ERROR
Definition: elog.h:43
void sepgsql_audit_log(bool denied, const char *scontext, const char *tcontext, uint16 tclass, uint32 audited, const char *audit_name)
Definition: selinux.c:675
char * GetSecurityLabel(const ObjectAddress *object, const char *provider)
Definition: seclabel.c:195
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
char * tcontext
Definition: uavc.c:35
bool sepgsql_get_debug_audit(void)
Definition: hooks.c:76
char * scontext
Definition: uavc.c:34
#define SEPG_CLASS_DB_PROCEDURE
Definition: sepgsql.h:48
void sepgsql_avc_init(void)
Definition: uavc.c:491
static void sepgsql_avc_exit(int code, Datum arg)
Definition: uavc.c:480
#define SEPGSQL_LABEL_TAG
Definition: sepgsql.h:23
unsigned int uint32
Definition: c.h:358
static int avc_lru_hint
Definition: uavc.c:60
char * sepgsql_avc_trusted_proc(Oid functionId)
Definition: uavc.c:448
#define ereport(elevel, rest)
Definition: elog.h:141
MemoryContext TopMemoryContext
Definition: mcxt.c:44
static int avc_num_caches
Definition: uavc.c:59
#define AVC_NUM_SLOTS
Definition: uavc.c:53
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
List * lcons(void *datum, List *list)
Definition: list.c:454
#define PG_CATCH()
Definition: elog.h:310
bool sepgsql_avc_check_perms(const ObjectAddress *tobject, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
Definition: uavc.c:423
#define lfirst(lc)
Definition: pg_list.h:190
static List * avc_slots[AVC_NUM_SLOTS]
Definition: uavc.c:58
static void sepgsql_avc_reclaim(void)
Definition: uavc.c:93
#define PG_RE_THROW()
Definition: elog.h:331
char * sepgsql_get_client_label(void)
Definition: label.c:82
static bool sepgsql_avc_check_valid(void)
Definition: uavc.c:153
uint32 auditdeny
Definition: uavc.c:40
char * sepgsql_compute_create(const char *scontext, const char *tcontext, uint16 tclass, const char *objname)
Definition: selinux.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
void * arg
#define PG_TRY()
Definition: elog.h:301
Definition: pg_list.h:50
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
bool sepgsql_avc_check_perms_label(const char *tcontext, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
Definition: uavc.c:341
#define PG_END_TRY()
Definition: elog.h:317
static int avc_threshold
Definition: uavc.c:61