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
26int security_load_policy(const 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
49#ifndef ANDROID
50#undef max
51#define max(a, b) (((a) > (b)) ? (a) : (b))
52
53int selinux_mkload_policy(int preservebools __attribute__((unused)))
54{
55	int kernvers = security_policyvers();
56	int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers;
57	char path[PATH_MAX];
58	struct stat sb;
59	size_t size;
60	void *map, *data;
61	int fd, rc = -1;
62	sepol_policydb_t *policydb;
63	sepol_policy_file_t *pf;
64	int usesepol = 0;
65	int (*vers_max)(void) = NULL;
66	int (*vers_min)(void) = NULL;
67	int (*policy_file_create)(sepol_policy_file_t **) = NULL;
68	void (*policy_file_free)(sepol_policy_file_t *) = NULL;
69	void (*policy_file_set_mem)(sepol_policy_file_t *, char*, size_t) = NULL;
70	int (*policydb_create)(sepol_policydb_t **) = NULL;
71	void (*policydb_free)(sepol_policydb_t *) = NULL;
72	int (*policydb_read)(sepol_policydb_t *, sepol_policy_file_t *) = NULL;
73	int (*policydb_set_vers)(sepol_policydb_t *, unsigned int) = NULL;
74	int (*policydb_to_image)(sepol_handle_t *, sepol_policydb_t *, void **, size_t *) = NULL;
75
76#ifdef SHARED
77	char *errormsg = NULL;
78	void *libsepolh = NULL;
79	libsepolh = dlopen("libsepol.so.2", RTLD_NOW);
80	if (libsepolh) {
81		usesepol = 1;
82		dlerror();
83#define DLERR() do { if ((errormsg = dlerror())) goto dlclose; } while (0)
84		vers_max = dlsym(libsepolh, "sepol_policy_kern_vers_max");
85		DLERR();
86		vers_min = dlsym(libsepolh, "sepol_policy_kern_vers_min");
87		DLERR();
88
89		policy_file_create = dlsym(libsepolh, "sepol_policy_file_create");
90		DLERR();
91		policy_file_free = dlsym(libsepolh, "sepol_policy_file_free");
92		DLERR();
93		policy_file_set_mem = dlsym(libsepolh, "sepol_policy_file_set_mem");
94		DLERR();
95		policydb_create = dlsym(libsepolh, "sepol_policydb_create");
96		DLERR();
97		policydb_free = dlsym(libsepolh, "sepol_policydb_free");
98		DLERR();
99		policydb_read = dlsym(libsepolh, "sepol_policydb_read");
100		DLERR();
101		policydb_set_vers = dlsym(libsepolh, "sepol_policydb_set_vers");
102		DLERR();
103		policydb_to_image = dlsym(libsepolh, "sepol_policydb_to_image");
104		DLERR();
105#undef DLERR
106	}
107#else
108	usesepol = 1;
109	vers_max = sepol_policy_kern_vers_max;
110	vers_min = sepol_policy_kern_vers_min;
111	policy_file_create = sepol_policy_file_create;
112	policy_file_free = sepol_policy_file_free;
113	policy_file_set_mem = sepol_policy_file_set_mem;
114	policydb_create = sepol_policydb_create;
115	policydb_free = sepol_policydb_free;
116	policydb_read = sepol_policydb_read;
117	policydb_set_vers = sepol_policydb_set_vers;
118	policydb_to_image = sepol_policydb_to_image;
119#endif
120
121	if (usesepol) {
122		maxvers = max(kernvers, vers_max());
123		minvers = vers_min();
124	}
125
126	vers = maxvers;
127      search:
128	snprintf(path, sizeof(path), "%s.%d",
129		 selinux_binary_policy_path(), vers);
130	fd = open(path, O_RDONLY | O_CLOEXEC);
131	while (fd < 0 && errno == ENOENT
132	       && --vers >= minvers) {
133		/* Check prior versions to see if old policy is available */
134		snprintf(path, sizeof(path), "%s.%d",
135			 selinux_binary_policy_path(), vers);
136		fd = open(path, O_RDONLY | O_CLOEXEC);
137	}
138	if (fd < 0) {
139		fprintf(stderr,
140			"SELinux:  Could not open policy file <= %s.%d:  %m\n",
141			selinux_binary_policy_path(), maxvers);
142		goto dlclose;
143	}
144
145	if (fstat(fd, &sb) < 0) {
146		fprintf(stderr,
147			"SELinux:  Could not stat policy file %s:  %m\n",
148			path);
149		goto close;
150	}
151
152	size = sb.st_size;
153	data = map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
154	if (map == MAP_FAILED) {
155		fprintf(stderr,
156			"SELinux:  Could not map policy file %s:  %m\n",
157			path);
158		goto close;
159	}
160
161	if (vers > kernvers && usesepol) {
162		/* Need to downgrade to kernel-supported version. */
163		if (policy_file_create(&pf))
164			goto unmap;
165		if (policydb_create(&policydb)) {
166			policy_file_free(pf);
167			goto unmap;
168		}
169		policy_file_set_mem(pf, data, size);
170		if (policydb_read(policydb, pf)) {
171			policy_file_free(pf);
172			policydb_free(policydb);
173			goto unmap;
174		}
175		if (policydb_set_vers(policydb, kernvers) ||
176		    policydb_to_image(NULL, policydb, &data, &size)) {
177			/* Downgrade failed, keep searching. */
178			fprintf(stderr,
179				"SELinux:  Could not downgrade policy file %s, searching for an older version.\n",
180				path);
181			policy_file_free(pf);
182			policydb_free(policydb);
183			munmap(map, sb.st_size);
184			close(fd);
185			vers--;
186			goto search;
187		}
188		policy_file_free(pf);
189		policydb_free(policydb);
190	}
191
192	rc = security_load_policy(data, size);
193
194	if (rc)
195		fprintf(stderr,
196			"SELinux:  Could not load policy file %s:  %m\n",
197			path);
198
199      unmap:
200	if (data != map)
201		free(data);
202	munmap(map, sb.st_size);
203      close:
204	close(fd);
205      dlclose:
206#ifdef SHARED
207	if (errormsg)
208		fprintf(stderr, "libselinux:  %s\n", errormsg);
209	if (libsepolh)
210		dlclose(libsepolh);
211#endif
212	return rc;
213}
214
215
216/*
217 * Mount point for selinuxfs.
218 * This definition is private to the function below.
219 * Everything else uses the location determined during
220 * libselinux startup via /proc/mounts (see init_selinuxmnt).
221 * We only need the hardcoded definition for the initial mount
222 * required for the initial policy load.
223 */
224int selinux_init_load_policy(int *enforce)
225{
226	int rc = 0, orig_enforce = 0, seconfig = -2, secmdline = -1;
227	FILE *cfg;
228	char *buf;
229
230	/*
231	 * Reread the selinux configuration in case it has changed.
232	 * Example:  Caller has chroot'd and is now loading policy from
233	 * chroot'd environment.
234	 */
235	selinux_reset_config();
236
237	/*
238	 * Get desired mode (disabled, permissive, enforcing) from
239	 * /etc/selinux/config.
240	 */
241	selinux_getenforcemode(&seconfig);
242
243	/* Check for an override of the mode via the kernel command line. */
244	rc = mount("proc", "/proc", "proc", 0, 0);
245	cfg = fopen("/proc/cmdline", "re");
246	if (cfg) {
247		char *tmp;
248		buf = malloc(selinux_page_size);
249		if (!buf) {
250			fclose(cfg);
251			return -1;
252		}
253		if (fgets(buf, selinux_page_size, cfg) &&
254		    (tmp = strstr(buf, "enforcing="))) {
255			if (tmp == buf || isspace(*(tmp - 1))) {
256				secmdline =
257				    atoi(tmp + sizeof("enforcing=") - 1);
258			}
259		}
260		fclose(cfg);
261		free(buf);
262	}
263
264	/*
265	 * Determine the final desired mode.
266	 * Command line argument takes precedence, then config file.
267	 */
268	if (secmdline >= 0)
269		*enforce = secmdline;
270	else if (seconfig >= 0)
271		*enforce = seconfig;
272	else
273		*enforce = 0;	/* unspecified or disabled */
274
275	/*
276	 * Check for the existence of SELinux via selinuxfs, and
277	 * mount it if present for use in the calls below.
278	 */
279	const char *mntpoint = NULL;
280	/* First make sure /sys is mounted */
281	if (mount("sysfs", "/sys", "sysfs", 0, 0) == 0 || errno == EBUSY) {
282		/* MS_NODEV can't be set because of /sys/fs/selinux/null device, used by Android */
283		if (mount(SELINUXFS, SELINUXMNT, SELINUXFS, MS_NOEXEC | MS_NOSUID, 0) == 0 || errno == EBUSY) {
284			mntpoint = SELINUXMNT;
285		} else {
286			/* check old mountpoint */
287			if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) {
288				mntpoint = OLDSELINUXMNT;
289			}
290		}
291	} else {
292		/* check old mountpoint */
293		if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) {
294			mntpoint = OLDSELINUXMNT;
295		}
296	}
297
298	if (! mntpoint ) {
299		if (errno == ENODEV || !selinuxfs_exists()) {
300			/*
301			 * SELinux was disabled in the kernel, either
302			 * omitted entirely or disabled at boot via selinux=0.
303			 * This takes precedence over any config or
304			 * commandline enforcing setting.
305			 */
306			*enforce = 0;
307		} else {
308			/* Only emit this error if selinux was not disabled */
309			fprintf(stderr, "Mount failed for selinuxfs on %s:  %m\n", SELINUXMNT);
310		}
311
312		if (rc == 0)
313			umount2("/proc", MNT_DETACH);
314
315		goto noload;
316	}
317	set_selinuxmnt(mntpoint);
318
319	if (rc == 0)
320		umount2("/proc", MNT_DETACH);
321
322	/*
323	 * Note:  The following code depends on having selinuxfs
324	 * already mounted and selinuxmnt set above.
325	 */
326
327	if (seconfig == -1) {
328		/* Runtime disable of SELinux. */
329		rc = security_disable();
330		if (rc == 0) {
331			/* Successfully disabled, so umount selinuxfs too. */
332			umount(selinux_mnt);
333			fini_selinuxmnt();
334			goto noload;
335		} else {
336			/*
337			 * It's possible that this failed because policy has
338			 * already been loaded. We can't disable SELinux now,
339			 * so the best we can do is force it to be permissive.
340			 */
341			*enforce = 0;
342		}
343	}
344
345	/*
346	 * If necessary, change the kernel enforcing status to match
347	 * the desired mode.
348	 */
349	orig_enforce = rc = security_getenforce();
350	if (rc < 0)
351		goto noload;
352	if (orig_enforce != *enforce) {
353		rc = security_setenforce(*enforce);
354		if (rc < 0) {
355			fprintf(stderr, "SELinux:  Unable to switch to %s mode:  %m\n", (*enforce ? "enforcing" : "permissive"));
356			if (*enforce)
357				goto noload;
358		}
359	}
360
361	if (seconfig == -1) {
362		umount(selinux_mnt);
363		fini_selinuxmnt();
364		goto noload;
365	}
366
367	/* Load the policy. */
368	return selinux_mkload_policy(0);
369
370      noload:
371	/*
372	 * Only return 0 on a successful completion of policy load.
373	 * In any other case, we want to return an error so that init
374	 * knows not to proceed with the re-exec for the domain transition.
375	 * Depending on the *enforce setting, init will halt (> 0) or proceed
376	 * normally (otherwise).
377	 */
378	return -1;
379}
380#endif
381