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