• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
security_load_policy(void * data,size_t len)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 
49 #ifndef ANDROID
50 #undef max
51 #define max(a, b) (((a) > (b)) ? (a) : (b))
52 
selinux_mkload_policy(int preservebools)53 int 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  */
selinux_init_load_policy(int * enforce)224 int 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