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