int selinux_mkload_policy(int preservebools) { int kernvers = security_policyvers(); int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers; int setlocaldefs = load_setlocaldefs; char path[PATH_MAX]; struct stat sb; struct utsname uts; size_t size; void *map, *data; int fd, rc = -1, prot; sepol_policydb_t *policydb; sepol_policy_file_t *pf; int usesepol = 0; int (*vers_max)(void) = NULL; int (*vers_min)(void) = NULL; int (*policy_file_create)(sepol_policy_file_t **) = NULL; void (*policy_file_free)(sepol_policy_file_t *) = NULL; void (*policy_file_set_mem)(sepol_policy_file_t *, char*, size_t) = NULL; int (*policydb_create)(sepol_policydb_t **) = NULL; void (*policydb_free)(sepol_policydb_t *) = NULL; int (*policydb_read)(sepol_policydb_t *, sepol_policy_file_t *) = NULL; int (*policydb_set_vers)(sepol_policydb_t *, unsigned int) = NULL; int (*policydb_to_image)(sepol_handle_t *, sepol_policydb_t *, void **, size_t *) = NULL; int (*genbools_array)(void *data, size_t len, char **names, int *values, int nel) = NULL; int (*genusers)(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen) = NULL; int (*genbools)(void *data, size_t len, const char *boolpath) = NULL; #ifdef SHARED char *errormsg = NULL; void *libsepolh = NULL; libsepolh = dlopen("libsepol.so.1", RTLD_NOW); if (libsepolh) { usesepol = 1; dlerror(); #define DLERR() if ((errormsg = dlerror())) goto dlclose; vers_max = dlsym(libsepolh, "sepol_policy_kern_vers_max"); DLERR(); vers_min = dlsym(libsepolh, "sepol_policy_kern_vers_min"); DLERR(); policy_file_create = dlsym(libsepolh, "sepol_policy_file_create"); DLERR(); policy_file_free = dlsym(libsepolh, "sepol_policy_file_free"); DLERR(); policy_file_set_mem = dlsym(libsepolh, "sepol_policy_file_set_mem"); DLERR(); policydb_create = dlsym(libsepolh, "sepol_policydb_create"); DLERR(); policydb_free = dlsym(libsepolh, "sepol_policydb_free"); DLERR(); policydb_read = dlsym(libsepolh, "sepol_policydb_read"); DLERR(); policydb_set_vers = dlsym(libsepolh, "sepol_policydb_set_vers"); DLERR(); policydb_to_image = dlsym(libsepolh, "sepol_policydb_to_image"); DLERR(); genbools_array = dlsym(libsepolh, "sepol_genbools_array"); DLERR(); genusers = dlsym(libsepolh, "sepol_genusers"); DLERR(); genbools = dlsym(libsepolh, "sepol_genbools"); DLERR(); #undef DLERR } #else usesepol = 1; vers_max = sepol_policy_kern_vers_max; vers_min = sepol_policy_kern_vers_min; policy_file_create = sepol_policy_file_create; policy_file_free = sepol_policy_file_free; policy_file_set_mem = sepol_policy_file_set_mem; policydb_create = sepol_policydb_create; policydb_free = sepol_policydb_free; policydb_read = sepol_policydb_read; policydb_set_vers = sepol_policydb_set_vers; policydb_to_image = sepol_policydb_to_image; genbools_array = sepol_genbools_array; genusers = sepol_genusers; genbools = sepol_genbools; #endif /* * Check whether we need to support local boolean and user definitions. */ if (setlocaldefs) { if (access(selinux_booleans_path(), F_OK) == 0) goto checkbool; snprintf(path, sizeof path, "%s.local", selinux_booleans_path()); if (access(path, F_OK) == 0) goto checkbool; snprintf(path, sizeof path, "%s/local.users", selinux_users_path()); if (access(path, F_OK) == 0) goto checkbool; /* No local definition files, so disable setlocaldefs. */ setlocaldefs = 0; } checkbool: /* * As of Linux 2.6.22, the kernel preserves boolean * values across a reload, so we do not need to * preserve them in userspace. */ if (preservebools && uname(&uts) == 0 && strverscmp(uts.release, "2.6.22") >= 0) preservebools = 0; if (usesepol) { maxvers = vers_max(); minvers = vers_min(); if (!setlocaldefs && !preservebools) maxvers = max(kernvers, maxvers); } vers = maxvers; search: snprintf(path, sizeof(path), "%s.%d", selinux_binary_policy_path(), vers); fd = open(path, O_RDONLY | O_CLOEXEC); 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 | O_CLOEXEC); } if (fd < 0) { fprintf(stderr, "SELinux: Could not open policy file <= %s.%d: %s\n", selinux_binary_policy_path(), maxvers, strerror(errno)); goto dlclose; } if (fstat(fd, &sb) < 0) { fprintf(stderr, "SELinux: Could not stat policy file %s: %s\n", path, strerror(errno)); goto close; } prot = PROT_READ; if (setlocaldefs || preservebools) prot |= PROT_WRITE; 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)); goto close; } if (vers > kernvers && usesepol) { /* Need to downgrade to kernel-supported version. */ if (policy_file_create(&pf)) goto unmap; if (policydb_create(&policydb)) { policy_file_free(pf); goto unmap; } policy_file_set_mem(pf, data, size); if (policydb_read(policydb, pf)) { policy_file_free(pf); policydb_free(policydb); goto unmap; } if (policydb_set_vers(policydb, kernvers) || policydb_to_image(NULL, policydb, &data, &size)) { /* Downgrade failed, keep searching. */ fprintf(stderr, "SELinux: Could not downgrade policy file %s, searching for an older version.\n", path); policy_file_free(pf); policydb_free(policydb); munmap(map, sb.st_size); close(fd); vers--; goto search; } policy_file_free(pf); policydb_free(policydb); } if (usesepol) { if (setlocaldefs) { void *olddata = data; size_t oldsize = size; rc = genusers(olddata, oldsize, selinux_users_path(), &data, &size); if (rc < 0) { /* Fall back to the prior image if genusers failed. */ data = olddata; size = oldsize; rc = 0; } else { if (olddata != map) free(olddata); } } if (preservebools) { int *values, len, i; char **names; rc = security_get_boolean_names(&names, &len); if (!rc) { values = malloc(sizeof(int) * len); if (!values) { free(names); goto unmap; } for (i = 0; i < len; i++) values[i] = security_get_boolean_active(names[i]); (void)genbools_array(data, size, names, values, len); free(values); for (i = 0; i < len; i++) free(names[i]); free(names); } } else if (setlocaldefs) { (void)genbools(data, size, selinux_booleans_path()); } } rc = security_load_policy(data, size); if (rc) fprintf(stderr, "SELinux: Could not load policy file %s: %s\n", path, strerror(errno)); unmap: if (data != map) free(data); munmap(map, sb.st_size); close: close(fd); dlclose: #ifdef SHARED if (errormsg) fprintf(stderr, "libselinux: %s\n", errormsg); if (libsepolh) dlclose(libsepolh); #endif return rc; }
/* Compare S1 and S2 as strings holding indices/version numbers, returning less than, equal to or greater than zero if S1 is less than, equal to or greater than S2 (for more info, see the texinfo doc). */ int str_verscmp (const char *s1, const char *s2) { #ifdef HAVE_STRVERSCMP return strverscmp (s1, s2); #else /* HAVE_STRVERSCMP */ unsigned char *p1 = (unsigned char *) s1; unsigned char *p2 = (unsigned char *) s2; unsigned char c1, c2; int state; int diff; /* Symbol(s) 0 [1-9] others (padding) Transition (10) 0 (01) d (00) x (11) - */ static const unsigned int next_state[] = { /* state x d 0 - */ /* S_N */ S_N, S_I, S_Z, S_N, /* S_I */ S_N, S_I, S_I, S_I, /* S_F */ S_N, S_F, S_F, S_F, /* S_Z */ S_N, S_F, S_Z, S_Z }; static const int result_type[] = { /* state x/x x/d x/0 x/- d/x d/d d/0 d/- 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, /* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP, +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, /* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP, -1, CMP, CMP, CMP }; if (p1 == p2) return 0; c1 = *p1++; c2 = *p2++; /* Hint: '0' is a digit too. */ state = S_N | ((c1 == '0') + (isdigit (c1) != 0)); while ((diff = c1 - c2) == 0 && c1 != '\0') { state = next_state[state]; c1 = *p1++; c2 = *p2++; state |= (c1 == '0') + (isdigit (c1) != 0); } state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))]; switch (state) { case CMP: return diff; case LEN: while (isdigit (*p1++)) if (!isdigit (*p2++)) return 1; return isdigit (*p2) ? -1 : diff; default: return state; } #endif /* HAVE_STRVERSCMP */ }
static int can_sigio(void) { return strverscmp("2.6.37", uts.release) <= 0; }
static int version (const char **a, const char **b) { return strverscmp (*a, *b); }
/* * This is called once when selinux_restorecon() is first called. * Searches /proc/mounts for all file systems that do not support extended * attributes and adds them to the exclude directory table. File systems * that support security labels have the seclabel option, return * approximate total file count. */ static int exclude_non_seclabel_mounts(void) { struct utsname uts; FILE *fp; size_t len; ssize_t num; int index = 0, found = 0, nfile = 0; char *mount_info[4]; char *buf = NULL, *item; /* Check to see if the kernel supports seclabel */ if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) return 0; if (is_selinux_enabled() <= 0) return 0; fp = fopen("/proc/mounts", "re"); if (!fp) return 0; while ((num = getline(&buf, &len, fp)) != -1) { found = 0; index = 0; item = strtok(buf, " "); while (item != NULL) { mount_info[index] = item; index++; if (index == 4) break; item = strtok(NULL, " "); } if (index < 4) { selinux_log(SELINUX_ERROR, "/proc/mounts record \"%s\" has incorrect format.\n", buf); continue; } /* Remove pre-existing entry */ remove_exclude(mount_info[1]); item = strtok(mount_info[3], ","); while (item != NULL) { if (strcmp(item, "seclabel") == 0) { found = 1; nfile += file_system_count(mount_info[1]); break; } item = strtok(NULL, ","); } /* Exclude mount points without the seclabel option */ if (!found) { if (add_exclude(mount_info[1], !CALLER_EXCLUDED) && errno == ENOMEM) assert(0); } } free(buf); fclose(fp); /* return estimated #Files + 5% for directories and hard links */ return nfile * 1.05; }