1 /* -------------------------------------------------------------------------
3 * contrib/sepgsql/uavc.c
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.
9 * Copyright (c) 2011-2016, PostgreSQL Global Development Group
11 * -------------------------------------------------------------------------
15 #include "access/hash.h"
16 #include "catalog/pg_proc.h"
17 #include "commands/seclabel.h"
18 #include "storage/ipc.h"
19 #include "utils/guc.h"
20 #include "utils/memutils.h"
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.
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 */
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 */
42 bool permissive; /* true, if permissive rule */
43 bool hot_cache; /* true, if recently referenced */
44 bool tcontext_is_valid;
45 /* true, if tcontext is valid */
46 char *ncontext; /* temporary scontext on execution of trusted
47 * procedure, or NULL elsewhere */
51 * Declaration of static variables
53 #define AVC_NUM_SLOTS 512
54 #define AVC_NUM_RECLAIM 16
55 #define AVC_DEF_THRESHOLD 384
57 static MemoryContext avc_mem_cxt;
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 */
68 sepgsql_avc_hash(const char *scontext, const char *tcontext, uint16 tclass)
70 return hash_any((const unsigned char *) scontext, strlen(scontext))
71 ^ hash_any((const unsigned char *) tcontext, strlen(tcontext))
76 * Reset all the avc caches
79 sepgsql_avc_reset(void)
81 MemoryContextReset(avc_mem_cxt);
83 memset(avc_slots, 0, sizeof(List *) * AVC_NUM_SLOTS);
90 * Reclaim caches recently unreferenced
93 sepgsql_avc_reclaim(void)
100 while (avc_num_caches >= avc_threshold - AVC_NUM_RECLAIM)
102 index = avc_lru_hint;
105 for (cell = list_head(avc_slots[index]); cell; cell = next)
107 avc_cache *cache = lfirst(cell);
110 if (!cache->hot_cache)
113 = list_delete_cell(avc_slots[index], cell, prev);
115 pfree(cache->scontext);
116 pfree(cache->tcontext);
118 pfree(cache->ncontext);
125 cache->hot_cache = false;
129 avc_lru_hint = (avc_lru_hint + 1) % AVC_NUM_SLOTS;
133 /* -------------------------------------------------------------------------
135 * sepgsql_avc_check_valid
137 * This function checks whether the cached entries are still valid. If
138 * the security policy has been reloaded (or any other events that requires
139 * resetting userspace caches has occurred) since the last reference to
140 * the access vector cache, we must flush the cache.
142 * Access control decisions must be atomic, but multiple system calls may
143 * be required to make a decision; thus, when referencing the access vector
144 * cache, we must loop until we complete without an intervening cache flush
145 * event. In practice, looping even once should be very rare. Callers should
146 * do something like this:
148 * sepgsql_avc_check_valid();
151 * <reference to uavc>
153 * } while (!sepgsql_avc_check_valid())
155 * -------------------------------------------------------------------------
158 sepgsql_avc_check_valid(void)
160 if (selinux_status_updated() > 0)
170 * sepgsql_avc_unlabeled
172 * Returns an alternative label to be applied when no label or an invalid
173 * label would otherwise be assigned.
176 sepgsql_avc_unlabeled(void)
180 security_context_t unlabeled;
182 if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
184 (errcode(ERRCODE_INTERNAL_ERROR),
185 errmsg("SELinux: failed to get initial security label: %m")));
188 avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled);
199 return avc_unlabeled;
203 * sepgsql_avc_compute
205 * A fallback path, when cache mishit. It asks SELinux its access control
206 * decision for the supplied pair of security context and object class.
209 sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass)
211 char *ucontext = NULL;
212 char *ncontext = NULL;
213 MemoryContext oldctx;
217 struct av_decision avd;
219 hash = sepgsql_avc_hash(scontext, tcontext, tclass);
220 index = hash % AVC_NUM_SLOTS;
223 * Validation check of the supplied security context. Because it always
224 * invoke system-call, frequent check should be avoided. Unless security
225 * policy is reloaded, validation status shall be kept, so we also cache
226 * whether the supplied security context was valid, or not.
228 if (security_check_context_raw((security_context_t) tcontext) != 0)
229 ucontext = sepgsql_avc_unlabeled();
232 * Ask SELinux its access control decision
235 sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
237 sepgsql_compute_avd(scontext, ucontext, tclass, &avd);
240 * It also caches a security label to be switched when a client labeled as
241 * 'scontext' executes a procedure labeled as 'tcontext', not only access
242 * control decision on the procedure. The security label to be switched
243 * shall be computed uniquely on a pair of 'scontext' and 'tcontext',
244 * thus, it is reasonable to cache the new label on avc, and enables to
245 * reduce unnecessary system calls. It shall be referenced at
246 * sepgsql_needs_fmgr_hook to check whether the supplied function is a
247 * trusted procedure, or not.
249 if (tclass == SEPG_CLASS_DB_PROCEDURE)
252 ncontext = sepgsql_compute_create(scontext, tcontext,
253 SEPG_CLASS_PROCESS, NULL);
255 ncontext = sepgsql_compute_create(scontext, ucontext,
256 SEPG_CLASS_PROCESS, NULL);
257 if (strcmp(scontext, ncontext) == 0)
265 * Set up an avc_cache object
267 oldctx = MemoryContextSwitchTo(avc_mem_cxt);
269 cache = palloc0(sizeof(avc_cache));
272 cache->scontext = pstrdup(scontext);
273 cache->tcontext = pstrdup(tcontext);
274 cache->tclass = tclass;
276 cache->allowed = avd.allowed;
277 cache->auditallow = avd.auditallow;
278 cache->auditdeny = avd.auditdeny;
279 cache->hot_cache = true;
280 if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)
281 cache->permissive = true;
283 cache->tcontext_is_valid = true;
285 cache->ncontext = pstrdup(ncontext);
289 if (avc_num_caches > avc_threshold)
290 sepgsql_avc_reclaim();
292 avc_slots[index] = lcons(cache, avc_slots[index]);
294 MemoryContextSwitchTo(oldctx);
302 * Look up a cache entry that matches the supplied security contexts and
303 * object class. If not found, create a new cache entry.
306 sepgsql_avc_lookup(const char *scontext, const char *tcontext, uint16 tclass)
313 hash = sepgsql_avc_hash(scontext, tcontext, tclass);
314 index = hash % AVC_NUM_SLOTS;
316 foreach(cell, avc_slots[index])
318 cache = lfirst(cell);
320 if (cache->hash == hash &&
321 cache->tclass == tclass &&
322 strcmp(cache->tcontext, tcontext) == 0 &&
323 strcmp(cache->scontext, scontext) == 0)
325 cache->hot_cache = true;
329 /* not found, so insert a new cache */
330 return sepgsql_avc_compute(scontext, tcontext, tclass);
334 * sepgsql_avc_check_perms(_label)
336 * It returns 'true', if the security policy suggested to allow the required
337 * permissions. Otherwise, it returns 'false' or raises an error according
338 * to the 'abort_on_violation' argument.
339 * The 'tobject' and 'tclass' identify the target object being referenced,
340 * and 'required' is a bitmask of permissions (SEPG_*__*) defined for each
342 * The 'audit_name' is the object name (optional). If SEPGSQL_AVC_NOAUDIT
343 * was supplied, it means to skip all the audit messages.
346 sepgsql_avc_check_perms_label(const char *tcontext,
347 uint16 tclass, uint32 required,
348 const char *audit_name,
349 bool abort_on_violation)
351 char *scontext = sepgsql_get_client_label();
357 sepgsql_avc_check_valid();
363 * If the target object is unlabeled, we perform the check using the
364 * label supplied by sepgsql_avc_unlabeled().
367 cache = sepgsql_avc_lookup(scontext, tcontext, tclass);
369 cache = sepgsql_avc_lookup(scontext,
370 sepgsql_avc_unlabeled(), tclass);
372 denied = required & ~cache->allowed;
375 * Compute permissions to be audited
377 if (sepgsql_get_debug_audit())
378 audited = (denied ? (denied & ~0) : (required & ~0));
380 audited = denied ? (denied & cache->auditdeny)
381 : (required & cache->auditallow);
386 * In permissive mode or permissive domain, violated permissions
387 * shall be audited to the log files at once, and then implicitly
388 * allowed to avoid a flood of access denied logs, because the
389 * purpose of permissive mode/domain is to collect a violation log
390 * that will make it possible to fix up the security policy.
392 if (!sepgsql_getenforce() || cache->permissive)
393 cache->allowed |= required;
397 } while (!sepgsql_avc_check_valid());
400 * In the case when we have something auditable actions here,
401 * sepgsql_audit_log shall be called with text representation of security
402 * labels for both of subject and object. It records this access
403 * violation, so DBA will be able to find out unexpected security problems
407 audit_name != SEPGSQL_AVC_NOAUDIT &&
408 sepgsql_get_mode() != SEPGSQL_MODE_INTERNAL)
410 sepgsql_audit_log(denied != 0,
412 cache->tcontext_is_valid ?
413 cache->tcontext : sepgsql_avc_unlabeled(),
419 if (abort_on_violation && !result)
421 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
422 errmsg("SELinux: security policy violation")));
428 sepgsql_avc_check_perms(const ObjectAddress *tobject,
429 uint16 tclass, uint32 required,
430 const char *audit_name,
431 bool abort_on_violation)
433 char *tcontext = GetSecurityLabel(tobject, SEPGSQL_LABEL_TAG);
436 rc = sepgsql_avc_check_perms_label(tcontext,
438 audit_name, abort_on_violation);
446 * sepgsql_avc_trusted_proc
448 * If the supplied function OID is configured as a trusted procedure, this
449 * function will return a security label to be used during the execution of
450 * that function. Otherwise, it returns NULL.
453 sepgsql_avc_trusted_proc(Oid functionId)
455 char *scontext = sepgsql_get_client_label();
457 ObjectAddress tobject;
460 tobject.classId = ProcedureRelationId;
461 tobject.objectId = functionId;
462 tobject.objectSubId = 0;
463 tcontext = GetSecurityLabel(&tobject, SEPGSQL_LABEL_TAG);
465 sepgsql_avc_check_valid();
469 cache = sepgsql_avc_lookup(scontext, tcontext,
470 SEPG_CLASS_DB_PROCEDURE);
472 cache = sepgsql_avc_lookup(scontext, sepgsql_avc_unlabeled(),
473 SEPG_CLASS_DB_PROCEDURE);
474 } while (!sepgsql_avc_check_valid());
476 return cache->ncontext;
482 * Clean up userspace AVC on process exit.
485 sepgsql_avc_exit(int code, Datum arg)
487 selinux_status_close();
493 * Initialize the userspace AVC. This should be called from _PG_init.
496 sepgsql_avc_init(void)
501 * All the avc stuff shall be allocated in avc_mem_cxt
503 avc_mem_cxt = AllocSetContextCreate(TopMemoryContext,
504 "userspace access vector cache",
505 ALLOCSET_DEFAULT_SIZES);
506 memset(avc_slots, 0, sizeof(avc_slots));
509 avc_threshold = AVC_DEF_THRESHOLD;
512 * SELinux allows to mmap(2) its kernel status page in read-only mode to
513 * inform userspace applications its status updating (such as policy
514 * reloading) without system-call invocations. This feature is only
515 * supported in Linux-2.6.38 or later, however, libselinux provides a
516 * fallback mode to know its status using netlink sockets.
518 rc = selinux_status_open(1);
521 (errcode(ERRCODE_INTERNAL_ERROR),
522 errmsg("SELinux: could not open selinux status : %m")));
525 (errmsg("SELinux: kernel status page uses fallback mode")));
527 /* Arrange to close selinux status page on process exit. */
528 on_proc_exit(sepgsql_avc_exit, 0);