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