diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index a4079aa..aba6e33 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -498,7 +498,9 @@ extern const char *selinux_policy_root(void); /* These functions return the paths to specific files under the policy root directory. */ +extern const char *selinux_current_policy_path(void); extern const char *selinux_binary_policy_path(void); +extern char *selinux_binary_policy_path_min_max(int min, int *max); extern const char *selinux_failsafe_context_path(void); extern const char *selinux_removable_context_path(void); extern const char *selinux_default_context_path(void); diff --git a/libselinux/man/man3/selinux_binary_policy_path.3 b/libselinux/man/man3/selinux_binary_policy_path.3 index ec97dcf..68f8fdf 100644 --- a/libselinux/man/man3/selinux_binary_policy_path.3 +++ b/libselinux/man/man3/selinux_binary_policy_path.3 @@ -17,6 +17,8 @@ directories and files .sp .B const char *selinux_binary_policy_path(void); .sp +.B const char *selinux_current_policy_path(void); +.sp .B const char *selinux_failsafe_context_path(void); .sp .B const char *selinux_removable_context_path(void); @@ -52,8 +54,11 @@ returns the top-level SELinux configuration directory. .BR selinux_policy_root () returns the top-level policy directory. .sp +.BR selinux_current_policy_path() +returns the binary policy file loaded into the kernel +.sp .BR selinux_binary_policy_path () -returns the binary policy file loaded into kernel. +returns the binary policy file on disk .sp .BR selinux_default_type_path () returns the context file mapping roles to default types. diff --git a/libselinux/src/audit2why.c b/libselinux/src/audit2why.c index ffe381b..73c07aa 100644 --- a/libselinux/src/audit2why.c +++ b/libselinux/src/audit2why.c @@ -191,49 +191,24 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) static int __policy_init(const char *init_path) { FILE *fp; - int vers = 0; - char path[PATH_MAX]; + const char *path; char errormsg[PATH_MAX]; struct sepol_policy_file *pf = NULL; int rc; unsigned int cnt; - path[PATH_MAX-1] = '\0'; - if (init_path) { - strncpy(path, init_path, PATH_MAX-1); - fp = fopen(path, "r"); - if (!fp) { - snprintf(errormsg, sizeof(errormsg), - "unable to open %s: %s\n", - path, strerror(errno)); - PyErr_SetString( PyExc_ValueError, errormsg); - return 1; - } - } else { - vers = sepol_policy_kern_vers_max(); - if (vers < 0) { - snprintf(errormsg, sizeof(errormsg), - "Could not get policy version: %s\n", - strerror(errno)); - PyErr_SetString( PyExc_ValueError, errormsg); - return 1; - } - snprintf(path, PATH_MAX, "%s.%d", - selinux_binary_policy_path(), vers); - fp = fopen(path, "r"); - while (!fp && errno == ENOENT && --vers) { - snprintf(path, PATH_MAX, "%s.%d", - selinux_binary_policy_path(), vers); - fp = fopen(path, "r"); - } - if (!fp) { - snprintf(errormsg, sizeof(errormsg), - "unable to open %s.%d: %s\n", - selinux_binary_policy_path(), - security_policyvers(), strerror(errno)); - PyErr_SetString( PyExc_ValueError, errormsg); - return 1; - } + if (init_path) + path = init_path; + else + path = selinux_current_policy_path(); + + fp = fopen(path, "r"); + if (!fp) { + snprintf(errormsg, sizeof(errormsg), + "unable to open %s: %s\n", + path, strerror(errno)); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; } avc = calloc(sizeof(struct avc_t), 1); @@ -310,10 +285,12 @@ static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { } #define RETURN(X) \ - PyTuple_SetItem(result, 0, Py_BuildValue("i", X)); \ - return result; + { \ + return Py_BuildValue("iO", (X), Py_None); \ + } static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { + char *reason_buf = NULL; security_context_t scon; security_context_t tcon; char *tclassstr; @@ -328,10 +305,6 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args struct sepol_av_decision avd; int rc; int i=0; - PyObject *result = PyTuple_New(2); - if (!result) return NULL; - Py_INCREF(Py_None); - PyTuple_SetItem(result, 1, Py_None); if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) return NULL; @@ -342,22 +315,21 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args /* should raise an error here. */ if (numlines < 0) return NULL; /* Not a list */ - if (!avc) { + if (!avc) RETURN(NOPOLICY) - } rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); - if (rc < 0) { + if (rc < 0) RETURN(BADSCON) - } + rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); - if (rc < 0) { + if (rc < 0) RETURN(BADTCON) - } + tclass = string_to_security_class(tclassstr); - if (!tclass) { + if (!tclass) RETURN(BADTCLASS) - } + /* Convert the permission list to an AV. */ av = 0; @@ -377,21 +349,20 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args #endif perm = string_to_av_perm(tclass, permstr); - if (!perm) { + if (!perm) RETURN(BADPERM) - } + av |= perm; } /* Reproduce the computation. */ - rc = sepol_compute_av_reason(ssid, tsid, tclass, av, &avd, &reason); - if (rc < 0) { + rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0); + if (rc < 0) RETURN(BADCOMPUTE) - } - if (!reason) { + if (!reason) RETURN(ALLOW) - } + if (reason & SEPOL_COMPUTEAV_TE) { avc->ssid = ssid; avc->tsid = tsid; @@ -404,28 +375,34 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args RETURN(TERULE) } } else { - PyTuple_SetItem(result, 0, Py_BuildValue("i", BOOLEAN)); + PyObject *outboollist; struct boolean_t *b = bools; int len=0; while (b->name) { len++; b++; } b = bools; - PyObject *outboollist = PyTuple_New(len); + outboollist = PyList_New(len); len=0; while(b->name) { - PyObject *bool = Py_BuildValue("(si)", b->name, b->active); - PyTuple_SetItem(outboollist, len++, bool); + PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); + PyList_SetItem(outboollist, len++, bool_); b++; } free(bools); - PyTuple_SetItem(result, 1, outboollist); - return result; + /* 'N' steals the reference to outboollist */ + return Py_BuildValue("iN", BOOLEAN, outboollist); } } if (reason & SEPOL_COMPUTEAV_CONS) { - RETURN(CONSTRAINT); + if (reason_buf) { + PyObject *result = NULL; + result = Py_BuildValue("is", CONSTRAINT, reason_buf); + free(reason_buf); + return result; + } + RETURN(CONSTRAINT) } if (reason & SEPOL_COMPUTEAV_RBAC) diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c index 802a07f..6ff83a7 100644 --- a/libselinux/src/avc.c +++ b/libselinux/src/avc.c @@ -827,6 +827,7 @@ int avc_has_perm(security_id_t ssid, security_id_t tsid, errsave = errno; avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); errno = errsave; + if (!avc_enforcing) return 0; return rc; } diff --git a/libselinux/src/get_context_list.c b/libselinux/src/get_context_list.c index b9e8002..355730a 100644 --- a/libselinux/src/get_context_list.c +++ b/libselinux/src/get_context_list.c @@ -426,7 +426,7 @@ int get_ordered_context_list(const char *user, /* Initialize ordering array. */ ordering = malloc(nreach * sizeof(unsigned int)); if (!ordering) - goto oom_order; + goto failsafe; for (i = 0; i < nreach; i++) ordering[i] = nreach; @@ -435,7 +435,7 @@ int get_ordered_context_list(const char *user, fname_len = strlen(user_contexts_path) + strlen(user) + 2; fname = malloc(fname_len); if (!fname) - goto oom_order; + goto failsafe; snprintf(fname, fname_len, "%s%s", user_contexts_path, user); fp = fopen(fname, "r"); if (fp) { @@ -465,31 +465,28 @@ int get_ordered_context_list(const char *user, } } + if (!nordered) + goto failsafe; + /* Apply the ordering. */ - if (nordered) { - co = malloc(nreach * sizeof(struct context_order)); - if (!co) - goto oom_order; - for (i = 0; i < nreach; i++) { - co[i].con = reachable[i]; - co[i].order = ordering[i]; - } - qsort(co, nreach, sizeof(struct context_order), order_compare); - for (i = 0; i < nreach; i++) - reachable[i] = co[i].con; - free(co); + co = malloc(nreach * sizeof(struct context_order)); + if (!co) + goto failsafe; + for (i = 0; i < nreach; i++) { + co[i].con = reachable[i]; + co[i].order = ordering[i]; } + qsort(co, nreach, sizeof(struct context_order), order_compare); + for (i = 0; i < nreach; i++) + reachable[i] = co[i].con; + free(co); - /* Return the ordered list. - If we successfully ordered it, then only report the ordered entries - to the caller. Otherwise, fall back to the entire reachable list. */ - if (nordered && nordered < nreach) { + /* Only report the ordered entries to the caller. */ + if (nordered < nreach) { for (i = nordered; i < nreach; i++) free(reachable[i]); reachable[nordered] = NULL; rc = nordered; - } else { - rc = nreach; } out: @@ -523,14 +520,6 @@ int get_ordered_context_list(const char *user, } rc = 1; /* one context in the list */ goto out; - - oom_order: - /* Unable to order context list due to OOM condition. - Fall back to unordered reachable context list. */ - fprintf(stderr, "%s: out of memory, unable to order list\n", - __FUNCTION__); - rc = nreach; - goto out; } hidden_def(get_ordered_context_list) diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c index 10e29b9..888dab5 100644 --- a/libselinux/src/load_policy.c +++ b/libselinux/src/load_policy.c @@ -49,8 +49,9 @@ int load_setlocaldefs hidden = 1; int selinux_mkload_policy(int preservebools) { int kernvers = security_policyvers(); - int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers; + int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION; int setlocaldefs = load_setlocaldefs; + char *pol_path = NULL; char path[PATH_MAX]; struct stat sb; struct utsname uts; @@ -162,29 +163,24 @@ checkbool: maxvers = max(kernvers, maxvers); } - vers = maxvers; - search: - snprintf(path, sizeof(path), "%s.%d", - selinux_binary_policy_path(), vers); - fd = open(path, O_RDONLY); - while (fd < 0 && errno == ENOENT - && --vers >= minvers) { - /* Check prior versions to see if old policy is available */ - snprintf(path, sizeof(path), "%s.%d", - selinux_binary_policy_path(), vers); - fd = open(path, O_RDONLY); +search: + pol_path = selinux_binary_policy_path_min_max(minvers, &maxvers); + if (!pol_path) { + fprintf(stderr, "SELinux: unable to find usable policy file: %s\n", + strerror(errno)); + goto dlclose; } + + fd = open(pol_path, O_RDONLY); if (fd < 0) { - fprintf(stderr, - "SELinux: Could not open policy file <= %s.%d: %s\n", - selinux_binary_policy_path(), maxvers, strerror(errno)); + fprintf(stderr, "SELinux: Could not open policy file %s: %s\n", + pol_path, strerror(errno)); goto dlclose; } if (fstat(fd, &sb) < 0) { - fprintf(stderr, - "SELinux: Could not stat policy file %s: %s\n", - path, strerror(errno)); + fprintf(stderr, "SELinux: Could not stat policy file %s: %s\n", + pol_path, strerror(errno)); goto close; } @@ -195,13 +191,12 @@ checkbool: size = sb.st_size; data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { - fprintf(stderr, - "SELinux: Could not map policy file %s: %s\n", - path, strerror(errno)); + fprintf(stderr, "SELinux: Could not map policy file %s: %s\n", + pol_path, strerror(errno)); goto close; } - if (vers > kernvers && usesepol) { + if (maxvers > kernvers && usesepol) { /* Need to downgrade to kernel-supported version. */ if (policy_file_create(&pf)) goto unmap; @@ -220,12 +215,12 @@ checkbool: /* Downgrade failed, keep searching. */ fprintf(stderr, "SELinux: Could not downgrade policy file %s, searching for an older version.\n", - path); + pol_path); policy_file_free(pf); policydb_free(policydb); munmap(map, sb.st_size); close(fd); - vers--; + maxvers--; goto search; } policy_file_free(pf); @@ -281,7 +276,7 @@ checkbool: if (rc) fprintf(stderr, "SELinux: Could not load policy file %s: %s\n", - path, strerror(errno)); + pol_path, strerror(errno)); unmap: if (data != map) @@ -296,6 +291,7 @@ checkbool: if (libsepolh) dlclose(libsepolh); #endif + free(pol_path); return rc; } diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c index 2d7369e..2a00807 100644 --- a/libselinux/src/matchpathcon.c +++ b/libselinux/src/matchpathcon.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "selinux_internal.h" #include "label_internal.h" #include "callbacks.h" @@ -62,7 +63,7 @@ static void { va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + vsyslog(LOG_ERR, fmt, ap); va_end(ap); } diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c index 296f357..cb65666 100644 --- a/libselinux/src/selinux_config.c +++ b/libselinux/src/selinux_config.c @@ -9,6 +9,7 @@ #include #include #include "selinux_internal.h" +#include "policy.h" #include "get_default_type_internal.h" #define SELINUXDIR "/etc/selinux/" @@ -296,13 +297,57 @@ const char *selinux_removable_context_path(void) hidden_def(selinux_removable_context_path) +char *selinux_binary_policy_path_min_max(int min, int *max) +{ + int ret; + char *path = NULL; + + while(*max >= min) { + ret = asprintf(&path, "%s.%d", get_path(BINPOLICY), *max); + if (ret < 0) + goto err; + ret = access(path, R_OK); + if (!ret) + return path; + free(path); + path = NULL; + *max = *max - 1; + } +err: + free(path); + return NULL; +} +hidden_def(selinux_binary_policy_path_min_max) + const char *selinux_binary_policy_path(void) { return get_path(BINPOLICY); } - hidden_def(selinux_binary_policy_path) +const char *selinux_current_policy_path(void) +{ + int rc = 0; + int vers = 0; + static char policy_path[PATH_MAX]; + + snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt); + if (access(policy_path, F_OK) != 0 ) { + vers = security_policyvers(); + do { + /* Check prior versions to see if old policy is available */ + snprintf(policy_path, sizeof(policy_path), "%s.%d", + selinux_binary_policy_path(), vers); + } while ((rc = access(policy_path, F_OK)) && --vers > 0); + + if (rc) return NULL; + } + + return policy_path; +} + +hidden_def(selinux_current_policy_path) + const char *selinux_file_context_path(void) { return get_path(FILE_CONTEXTS); diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index 2c7c85c..008aa6d 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -61,7 +61,9 @@ hidden_proto(selinux_mkload_policy) hidden_proto(security_deny_unknown) hidden_proto(selinux_boolean_sub) hidden_proto(selinux_binary_policy_path) + hidden_proto(selinux_binary_policy_path_min_max) hidden_proto(selinux_booleans_subs_path) + hidden_proto(selinux_current_policy_path) hidden_proto(selinux_default_context_path) hidden_proto(selinux_securetty_types_path) hidden_proto(selinux_failsafe_context_path)