int security_compute_av(const char * scon, const char * tcon, security_class_t tclass, access_vector_t requested, struct av_decision *avd) { struct av_decision lavd; int ret; ret = security_compute_av_flags(scon, tcon, tclass, requested, &lavd); if (ret == 0) { avd->allowed = lavd.allowed; avd->decided = lavd.decided; avd->auditallow = lavd.auditallow; avd->auditdeny = lavd.auditdeny; avd->seqno = lavd.seqno; /* NOTE: * We should not return avd->flags via the interface * due to the binary compatibility. */ } return ret; }
/* selinux_prepare_fork - Initialize context switching * * Returns * - 0 if everything is OK, * - +1 if the code should continue, even if SELinux wouldn't allow * (for instance due to permissive mode) * - -1 if the code should not continue */ int selinux_prepare_fork(char * name) { #ifndef SELINUX return 0; #else char * newcon = 0; char * curcon = 0; struct av_decision avd; int rc; int permissive = 0; int dom_permissive = 0; char * sename = 0; char * selevel = 0; /* * See if SELinux is enabled. * If not, then we can immediately tell the code * that everything is OK. */ rc = is_selinux_enabled(); if (rc == 0) { out(DEBUG, "SELinux is not enabled.\n"); return 0; } else if (rc == -1) { out(WARN, "Could not check SELinux state (is_selinux_enabled() failed)\n"); return 1; }; out(DEBUG, "SELinux is enabled.\n"); /* * See if SELinux is in enforcing mode * or permissive mode */ rc = security_getenforce(); if (rc == 0) { permissive = 1; } else if (rc == 1) { permissive = 0; } else { out(WARN, "Could not check SELinux mode (security_getenforce() failed)\n"); } out(DEBUG, "SELinux mode is %s\n", permissive ? "permissive" : "enforcing"); /* * Get the current SELinux context of the process. * Always interesting to log this for end users * trying to debug a possible issue. */ rc = getcon(&curcon); if (rc) { out(WARN, "Could not get current SELinux context (getcon() failed)\n"); if (permissive) return +1; else return -1; }; out(DEBUG, "Currently in SELinux context \"%s\"\n", (char *) curcon); /* * Get the SELinux user given the Linux user * name passed on to this function. */ rc = getseuserbyname(name, &sename, &selevel); if (rc) { out(WARN, "Could not find SELinux user for Linux user \"%s\" (getseuserbyname() failed)\n", name); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux user for Linux user \"%s\" is \"%s\"\n", name, sename); /* * Find out what the context is that this process should transition * to. */ rc = get_default_context(sename, NULL, &newcon); if (rc) { out(WARN, "Could not deduce default context for SELinux user \"%s\" given our current context (\"%s\")\n", sename, (char *) curcon); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux context to transition to is \"%s\"\n", (char *) newcon); /* * Now let's look if we are allowed to transition to the new context. * We currently only check the transition access for the process class. However, * transitioning is a bit more complex (execute rights on target context, * entrypoint of that context for the new domain, no constraints like target * domain not being a valid one, MLS constraints, etc.). */ rc = security_compute_av_flags(curcon, newcon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd); if (rc) { out(WARN, "Could not deduce rights for transitioning \"%s\" -> \"%s\" (security_compute_av_flags() failed)\n", (char *) curcon, (char *) newcon); freecon(curcon); freecon(newcon); if (permissive) return +1; else return -1; }; /* Validate the response * * We are interested in two things: * - Is the transition allowed, but also * - Is the permissive flag set * * If the permissive flag is set, then we * know the current domain is permissive * (even if the rest of the system is in * enforcing mode). */ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) { out(DEBUG, "The SELINUX_AVD_FLAGS_PERMISSIVE flag is set, so domain is permissive.\n"); dom_permissive = 1; }; if (!(avd.allowed & PROCESS__TRANSITION)) { // The transition is denied if (permissive) { out(DEBUG, "Transition is not allowed by SELinux, but permissive mode is enabled. Continuing.\n"); }; if (dom_permissive) { out(DEBUG, "Transition is not allowed by SELinux, but domain is in permissive mode. Continuing.\n"); }; if ((permissive == 0) && (dom_permissive == 0)) { out(WARN, "The domain transition is not allowed and we are not in permissive mode.\n"); freecon(curcon); freecon(newcon); return -1; }; }; /* * Set the context for the fork (process execution). */ rc = setexeccon(newcon); if (rc) { out(WARN, "Could not set execution context (setexeccon() failed)\n"); freecon(curcon); freecon(newcon); if ((permissive) || (dom_permissive)) return +1; else return -1; }; freecon(newcon); freecon(curcon); return 0; #endif };