Home | History | Annotate | Download | only in src
      1 #include <unistd.h>
      2 #include <sys/types.h>
      3 #include <sys/stat.h>
      4 #include <sys/mman.h>
      5 #include <sys/mount.h>
      6 #include <sys/utsname.h>
      7 #include <fcntl.h>
      8 #include <stdlib.h>
      9 #include <stdio.h>
     10 #include <ctype.h>
     11 #include <string.h>
     12 #include <errno.h>
     13 #include "selinux_internal.h"
     14 #ifndef ANDROID
     15 #include <sepol/sepol.h>
     16 #include <sepol/policydb.h>
     17 #endif
     18 #include <dlfcn.h>
     19 #include "policy.h"
     20 #include <limits.h>
     21 
     22 #ifndef MNT_DETACH
     23 #define MNT_DETACH 2
     24 #endif
     25 
     26 int security_load_policy(void *data, size_t len)
     27 {
     28 	char path[PATH_MAX];
     29 	int fd, ret;
     30 
     31 	if (!selinux_mnt) {
     32 		errno = ENOENT;
     33 		return -1;
     34 	}
     35 
     36 	snprintf(path, sizeof path, "%s/load", selinux_mnt);
     37 	fd = open(path, O_RDWR | O_CLOEXEC);
     38 	if (fd < 0)
     39 		return -1;
     40 
     41 	ret = write(fd, data, len);
     42 	close(fd);
     43 	if (ret < 0)
     44 		return -1;
     45 	return 0;
     46 }
     47 
     48 hidden_def(security_load_policy)
     49 
     50 #ifndef ANDROID
     51 int load_setlocaldefs hidden = 1;
     52 
     53 #undef max
     54 #define max(a, b) (((a) > (b)) ? (a) : (b))
     55 
     56 int selinux_mkload_policy(int preservebools)
     57 {
     58 	int kernvers = security_policyvers();
     59 	int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers;
     60 	int setlocaldefs = load_setlocaldefs;
     61 	char path[PATH_MAX];
     62 	struct stat sb;
     63 	struct utsname uts;
     64 	size_t size;
     65 	void *map, *data;
     66 	int fd, rc = -1, prot;
     67 	sepol_policydb_t *policydb;
     68 	sepol_policy_file_t *pf;
     69 	int usesepol = 0;
     70 	int (*vers_max)(void) = NULL;
     71 	int (*vers_min)(void) = NULL;
     72 	int (*policy_file_create)(sepol_policy_file_t **) = NULL;
     73 	void (*policy_file_free)(sepol_policy_file_t *) = NULL;
     74 	void (*policy_file_set_mem)(sepol_policy_file_t *, char*, size_t) = NULL;
     75 	int (*policydb_create)(sepol_policydb_t **) = NULL;
     76 	void (*policydb_free)(sepol_policydb_t *) = NULL;
     77 	int (*policydb_read)(sepol_policydb_t *, sepol_policy_file_t *) = NULL;
     78 	int (*policydb_set_vers)(sepol_policydb_t *, unsigned int) = NULL;
     79 	int (*policydb_to_image)(sepol_handle_t *, sepol_policydb_t *, void **, size_t *) = NULL;
     80 	int (*genbools_array)(void *data, size_t len, char **names, int *values, int nel) = NULL;
     81 	int (*genusers)(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen) = NULL;
     82 	int (*genbools)(void *data, size_t len, const char *boolpath) = NULL;
     83 
     84 #ifdef SHARED
     85 	char *errormsg = NULL;
     86 	void *libsepolh = NULL;
     87 	libsepolh = dlopen("libsepol.so.1", RTLD_NOW);
     88 	if (libsepolh) {
     89 		usesepol = 1;
     90 		dlerror();
     91 #define DLERR() if ((errormsg = dlerror())) goto dlclose;
     92 		vers_max = dlsym(libsepolh, "sepol_policy_kern_vers_max");
     93 		DLERR();
     94 		vers_min = dlsym(libsepolh, "sepol_policy_kern_vers_min");
     95 		DLERR();
     96 
     97 		policy_file_create = dlsym(libsepolh, "sepol_policy_file_create");
     98 		DLERR();
     99 		policy_file_free = dlsym(libsepolh, "sepol_policy_file_free");
    100 		DLERR();
    101 		policy_file_set_mem = dlsym(libsepolh, "sepol_policy_file_set_mem");
    102 		DLERR();
    103 		policydb_create = dlsym(libsepolh, "sepol_policydb_create");
    104 		DLERR();
    105 		policydb_free = dlsym(libsepolh, "sepol_policydb_free");
    106 		DLERR();
    107 		policydb_read = dlsym(libsepolh, "sepol_policydb_read");
    108 		DLERR();
    109 		policydb_set_vers = dlsym(libsepolh, "sepol_policydb_set_vers");
    110 		DLERR();
    111 		policydb_to_image = dlsym(libsepolh, "sepol_policydb_to_image");
    112 		DLERR();
    113 		genbools_array = dlsym(libsepolh, "sepol_genbools_array");
    114 		DLERR();
    115 		genusers = dlsym(libsepolh, "sepol_genusers");
    116 		DLERR();
    117 		genbools = dlsym(libsepolh, "sepol_genbools");
    118 		DLERR();
    119 
    120 #undef DLERR
    121 	}
    122 #else
    123 	usesepol = 1;
    124 	vers_max = sepol_policy_kern_vers_max;
    125 	vers_min = sepol_policy_kern_vers_min;
    126 	policy_file_create = sepol_policy_file_create;
    127 	policy_file_free = sepol_policy_file_free;
    128 	policy_file_set_mem = sepol_policy_file_set_mem;
    129 	policydb_create = sepol_policydb_create;
    130 	policydb_free = sepol_policydb_free;
    131 	policydb_read = sepol_policydb_read;
    132 	policydb_set_vers = sepol_policydb_set_vers;
    133 	policydb_to_image = sepol_policydb_to_image;
    134 	genbools_array = sepol_genbools_array;
    135 	genusers = sepol_genusers;
    136 	genbools = sepol_genbools;
    137 
    138 #endif
    139 
    140 	/*
    141 	 * Check whether we need to support local boolean and user definitions.
    142 	 */
    143 	if (setlocaldefs) {
    144 		if (access(selinux_booleans_path(), F_OK) == 0)
    145 			goto checkbool;
    146 		snprintf(path, sizeof path, "%s.local", selinux_booleans_path());
    147 		if (access(path, F_OK) == 0)
    148 			goto checkbool;
    149 		snprintf(path, sizeof path, "%s/local.users", selinux_users_path());
    150 		if (access(path, F_OK) == 0)
    151 			goto checkbool;
    152 		/* No local definition files, so disable setlocaldefs. */
    153 		setlocaldefs = 0;
    154 	}
    155 
    156 checkbool:
    157 	/*
    158 	 * As of Linux 2.6.22, the kernel preserves boolean
    159 	 * values across a reload, so we do not need to
    160 	 * preserve them in userspace.
    161 	 */
    162 	if (preservebools && uname(&uts) == 0 && strverscmp(uts.release, "2.6.22") >= 0)
    163 		preservebools = 0;
    164 
    165 	if (usesepol) {
    166 		maxvers = vers_max();
    167 		minvers = vers_min();
    168 		if (!setlocaldefs && !preservebools)
    169 			maxvers = max(kernvers, maxvers);
    170 	}
    171 
    172 	vers = maxvers;
    173       search:
    174 	snprintf(path, sizeof(path), "%s.%d",
    175 		 selinux_binary_policy_path(), vers);
    176 	fd = open(path, O_RDONLY | O_CLOEXEC);
    177 	while (fd < 0 && errno == ENOENT
    178 	       && --vers >= minvers) {
    179 		/* Check prior versions to see if old policy is available */
    180 		snprintf(path, sizeof(path), "%s.%d",
    181 			 selinux_binary_policy_path(), vers);
    182 		fd = open(path, O_RDONLY | O_CLOEXEC);
    183 	}
    184 	if (fd < 0) {
    185 		fprintf(stderr,
    186 			"SELinux:  Could not open policy file <= %s.%d:  %s\n",
    187 			selinux_binary_policy_path(), maxvers, strerror(errno));
    188 		goto dlclose;
    189 	}
    190 
    191 	if (fstat(fd, &sb) < 0) {
    192 		fprintf(stderr,
    193 			"SELinux:  Could not stat policy file %s:  %s\n",
    194 			path, strerror(errno));
    195 		goto close;
    196 	}
    197 
    198 	prot = PROT_READ;
    199 	if (setlocaldefs || preservebools)
    200 		prot |= PROT_WRITE;
    201 
    202 	size = sb.st_size;
    203 	data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
    204 	if (map == MAP_FAILED) {
    205 		fprintf(stderr,
    206 			"SELinux:  Could not map policy file %s:  %s\n",
    207 			path, strerror(errno));
    208 		goto close;
    209 	}
    210 
    211 	if (vers > kernvers && usesepol) {
    212 		/* Need to downgrade to kernel-supported version. */
    213 		if (policy_file_create(&pf))
    214 			goto unmap;
    215 		if (policydb_create(&policydb)) {
    216 			policy_file_free(pf);
    217 			goto unmap;
    218 		}
    219 		policy_file_set_mem(pf, data, size);
    220 		if (policydb_read(policydb, pf)) {
    221 			policy_file_free(pf);
    222 			policydb_free(policydb);
    223 			goto unmap;
    224 		}
    225 		if (policydb_set_vers(policydb, kernvers) ||
    226 		    policydb_to_image(NULL, policydb, &data, &size)) {
    227 			/* Downgrade failed, keep searching. */
    228 			fprintf(stderr,
    229 				"SELinux:  Could not downgrade policy file %s, searching for an older version.\n",
    230 				path);
    231 			policy_file_free(pf);
    232 			policydb_free(policydb);
    233 			munmap(map, sb.st_size);
    234 			close(fd);
    235 			vers--;
    236 			goto search;
    237 		}
    238 		policy_file_free(pf);
    239 		policydb_free(policydb);
    240 	}
    241 
    242 	if (usesepol) {
    243 		if (setlocaldefs) {
    244 			void *olddata = data;
    245 			size_t oldsize = size;
    246 			rc = genusers(olddata, oldsize, selinux_users_path(),
    247 				      &data, &size);
    248 			if (rc < 0) {
    249 				/* Fall back to the prior image if genusers failed. */
    250 				data = olddata;
    251 				size = oldsize;
    252 				rc = 0;
    253 			} else {
    254 				if (olddata != map)
    255 					free(olddata);
    256 			}
    257 		}
    258 
    259 		if (preservebools) {
    260 			int *values, len, i;
    261 			char **names;
    262 			rc = security_get_boolean_names(&names, &len);
    263 			if (!rc) {
    264 				values = malloc(sizeof(int) * len);
    265 				if (!values) {
    266 					free(names);
    267 					goto unmap;
    268 				}
    269 				for (i = 0; i < len; i++)
    270 					values[i] =
    271 						security_get_boolean_active(names[i]);
    272 				(void)genbools_array(data, size, names, values,
    273 						     len);
    274 				free(values);
    275 				for (i = 0; i < len; i++)
    276 					free(names[i]);
    277 				free(names);
    278 			}
    279 		} else if (setlocaldefs) {
    280 			(void)genbools(data, size, selinux_booleans_path());
    281 		}
    282 	}
    283 
    284 
    285 	rc = security_load_policy(data, size);
    286 
    287 	if (rc)
    288 		fprintf(stderr,
    289 			"SELinux:  Could not load policy file %s:  %s\n",
    290 			path, strerror(errno));
    291 
    292       unmap:
    293 	if (data != map)
    294 		free(data);
    295 	munmap(map, sb.st_size);
    296       close:
    297 	close(fd);
    298       dlclose:
    299 #ifdef SHARED
    300 	if (errormsg)
    301 		fprintf(stderr, "libselinux:  %s\n", errormsg);
    302 	if (libsepolh)
    303 		dlclose(libsepolh);
    304 #endif
    305 	return rc;
    306 }
    307 
    308 hidden_def(selinux_mkload_policy)
    309 
    310 /*
    311  * Mount point for selinuxfs.
    312  * This definition is private to the function below.
    313  * Everything else uses the location determined during
    314  * libselinux startup via /proc/mounts (see init_selinuxmnt).
    315  * We only need the hardcoded definition for the initial mount
    316  * required for the initial policy load.
    317  */
    318 int selinux_init_load_policy(int *enforce)
    319 {
    320 	int rc = 0, orig_enforce = 0, seconfig = -2, secmdline = -1;
    321 	FILE *cfg;
    322 	char *buf;
    323 
    324 	/*
    325 	 * Reread the selinux configuration in case it has changed.
    326 	 * Example:  Caller has chroot'd and is now loading policy from
    327 	 * chroot'd environment.
    328 	 */
    329 	selinux_reset_config();
    330 
    331 	/*
    332 	 * Get desired mode (disabled, permissive, enforcing) from
    333 	 * /etc/selinux/config.
    334 	 */
    335 	selinux_getenforcemode(&seconfig);
    336 
    337 	/* Check for an override of the mode via the kernel command line. */
    338 	rc = mount("proc", "/proc", "proc", 0, 0);
    339 	cfg = fopen("/proc/cmdline", "re");
    340 	if (cfg) {
    341 		char *tmp;
    342 		buf = malloc(selinux_page_size);
    343 		if (!buf) {
    344 			fclose(cfg);
    345 			return -1;
    346 		}
    347 		if (fgets(buf, selinux_page_size, cfg) &&
    348 		    (tmp = strstr(buf, "enforcing="))) {
    349 			if (tmp == buf || isspace(*(tmp - 1))) {
    350 				secmdline =
    351 				    atoi(tmp + sizeof("enforcing=") - 1);
    352 			}
    353 		}
    354 		fclose(cfg);
    355 		free(buf);
    356 	}
    357 
    358 	/*
    359 	 * Determine the final desired mode.
    360 	 * Command line argument takes precedence, then config file.
    361 	 */
    362 	if (secmdline >= 0)
    363 		*enforce = secmdline;
    364 	else if (seconfig >= 0)
    365 		*enforce = seconfig;
    366 	else
    367 		*enforce = 0;	/* unspecified or disabled */
    368 
    369 	/*
    370 	 * Check for the existence of SELinux via selinuxfs, and
    371 	 * mount it if present for use in the calls below.
    372 	 */
    373 	const char *mntpoint = NULL;
    374 	/* First make sure /sys is mounted */
    375 	if (mount("sysfs", "/sys", "sysfs", 0, 0) == 0 || errno == EBUSY) {
    376 		if (mount(SELINUXFS, SELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) {
    377 			mntpoint = SELINUXMNT;
    378 		} else {
    379 			/* check old mountpoint */
    380 			if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) {
    381 				mntpoint = OLDSELINUXMNT;
    382 			}
    383 		}
    384 	} else {
    385 		/* check old mountpoint */
    386 		if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) {
    387 			mntpoint = OLDSELINUXMNT;
    388 		}
    389 	}
    390 
    391 	if (! mntpoint ) {
    392 		if (errno == ENODEV || !selinuxfs_exists()) {
    393 			/*
    394 			 * SELinux was disabled in the kernel, either
    395 			 * omitted entirely or disabled at boot via selinux=0.
    396 			 * This takes precedence over any config or
    397 			 * commandline enforcing setting.
    398 			 */
    399 			*enforce = 0;
    400 		} else {
    401 			/* Only emit this error if selinux was not disabled */
    402 			fprintf(stderr, "Mount failed for selinuxfs on %s:  %s\n", SELINUXMNT, strerror(errno));
    403 		}
    404 
    405 		if (rc == 0)
    406 			umount2("/proc", MNT_DETACH);
    407 
    408 		goto noload;
    409 	}
    410 	set_selinuxmnt(mntpoint);
    411 
    412 	if (rc == 0)
    413 		umount2("/proc", MNT_DETACH);
    414 
    415 	/*
    416 	 * Note:  The following code depends on having selinuxfs
    417 	 * already mounted and selinuxmnt set above.
    418 	 */
    419 
    420 	if (seconfig == -1) {
    421 		/* Runtime disable of SELinux. */
    422 		rc = security_disable();
    423 		if (rc == 0) {
    424 			/* Successfully disabled, so umount selinuxfs too. */
    425 			umount(selinux_mnt);
    426 			fini_selinuxmnt();
    427 			goto noload;
    428 		} else {
    429 			/*
    430 			 * It's possible that this failed because policy has
    431 			 * already been loaded. We can't disable SELinux now,
    432 			 * so the best we can do is force it to be permissive.
    433 			 */
    434 			*enforce = 0;
    435 		}
    436 	}
    437 
    438 	/*
    439 	 * If necessary, change the kernel enforcing status to match
    440 	 * the desired mode.
    441 	 */
    442 	orig_enforce = rc = security_getenforce();
    443 	if (rc < 0)
    444 		goto noload;
    445 	if (orig_enforce != *enforce) {
    446 		rc = security_setenforce(*enforce);
    447 		if (rc < 0) {
    448 			fprintf(stderr, "SELinux:  Unable to switch to %s mode:  %s\n", (*enforce ? "enforcing" : "permissive"), strerror(errno));
    449 			if (*enforce)
    450 				goto noload;
    451 		}
    452 	}
    453 
    454 	if (seconfig == -1) {
    455 		umount(selinux_mnt);
    456 		fini_selinuxmnt();
    457 		goto noload;
    458 	}
    459 
    460 	/* Load the policy. */
    461 	return selinux_mkload_policy(0);
    462 
    463       noload:
    464 	/*
    465 	 * Only return 0 on a successful completion of policy load.
    466 	 * In any other case, we want to return an error so that init
    467 	 * knows not to proceed with the re-exec for the domain transition.
    468 	 * Depending on the *enforce setting, init will halt (> 0) or proceed
    469 	 * normally (otherwise).
    470 	 */
    471 	return -1;
    472 }
    473 #endif
    474