static int check_dominance(const char *pattern, const char *raw) { security_context_t ctx; context_t con; struct av_decision avd; int rc = -1; context_t my_tmp; const char *raw_range; security_class_t context_class = string_to_security_class("context"); access_vector_t context_contains_perm = string_to_av_perm(context_class, "contains"); con = context_new(raw); if (!con) return -1; raw_range = context_range_get(con); my_tmp = context_new(my_context); if (!my_tmp) { context_free(con); return -1; } ctx = NULL; if (context_range_set(my_tmp, pattern)) goto out; ctx = strdup(context_str(my_tmp)); if (!ctx) goto out; if (context_range_set(my_tmp, raw_range)) goto out; raw = context_str(my_tmp); if (!raw) goto out; rc = security_compute_av_raw(ctx, (security_context_t)raw, context_class, context_contains_perm, &avd); if (rc) goto out; rc = (context_contains_perm & avd.allowed) != context_contains_perm; out: free(ctx); context_free(my_tmp); context_free(con); return rc; }
int within_range(security_context_t sl, security_context_t range) { int rtn = 1; security_id_t slsid; security_id_t rangesid; struct av_decision avd; security_class_t tclass; access_vector_t av; if (!selinux_ready) { /* mls may not be enabled */ dbg("selinux check failed"); return 0; } /* * * Get the sids for the sl and range contexts */ rtn = avc_context_to_sid(sl, &slsid); if (rtn != 0) { dbg("within_range: Unable to retrieve sid for sl context (%s)", sl); return 0; } rtn = avc_context_to_sid(range, &rangesid); if (rtn != 0) { dbg("within_range: Unable to retrieve sid for range context (%s)", range); sidput(slsid); return 0; } /* ** Straight up test between sl and range **/ tclass = string_to_security_class("association"); av = string_to_av_perm(tclass, "polmatch"); rtn = avc_has_perm(slsid, rangesid, tclass, av, NULL, &avd); if (rtn != 0) { dbg("within_range: The sl (%s) is not within range of (%s)", sl, range); sidput(slsid); sidput(rangesid); return 0; } dbg("within_range: The sl (%s) is within range of (%s)", sl, range); return 1; }
int selinux_set_mapping(struct security_class_mapping *map) { size_t size = sizeof(struct selinux_mapping); security_class_t i, j; unsigned k; free(current_mapping); current_mapping = NULL; current_mapping_size = 0; if (avc_reset() < 0) goto err; /* Find number of classes in the input mapping */ if (!map) { errno = EINVAL; goto err; } i = 0; while (map[i].name) i++; /* Allocate space for the class records, plus one for class zero */ current_mapping = (struct selinux_mapping *)calloc(++i, size); if (!current_mapping) goto err; /* Store the raw class and permission values */ j = 0; while (map[j].name) { struct security_class_mapping *p_in = map + (j++); struct selinux_mapping *p_out = current_mapping + j; p_out->value = string_to_security_class(p_in->name); if (!p_out->value) goto err2; k = 0; while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) { k++; continue; } p_out->perms[k] = string_to_av_perm(p_out->value, p_in->perms[k]); if (!p_out->perms[k]) goto err2; k++; } p_out->num_perms = k; } /* Set the mapping size here so the above lookups are "raw" */ current_mapping_size = i; return 0; err2: free(current_mapping); current_mapping = NULL; current_mapping_size = 0; err: return -1; }
/* * sepgsql_compute_avd * * It actually asks SELinux what permissions are allowed on a pair of * the security contexts and object class. It also returns what permissions * should be audited on access violation or allowed. * In most cases, subject's security context (scontext) is a client, and * target security context (tcontext) is a database object. * * The access control decision shall be set on the given av_decision. * The av_decision.allowed has a bitmask of SEPG_<class>__<perms> * to suggest a set of allowed actions in this object class. */ void sepgsql_compute_avd(const char *scontext, const char *tcontext, uint16 tclass, struct av_decision *avd) { const char *tclass_name; security_class_t tclass_ex; struct av_decision avd_ex; int i, deny_unknown = security_deny_unknown(); /* Get external code of the object class*/ Assert(tclass < SEPG_CLASS_MAX); Assert(tclass == selinux_catalog[tclass].class_code); tclass_name = selinux_catalog[tclass].class_name; tclass_ex = string_to_security_class(tclass_name); if (tclass_ex == 0) { /* * If the current security policy does not support permissions * corresponding to database objects, we fill up them with dummy * data. * If security_deny_unknown() returns positive value, undefined * permissions should be denied. Otherwise, allowed */ avd->allowed = (security_deny_unknown() > 0 ? 0 : ~0); avd->auditallow = 0U; avd->auditdeny = ~0U; avd->flags = 0; return; } /* * Ask SELinux what is allowed set of permissions on a pair of the * security contexts and the given object class. */ if (security_compute_av_flags_raw((security_context_t)scontext, (security_context_t)tcontext, tclass_ex, 0, &avd_ex) < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SELinux could not compute av_decision: " "scontext=%s tcontext=%s tclass=%s", scontext, tcontext, tclass_name))); /* * SELinux returns its access control decision as a set of permissions * represented in external code which depends on run-time environment. * So, we need to translate it to the internal representation before * returning results for the caller. */ memset(avd, 0, sizeof(struct av_decision)); for (i=0; selinux_catalog[tclass].av[i].av_name; i++) { access_vector_t av_code_ex; const char *av_name = selinux_catalog[tclass].av[i].av_name; uint32 av_code = selinux_catalog[tclass].av[i].av_code; av_code_ex = string_to_av_perm(tclass_ex, av_name); if (av_code_ex == 0) { /* fill up undefined permissions */ if (!deny_unknown) avd->allowed |= av_code; avd->auditdeny |= av_code; continue; } if (avd_ex.allowed & av_code_ex) avd->allowed |= av_code; if (avd_ex.auditallow & av_code_ex) avd->auditallow |= av_code; if (avd_ex.auditdeny & av_code_ex) avd->auditdeny |= av_code; } return; }
/* Check the permission from the caller (via getpeercon) to nscd. Returns 0 if access is allowed, 1 if denied, and -1 on error. The SELinux policy, enablement, and permission bits are all dynamic and the caching done by glibc is not entirely correct. This nscd support should be rewritten to use selinux_check_permission. A rewrite is risky though and requires some refactoring. Currently we use symbolic mappings instead of compile time constants (which SELinux upstream says are going away), and we use security_deny_unknown to determine what to do if selinux-policy* doesn't have a definition for the the permission or object class we are looking up. */ int nscd_request_avc_has_perm (int fd, request_type req) { /* Initialize to NULL so we know what to free in case of failure. */ security_context_t scon = NULL; security_context_t tcon = NULL; security_id_t ssid = NULL; security_id_t tsid = NULL; int rc = -1; security_class_t sc_nscd; access_vector_t perm; int avc_deny_unknown; /* Check if SELinux denys or allows unknown object classes and permissions. It is 0 if they are allowed, 1 if they are not allowed and -1 on error. */ if ((avc_deny_unknown = security_deny_unknown ()) == -1) dbg_log (_("Error querying policy for undefined object classes " "or permissions.")); /* Get the security class for nscd. If this fails we will likely be unable to do anything unless avc_deny_unknown is 0. */ sc_nscd = string_to_security_class ("nscd"); if (sc_nscd == 0 && avc_deny_unknown == 1) dbg_log (_("Error getting security class for nscd.")); /* Convert permission to AVC bits. */ perm = string_to_av_perm (sc_nscd, perms[req]); if (perm == 0 && avc_deny_unknown == 1) dbg_log (_("Error translating permission name " "\"%s\" to access vector bit."), perms[req]); /* If the nscd security class was not found or perms were not found and AVC does not deny unknown values then allow it. */ if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0) return 0; if (getpeercon (fd, &scon) < 0) { dbg_log (_("Error getting context of socket peer")); goto out; } if (getcon (&tcon) < 0) { dbg_log (_("Error getting context of nscd")); goto out; } if (avc_context_to_sid (scon, &ssid) < 0 || avc_context_to_sid (tcon, &tsid) < 0) { dbg_log (_("Error getting sid from context")); goto out; } /* The SELinux API for avc_has_perm conflates access denied and error into the return code -1, while nscd_request_avs_has_perm has distinct error (-1) and denied (1) return codes. We map the avc_has_perm access denied or error into an access denied at the nscd interface level (we do accurately report error for the getpeercon, getcon, and avc_context_to_sid interfaces used above). */ rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0; out: if (scon) freecon (scon); if (tcon) freecon (tcon); if (ssid) sidput (ssid); if (tsid) sidput (tsid); return rc; }
int selinux_set_mapping(struct security_class_mapping *map) { size_t size = sizeof(struct selinux_mapping); security_class_t i, j; unsigned k; bool print_unknown_handle = false; bool reject = (security_reject_unknown() == 1); bool deny = (security_deny_unknown() == 1); free(current_mapping); current_mapping = NULL; current_mapping_size = 0; if (avc_reset() < 0) goto err; /* Find number of classes in the input mapping */ if (!map) { errno = EINVAL; goto err; } i = 0; while (map[i].name) i++; /* Allocate space for the class records, plus one for class zero */ current_mapping = (struct selinux_mapping *)calloc(++i, size); if (!current_mapping) goto err; /* Store the raw class and permission values */ j = 0; while (map[j].name) { struct security_class_mapping *p_in = map + (j++); struct selinux_mapping *p_out = current_mapping + j; p_out->value = string_to_security_class(p_in->name); if (!p_out->value) { selinux_log(SELINUX_INFO, "SELinux: Class %s not defined in policy.\n", p_in->name); if (reject) goto err2; p_out->num_perms = 0; print_unknown_handle = true; continue; } k = 0; while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) { k++; continue; } p_out->perms[k] = string_to_av_perm(p_out->value, p_in->perms[k]); if (!p_out->perms[k]) { selinux_log(SELINUX_INFO, "SELinux: Permission %s in class %s not defined in policy.\n", p_in->perms[k], p_in->name); if (reject) goto err2; print_unknown_handle = true; } k++; } p_out->num_perms = k; } if (print_unknown_handle) selinux_log(SELINUX_INFO, "SELinux: the above unknown classes and permissions will be %s\n", deny ? "denied" : "allowed"); /* Set the mapping size here so the above lookups are "raw" */ current_mapping_size = i; return 0; err2: free(current_mapping); current_mapping = NULL; current_mapping_size = 0; err: return -1; }
static int mavc_cb_policyload(int seqno) { security_class_t tclass; pthread_rwlock_wrlock(&permissions.lock); tclass = string_to_security_class("kv_item"); permissions.tclass = tclass; permissions.create = string_to_av_perm(tclass, "create"); permissions.getattr = string_to_av_perm(tclass, "getattr"); permissions.setattr = string_to_av_perm(tclass, "setattr"); permissions.remove = string_to_av_perm(tclass, "remove"); permissions.read = string_to_av_perm(tclass, "read"); permissions.write = string_to_av_perm(tclass, "write"); permissions.append = string_to_av_perm(tclass, "append"); permissions.calculate = string_to_av_perm(tclass, "calculate"); permissions.relabelfrom = string_to_av_perm(tclass, "relabelfrom") | string_to_av_perm(tclass, "setattr"); permissions.relabelto = string_to_av_perm(tclass, "relabelto"); pthread_rwlock_unlock(&permissions.lock); return 0; }