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