int is_selinux_enabled(void) { char buf[BUFSIZ]; FILE *fp; char *bufp; size_t len; int enabled = 0; security_context_t con; /* init_selinuxmnt() gets called before this function. We * will assume that if a selinux file system is mounted, then * selinux is enabled. */ if (selinux_mnt) { /* Since a file system is mounted, we consider selinux * enabled. If getcon fails, selinux is still enabled. * We only consider it disabled if no policy is loaded. */ enabled = 1; if (getcon(&con) == 0) { if (!strcmp(con, "kernel")) enabled = 0; freecon(con); } return enabled; } /* Drop back to detecting it the long way. */ fp = fopen("/proc/filesystems", "r"); if (!fp) return -1; while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) { if (strstr(buf, "selinuxfs")) { enabled = 1; break; } } if (!bufp) goto out; /* Since an selinux file system is available, we consider * selinux enabled. If getcon fails, selinux is still * enabled. We only consider it disabled if no policy is loaded. */ if (getcon(&con) == 0) { if (!strcmp(con, "kernel")) enabled = 0; freecon(con); } out: fclose(fp); return enabled; }
static context_t runcon_compute_new_context(char *user, char *role, char *type, char *range, char *command, int compute_trans) { context_t con; security_context_t cur_context; if (getcon(&cur_context)) bb_error_msg_and_die("can't get current context"); if (compute_trans) { security_context_t file_context, new_context; if (getfilecon(command, &file_context) < 0) bb_error_msg_and_die("can't retrieve attributes of '%s'", command); if (security_compute_create(cur_context, file_context, SECCLASS_PROCESS, &new_context)) bb_error_msg_and_die("unable to compute a new context"); cur_context = new_context; } con = context_new(cur_context); if (!con) bb_error_msg_and_die("'%s' is not a valid context", cur_context); if (user && context_user_set(con, user)) bb_error_msg_and_die("can't set new user '%s'", user); if (type && context_type_set(con, type)) bb_error_msg_and_die("can't set new type '%s'", type); if (range && context_range_set(con, range)) bb_error_msg_and_die("can't set new range '%s'", range); if (role && context_role_set(con, role)) bb_error_msg_and_die("can't set new role '%s'", role); return con; }
static int computecon (char const *path, mode_t mode, char **con) { char *scon = NULL; char *tcon = NULL; security_class_t tclass; int rc = -1; char *dir = dir_name (path); if (!dir) goto quit; if (getcon (&scon) < 0) goto quit; if (getfilecon (dir, &tcon) < 0) goto quit; tclass = mode_to_security_class (mode); if (!tclass) goto quit; rc = security_compute_create (scon, tcon, tclass, con); quit: free (dir); freecon (scon); freecon (tcon); return rc; }
char * do_getcon (void) { #if defined(HAVE_GETCON) security_context_t context; char *r; if (getcon (&context) == -1) { reply_with_perror ("getcon"); return NULL; } r = strdup (context); freecon (context); if (r == NULL) { reply_with_perror ("strdup"); return NULL; } return r; /* caller frees */ #else reply_with_error ("function not available"); return NULL; #endif }
void ssh_selinux_change_context(const char *newname) { int len, newlen; char *oldctx, *newctx, *cx; if (!ssh_selinux_enabled()) return; if (getcon((security_context_t *)&oldctx) < 0) { logit("%s: getcon failed with %s", __func__, strerror (errno)); return; } if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) == NULL) { logit ("%s: unparseable context %s", __func__, oldctx); return; } newlen = strlen(oldctx) + strlen(newname) + 1; newctx = xmalloc(newlen); len = cx - oldctx + 1; memcpy(newctx, oldctx, len); strlcpy(newctx + len, newname, newlen - len); if ((cx = index(cx + 1, ':'))) strlcat(newctx, cx, newlen); debug3("%s: setting context from '%s' to '%s'", __func__, oldctx, newctx); if (setcon(newctx) < 0) logit("%s: setcon failed with %s", __func__, strerror (errno)); xfree(oldctx); xfree(newctx); }
/** * virIdentityGetSystem: * * Returns an identity that represents the system itself. * This is the identity that the process is running as * * Returns a reference to the system identity, or NULL */ virIdentityPtr virIdentityGetSystem(void) { char *username = NULL; char *groupname = NULL; char *seccontext = NULL; virIdentityPtr ret = NULL; #if WITH_SELINUX security_context_t con; #endif if (!(username = virGetUserName(getuid()))) goto cleanup; if (!(groupname = virGetGroupName(getgid()))) goto cleanup; #if WITH_SELINUX if (getcon(&con) < 0) { virReportSystemError(errno, "%s", _("Unable to lookup SELinux process context")); goto cleanup; } if (VIR_STRDUP(seccontext, con) < 0) { freecon(con); goto cleanup; } freecon(con); #endif if (!(ret = virIdentityNew())) goto cleanup; if (username && virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_USER_NAME, username) < 0) goto error; if (groupname && virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_GROUP_NAME, groupname) < 0) goto error; if (seccontext && virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_SELINUX_CONTEXT, seccontext) < 0) goto error; cleanup: VIR_FREE(username); VIR_FREE(groupname); VIR_FREE(seccontext); return ret; error: virObjectUnref(ret); ret = NULL; goto cleanup; }
/** * virIdentityGetSystem: * * Returns an identity that represents the system itself. * This is the identity that the process is running as * * Returns a reference to the system identity, or NULL */ virIdentityPtr virIdentityGetSystem(void) { VIR_AUTOFREE(char *) username = NULL; VIR_AUTOFREE(char *) groupname = NULL; unsigned long long startTime; virIdentityPtr ret = NULL; #if WITH_SELINUX security_context_t con; #endif if (!(ret = virIdentityNew())) goto error; if (virIdentitySetUNIXProcessID(ret, getpid()) < 0) goto error; if (virProcessGetStartTime(getpid(), &startTime) < 0) goto error; if (startTime != 0 && virIdentitySetUNIXProcessTime(ret, startTime) < 0) goto error; if (!(username = virGetUserName(geteuid()))) return ret; if (virIdentitySetUNIXUserName(ret, username) < 0) goto error; if (virIdentitySetUNIXUserID(ret, getuid()) < 0) goto error; if (!(groupname = virGetGroupName(getegid()))) return ret; if (virIdentitySetUNIXGroupName(ret, groupname) < 0) goto error; if (virIdentitySetUNIXGroupID(ret, getgid()) < 0) goto error; #if WITH_SELINUX if (is_selinux_enabled() > 0) { if (getcon(&con) < 0) { virReportSystemError(errno, "%s", _("Unable to lookup SELinux process context")); return ret; } if (virIdentitySetSELinuxContext(ret, con) < 0) { freecon(con); goto error; } freecon(con); } #endif return ret; error: virObjectUnref(ret); return NULL; }
int main(int argc, char **argv) { security_context_t *list, usercon = NULL, cur_context = NULL; char *user = NULL, *level = NULL; int ret, i, opt; while ((opt = getopt(argc, argv, "l:")) > 0) { switch (opt) { case 'l': level = strdup(optarg); break; default: usage(argv[0], "invalid option", 1); } } if (((argc - optind) < 1) || ((argc - optind) > 2)) usage(argv[0], "invalid number of arguments", 2); /* If selinux isn't available, bail out. */ if (!is_selinux_enabled()) { fprintf(stderr, "getconlist may be used only on a SELinux kernel.\n"); return 1; } user = argv[optind]; /* If a context wasn't passed, use the current context. */ if (((argc - optind) < 2)) { if (getcon(&cur_context) < 0) { fprintf(stderr, "Couldn't get current context.\n"); return 2; } } else cur_context = argv[optind + 1]; /* Get the list and print it */ if (level) ret = get_ordered_context_list_with_level(user, level, cur_context, &list); else ret = get_ordered_context_list(user, cur_context, &list); if (ret != -1) { for (i = 0; list[i]; i++) puts(list[i]); freeconary(list); } free(usercon); return 0; }
static int set_context_from_socket( const struct service_config *scp, int fd ) { security_context_t curr_context = NULL; security_context_t peer_context = NULL; security_context_t exec_context = NULL; context_t bcon = NULL; context_t pcon = NULL; security_context_t new_context = NULL; security_context_t new_exec_context = NULL; int retval = -1; const char *exepath = NULL; if (getcon(&curr_context) < 0) goto fail; if (getpeercon(fd, &peer_context) < 0) goto fail; exepath = SC_SERVER_ARGV( scp )[0]; if (getfilecon(exepath, &exec_context) < 0) goto fail; if (!(bcon = context_new(curr_context))) goto fail; if (!(pcon = context_new(peer_context))) goto fail; if (!context_range_get(pcon)) goto fail; if (context_range_set(bcon, context_range_get(pcon))) goto fail; if (!(new_context = context_str(bcon))) goto fail; if (security_compute_create(new_context, exec_context, SECCLASS_PROCESS, &new_exec_context) < 0) goto fail; retval = set_context(new_exec_context); freecon(new_exec_context); fail: context_free(pcon); context_free(bcon); freecon(exec_context); freecon(peer_context); freecon(curr_context); return retval; }
int main(int argc, char *argv[]) { security_context_t security_context; context_t context; pthread_t thread; int rc; if (argc != 2) { fprintf(stderr, "usage: %s <new domain>\n", argv[0]); return 1; } rc = getcon(&security_context); if (rc < 0) { fprintf(stderr, "%s: unable to get my context\n", argv[0]); return 1; } context = context_new(security_context); if (!context) { fprintf(stderr, "%s: unable to create context structure\n", argv[0]); return 1; } if (context_type_set(context, argv[1])) { fprintf(stderr, "%s: unable to set new type\n", argv[0]); return 1; } freecon(security_context); security_context = context_str(context); if (!security_context) { fprintf(stderr, "%s: unable to obtain new context string\n", argv[0]); return 1; } rc = pthread_create(&thread, NULL, worker, security_context); if (rc) { fprintf(stderr, "%s: unable to kick a new thread\n", argv[0]); return 1; } rc = pthread_join(thread, NULL); if (rc) { fprintf(stderr, "%s: unable to join its thread\n", argv[0]); return 1; } fprintf(stderr, "%s: setcon('%s') : %s\n", argv[0], argv[1], strerror(thread_status)); return thread_status; }
/* Check the permission from the caller (via getpeercon) to nscd. Returns 0 if access is allowed, 1 if denied, and -1 on error. */ int nscd_request_avc_has_perm (int fd, request_type req) { /* Initialize to NULL so we know what to free in case of failure. */ security_context_t scon = NULL; security_context_t tcon = NULL; security_id_t ssid = NULL; security_id_t tsid = NULL; int rc = -1; if (getpeercon (fd, &scon) < 0) { dbg_log (_("Error getting context of socket peer")); goto out; } if (getcon (&tcon) < 0) { dbg_log (_("Error getting context of nscd")); goto out; } if (avc_context_to_sid (scon, &ssid) < 0 || avc_context_to_sid (tcon, &tsid) < 0) { dbg_log (_("Error getting sid from context")); goto out; } #ifndef NSCD__GETSERV if (perms[req] == 0) { dbg_log (_("compile-time support for database policy missing")); goto out; } #endif rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0; out: if (scon) freecon (scon); if (tcon) freecon (tcon); if (ssid) sidput (ssid); if (tsid) sidput (tsid); return rc; }
tmap->mark_all_dirty(); } } WRITE16_MEMBER(aerofgt_state::pspikes_gfxbank_w) { if (ACCESSING_BITS_0_7) { setbank(m_bg1_tilemap, 0, (data & 0xf0) >> 4); setbank(m_bg1_tilemap, 1, data & 0x0f); } } WRITE16_MEMBER(aerofgt_state::karatblz_gfxbank_w) { if (ACCESSING_BITS_8_15) { setbank(m_bg1_tilemap, 0, (data & 0x0100) >> 8); setbank(m_bg2_tilemap, 1, (data & 0x0800) >> 11); } } WRITE16_MEMBER(aerofgt_state::spinlbrk_gfxbank_w) {
static void httpd_child_setup (gpointer user_data) { #ifdef HAVE_SELINUX char *mycon; /* If selinux is enabled, avoid transitioning to the httpd_t context, as this normally means you can't read the users homedir. */ if (is_selinux_enabled()) { if (getcon (&mycon) < 0) { abort (); } if (setexeccon (mycon) < 0) abort (); freecon (mycon); } #endif }
/* * Function: getCon * Purpose: Get the context of the current process. * Parameters: none * Returns: a jstring representing the security context of the process, * the jstring may be NULL if there was an error * Exceptions: none */ static jstring getCon(JNIEnv *env, jobject) { if (isSELinuxDisabled) { return NULL; } security_context_t tmp = NULL; int ret = getcon(&tmp); Unique_SecurityContext context(tmp); ScopedLocalRef<jstring> securityString(env, NULL); if (ret != -1) { securityString.reset(env->NewStringUTF(context.get())); } ALOGV("getCon() => %s", context.get()); return securityString.release(); }
int main(int argc, char **argv) { int rc; security_context_t context_s; context_t context; if (argc != 2) { fprintf(stderr, "usage: %s newdomain\n", argv[0]); exit(-1); } rc = getcon(&context_s); if (rc < 0) { fprintf(stderr, "%s: unable to get my context\n", argv[0]); exit(-1); } context = context_new(context_s); if (!context) { fprintf(stderr, "%s: unable to create context structure\n", argv[0]); exit(-1); } if (context_type_set(context, argv[1])) { fprintf(stderr, "%s: unable to set new type\n", argv[0]); exit(-1); } freecon(context_s); context_s = context_str(context); if (!context_s) { fprintf(stderr, "%s: unable to obtain new context string\n", argv[0]); exit(-1); } rc = setcon(context_s); if (rc < 0) { perror("setcon failed"); exit(-1); } printf("All systems go\n"); exit(0); }
void ssh_selinux_change_context(const char *newname) { int len, newlen; char *oldctx, *newctx, *cx; void (*switchlog) (const char *fmt,...) = logit; if (!ssh_selinux_enabled()) return; if (getcon((security_context_t *)&oldctx) < 0) { logit("%s: getcon failed with %s", __func__, strerror(errno)); return; } if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) == NULL) { logit ("%s: unparseable context %s", __func__, oldctx); return; } /* * Check whether we are attempting to switch away from an unconfined * security context. */ if (strncmp(cx, SSH_SELINUX_UNCONFINED_TYPE, sizeof(SSH_SELINUX_UNCONFINED_TYPE) - 1) == 0) switchlog = debug3; newlen = strlen(oldctx) + strlen(newname) + 1; newctx = xmalloc(newlen); len = cx - oldctx + 1; memcpy(newctx, oldctx, len); strlcpy(newctx + len, newname, newlen - len); if ((cx = index(cx + 1, ':'))) strlcat(newctx, cx, newlen); debug3("%s: setting context from '%s' to '%s'", __func__, oldctx, newctx); if (setcon(newctx) < 0) switchlog("%s: setcon %s from %s failed with %s", __func__, newctx, oldctx, strerror(errno)); free(oldctx); free(newctx); }
int get_default_context_with_rolelevel(const char *user, const char *role, const char *level, security_context_t fromcon, security_context_t * newcon) { int rc = 0; int freefrom = 0; context_t con; char *newfromcon; if (!level) return get_default_context_with_role(user, role, fromcon, newcon); if (!fromcon) { rc = getcon(&fromcon); if (rc < 0) return rc; freefrom = 1; } rc = -1; con = context_new(fromcon); if (!con) goto out; if (context_range_set(con, level)) goto out; newfromcon = context_str(con); if (!newfromcon) goto out; rc = get_default_context_with_role(user, role, newfromcon, newcon); out: context_free(con); if (freefrom) freecon(fromcon); return rc; }
/* Read in color file. */ int init_colors(void) { FILE *cfg = NULL; size_t size = 0; char *buffer = NULL; int line = 0; getcon(&my_context); cfg = fopen(selinux_colors_path(), "r"); if (!cfg) return 1; __fsetlocking(cfg, FSETLOCKING_BYCALLER); while (getline(&buffer, &size, cfg) > 0) { if( process_color(buffer, ++line) < 0 ) break; } free(buffer); fclose(cfg); return 0; }
int main(int argc, char **argv) { struct binder_state *bs; bs = binder_open(128*1024); if (!bs) { ALOGE("failed to open binder driver\n"); return -1; } if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } selinux_enabled = is_selinux_enabled(); sehandle = selinux_android_service_context_handle(); selinux_status_open(true); if (selinux_enabled > 0) { if (sehandle == NULL) { ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); abort(); } if (getcon(&service_manager_context) != 0) { ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); abort(); } } union selinux_callback cb; cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); cb.func_log = selinux_log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); binder_loop(bs, svcmgr_handler); return 0; }
int get_ordered_context_list_with_level(const char *user, const char *level, security_context_t fromcon, security_context_t ** list) { int rc; int freefrom = 0; context_t con; char *newfromcon; if (!level) return get_ordered_context_list(user, fromcon, list); if (!fromcon) { rc = getcon(&fromcon); if (rc < 0) return rc; freefrom = 1; } rc = -1; con = context_new(fromcon); if (!con) goto out; if (context_range_set(con, level)) goto out; newfromcon = context_str(con); if (!newfromcon) goto out; rc = get_ordered_context_list(user, newfromcon, list); out: context_free(con); if (freefrom) freecon(fromcon); return rc; }
static void BenchmarkSuccess(benchmark::State& state) { if (getuid() != 0) { state.SkipWithError("Skipping benchmark, must be run as root."); return; } char* context; if (getcon(&context) != 0) { state.SkipWithError("getcon() failed"); return; } auto subcontext = Subcontext("path", context); free(context); while (state.KeepRunning()) { subcontext.Execute(std::vector<std::string>{"return_success"}).IgnoreError(); } if (subcontext.pid() > 0) { kill(subcontext.pid(), SIGTERM); kill(subcontext.pid(), SIGKILL); } }
int label_get_socket_label_from_exe(const char *exe, char **label) { int r = 0; #ifdef HAVE_SELINUX security_context_t mycon = NULL, fcon = NULL; security_class_t sclass; if (!use_selinux()) { *label = NULL; return 0; } r = getcon(&mycon); if (r < 0) goto fail; r = getfilecon(exe, &fcon); if (r < 0) goto fail; sclass = string_to_security_class("process"); r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); if (r == 0) log_debug("SELinux Socket context for %s will be set to %s", exe, *label); fail: if (r < 0 && security_getenforce() == 1) r = -errno; freecon(mycon); freecon(fcon); #endif return r; }
/* * Function: getCon * Purpose: Get the context of the current process. * Parameters: none * Returns: a jstring representing the security context of the process, * the jstring may be NULL if there was an error * Exceptions: none */ static jstring getCon(JNIEnv *env, jobject clazz) { #ifdef HAVE_SELINUX if (isSELinuxDisabled) return NULL; security_context_t context = NULL; jstring securityString = NULL; if (getcon(&context) == -1) goto bail; ALOGV("getCon: Successfully retrieved context '%s'", context); securityString = env->NewStringUTF(context); bail: if (context != NULL) freecon(context); return securityString; #else return NULL; #endif }
void service_start(struct service *svc, const char *dynamic_args) { // Starting a service removes it from the disabled or reset state and // immediately takes it out of the restarting state if it was in there. svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); svc->time_started = 0; // Running processes require no additional work --- if they're in the // process of exiting, we've ensured that they will immediately restart // on exit, unless they are ONESHOT. if (svc->flags & SVC_RUNNING) { return; } bool needs_console = (svc->flags & SVC_CONSOLE); if (needs_console && !have_console) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } struct stat sb; if (stat(svc->args[0], &sb) == -1) { ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name); svc->flags |= SVC_DISABLED; return; } if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); svc->flags |= SVC_DISABLED; return; } char* scon = NULL; if (svc->seclabel) { scon = strdup(svc->seclabel); if (!scon) { ERROR("Out of memory while starting '%s'\n", svc->name); return; } } else { char *mycon = NULL, *fcon = NULL; INFO("computing context for service '%s'\n", svc->args[0]); int rc = getcon(&mycon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } rc = getfilecon(svc->args[0], &fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); free(mycon); return; } rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon); if (rc == 0 && !strcmp(scon, mycon)) { ERROR("Service %s does not have a SELinux domain defined.\n", svc->name); free(mycon); free(fcon); free(scon); return; } free(mycon); free(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } NOTICE("Starting service '%s'...\n", svc->name); pid_t pid = fork(); if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); if (properties_initialized()) { get_property_workspace(&fd, &sz); snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); for (si = svc->sockets; si; si = si->next) { int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid, si->socketcon ?: scon); if (s >= 0) { publish_socket(si->name, s); } } free(scon); scon = NULL; if (svc->writepid_files_) { std::string pid_str = android::base::StringPrintf("%d", pid); for (auto& file : *svc->writepid_files_) { if (!android::base::WriteStringToFile(pid_str, file)) { ERROR("couldn't write %s to %s: %s\n", pid_str.c_str(), file.c_str(), strerror(errno)); } } } if (svc->ioprio_class != IoSchedClass_NONE) { if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { ERROR("Failed to set pid %d ioprio = %d,%d: %s\n", getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno)); } } if (needs_console) { setsid(); open_console(); } else { zap_stdio(); } if (false) { for (size_t n = 0; svc->args[n]; n++) { INFO("args[%zu] = '%s'\n", n, svc->args[n]); } for (size_t n = 0; ENV[n]; n++) { INFO("env[%zu] = '%s'\n", n, ENV[n]); } } setpgid(0, getpid()); // As requested, set our gid, supplemental gids, and uid. if (svc->gid) { if (setgid(svc->gid) != 0) { ERROR("setgid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->nr_supp_gids) { if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) { ERROR("setgroups failed: %s\n", strerror(errno)); _exit(127); } } if (svc->uid) { if (setuid(svc->uid) != 0) { ERROR("setuid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->seclabel) { if (setexeccon(svc->seclabel) < 0) { ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno)); _exit(127); } } if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); } } else { char *arg_ptrs[INIT_PARSER_MAXARGS+1]; int arg_idx = svc->nargs; char *tmp = strdup(dynamic_args); char *next = tmp; char *bword; /* Copy the static arguments */ memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *))); while((bword = strsep(&next, " "))) { arg_ptrs[arg_idx++] = bword; if (arg_idx == INIT_PARSER_MAXARGS) break; } arg_ptrs[arg_idx] = NULL; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } free(scon); if (pid < 0) { ERROR("failed to start '%s'\n", svc->name); svc->pid = 0; return; } svc->time_started = gettime(); svc->pid = pid; svc->flags |= SVC_RUNNING; if ((svc->flags & SVC_EXEC) != 0) { INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n", svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel ? : "default"); waiting_for_exec = true; }
/** * virDomainLxcEnterSecurityLabel: * @model: the security model to set * @label: the security label to apply * @oldlabel: filled with old security label * @flags: currently unused, pass 0 * * This API is LXC specific, so it will only work with hypervisor * connections to the LXC driver. * * Attaches the process to the security label specified * by @label. @label is interpreted relative to @model * Depending on the security driver, this may * not take effect until the next call to exec(). * * If @oldlabel is not NULL, it will be filled with info * about the current security label. This may let the * process be moved back to the previous label if no * exec() has yet been performed. * * Returns 0 on success, -1 on error */ int virDomainLxcEnterSecurityLabel(virSecurityModelPtr model, virSecurityLabelPtr label, virSecurityLabelPtr oldlabel, unsigned int flags) { VIR_DEBUG("model=%p, label=%p, oldlabel=%p, flags=%x", model, label, oldlabel, flags); virResetLastError(); virCheckFlagsGoto(0, error); virCheckNonNullArgGoto(model, error); virCheckNonNullArgGoto(label, error); if (oldlabel) memset(oldlabel, 0, sizeof(*oldlabel)); if (STREQ(model->model, "selinux")) { #ifdef WITH_SELINUX if (oldlabel) { security_context_t ctx; if (getcon(&ctx) < 0) { virReportSystemError(errno, _("unable to get PID %d security context"), getpid()); goto error; } if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) { virReportError(VIR_ERR_INTERNAL_ERROR, _("security label exceeds " "maximum length: %d"), VIR_SECURITY_LABEL_BUFLEN - 1); freecon(ctx); goto error; } strcpy(oldlabel->label, (char *) ctx); freecon(ctx); if ((oldlabel->enforcing = security_getenforce()) < 0) { virReportSystemError(errno, "%s", _("error calling security_getenforce()")); goto error; } } if (setexeccon(label->label) < 0) { virReportSystemError(errno, _("Cannot set context %s"), label->label); goto error; } #else virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("Support for SELinux is not enabled")); goto error; #endif } else if (STREQ(model->model, "apparmor")) { #ifdef WITH_APPARMOR if (aa_change_profile(label->label) < 0) { virReportSystemError(errno, _("error changing profile to %s"), label->label); goto error; } #else virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("Support for AppArmor is not enabled")); goto error; #endif } else if (STREQ(model->model, "none")) { /* nothing todo */ } else { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Security model %s cannot be entered"), model->model); goto error; } return 0; error: virDispatchError(NULL); return -1; }
/* This function communicates with the kernel to check whether or not it should allow the access. If the machine is in permissive mode it will return ok. Audit messages will still be generated if the access would be denied in enforcing mode. */ int selinux_access_check( DBusConnection *connection, DBusMessage *message, const char *path, const char *permission, DBusError *error) { security_context_t scon = NULL, fcon = NULL; int r = 0; const char *tclass = NULL; struct auditstruct audit; assert(connection); assert(message); assert(permission); assert(error); if (!use_selinux()) return 0; r = selinux_access_init(error); if (r < 0) return r; log_debug("SELinux access check for path=%s permission=%s", strna(path), permission); audit.uid = audit.loginuid = (uid_t) -1; audit.gid = (gid_t) -1; audit.cmdline = NULL; audit.path = path; r = get_calling_context(connection, message, &scon, error); if (r < 0) { log_error("Failed to get caller's security context on: %m"); goto finish; } if (path) { tclass = "service"; /* get the file context of the unit file */ r = getfilecon(path, &fcon); if (r < 0) { dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); r = -errno; log_error("Failed to get security context on %s: %m",path); goto finish; } } else { tclass = "system"; r = getcon(&fcon); if (r < 0) { dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get current context."); r = -errno; log_error("Failed to get current process context on: %m"); goto finish; } } (void) get_audit_data(connection, message, &audit, error); errno = 0; r = selinux_check_access(scon, fcon, tclass, permission, &audit); if (r < 0) { dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); r = -errno; log_error("SELinux policy denies access."); } log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, audit.cmdline, r); finish: free(audit.cmdline); freecon(scon); freecon(fcon); if (r && security_getenforce() != 1) { dbus_error_init(error); r = 0; } return r; }
void service_start(struct service *svc, const char *dynamic_args) { struct stat s; pid_t pid; int needs_console; int n; #ifdef HAVE_SELINUX char *scon = NULL; int rc; #endif /* starting a service removes it from the disabled or reset * state and immediately takes it out of the restarting * state if it was in there */ svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET)); svc->time_started = 0; /* running processes require no additional work -- if * they're in the process of exiting, we've ensured * that they will immediately restart on exit, unless * they are ONESHOT */ if (svc->flags & SVC_RUNNING) { return; } needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; if (needs_console && (!have_console)) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } if (stat(svc->args[0], &s) != 0) { ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name); svc->flags |= SVC_DISABLED; return; } if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); svc->flags |= SVC_DISABLED; return; } #ifdef HAVE_SELINUX if (is_selinux_enabled() > 0) { char *mycon = NULL, *fcon = NULL; INFO("computing context for service '%s'\n", svc->args[0]); rc = getcon(&mycon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } rc = getfilecon(svc->args[0], &fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); freecon(mycon); return; } rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon); freecon(mycon); freecon(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } #endif NOTICE("starting '%s'\n", svc->name); pid = fork(); if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); #ifdef __arm__ /* * b/7188322 - Temporarily revert to the compat memory layout * to avoid breaking third party apps. * * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. * * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 * changes the kernel mapping from bottom up to top-down. * This breaks some programs which improperly embed * an out of date copy of Android's linker. */ int current = personality(0xffffFFFF); personality(current | ADDR_COMPAT_LAYOUT); #endif if (properties_inited()) { get_property_workspace(&fd, &sz); sprintf(tmp, "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); #ifdef HAVE_SELINUX setsockcreatecon(scon); #endif for (si = svc->sockets; si; si = si->next) { int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid); if (s >= 0) { publish_socket(si->name, s); } } #ifdef HAVE_SELINUX freecon(scon); scon = NULL; setsockcreatecon(NULL); #endif if (svc->ioprio_class != IoSchedClass_NONE) { if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { ERROR("Failed to set pid %d ioprio = %d,%d: %s\n", getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno)); } } if (needs_console) { setsid(); open_console(); } else { zap_stdio(); } #if 0 for (n = 0; svc->args[n]; n++) { INFO("args[%d] = '%s'\n", n, svc->args[n]); } for (n = 0; ENV[n]; n++) { INFO("env[%d] = '%s'\n", n, ENV[n]); } #endif setpgid(0, getpid()); /* as requested, set our gid, supplemental gids, and uid */ if (svc->gid) { if (setgid(svc->gid) != 0) { ERROR("setgid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->nr_supp_gids) { if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) { ERROR("setgroups failed: %s\n", strerror(errno)); _exit(127); } } if (svc->uid) { if (setuid(svc->uid) != 0) { ERROR("setuid failed: %s\n", strerror(errno)); _exit(127); } } #ifdef HAVE_SELINUX if (svc->seclabel) { if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) { ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno)); _exit(127); } } #endif if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); } } else { char *arg_ptrs[INIT_PARSER_MAXARGS+1]; int arg_idx = svc->nargs; char *tmp = strdup(dynamic_args); char *next = tmp; char *bword; /* Copy the static arguments */ memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *))); while((bword = strsep(&next, " "))) { arg_ptrs[arg_idx++] = bword; if (arg_idx == INIT_PARSER_MAXARGS) break; } arg_ptrs[arg_idx] = '\0'; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } #ifdef HAVE_SELINUX freecon(scon); #endif if (pid < 0) { ERROR("failed to start '%s'\n", svc->name); svc->pid = 0; return; } svc->time_started = gettime(); svc->pid = pid; svc->flags |= SVC_RUNNING; if (properties_inited()) notify_service_state(svc->name, "running"); }
/* This function communicates with the kernel to check whether or not it should allow the access. If the machine is in permissive mode it will return ok. Audit messages will still be generated if the access would be denied in enforcing mode. */ int mac_selinux_generic_access_check( sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error) { #ifdef HAVE_SELINUX _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; const char *tclass = NULL, *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; security_context_t fcon = NULL; char **cmdline = NULL; int r = 0; assert(message); assert(permission); assert(error); if (!mac_selinux_use()) return 0; r = mac_selinux_access_init(error); if (r < 0) return r; r = sd_bus_query_sender_creds( message, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID| SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID| SD_BUS_CREDS_SELINUX_CONTEXT| SD_BUS_CREDS_AUGMENT /* get more bits from /proc */, &creds); if (r < 0) goto finish; /* The SELinux context is something we really should have * gotten directly from the message or sender, and not be an * augmented field. If it was augmented we cannot use it for * authorization, since this is racy and vulnerable. Let's add * an extra check, just in case, even though this really * shouldn't be possible. */ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_SELINUX_CONTEXT) == 0, -EPERM); r = sd_bus_creds_get_selinux_context(creds, &scon); if (r < 0) goto finish; if (path) { /* Get the file context of the unit file */ r = getfilecon(path, &fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); goto finish; } tclass = "service"; } else { r = getcon(&fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); goto finish; } tclass = "system"; } sd_bus_creds_get_cmdline(creds, &cmdline); cl = strv_join(cmdline, " "); audit_info.creds = creds; audit_info.path = path; audit_info.cmdline = cl; r = selinux_check_access(scon, fcon, tclass, permission, &audit_info); if (r < 0) r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r); finish: freecon(fcon); if (r < 0 && security_getenforce() != 1) { sd_bus_error_free(error); r = 0; } return r; #else return 0; #endif }
int main(int argc, char **argv) { /* these vars are reused several times */ int rc, opt, i, c; char *context, *root_path; /* files that need context checks */ char *fc[MAX_CHECK]; char *cterm = ttyname(0); int nfc = 0; struct stat m; /* processes that need context checks */ char *pc[MAX_CHECK]; int npc = 0; /* booleans */ char **bools; int nbool; int verbose = 0; int show_bools = 0; /* policy */ const char *pol_name, *root_dir; char *pol_path; while (1) { opt = getopt(argc, argv, "vb"); if (opt == -1) break; switch (opt) { case 'v': verbose = 1; break; case 'b': show_bools = 1; break; default: /* invalid option */ printf("\nUsage: %s [OPTION]\n\n", basename(argv[0])); printf(" -v Verbose check of process and file contexts.\n"); printf(" -b Display current state of booleans.\n"); printf("\nWithout options, show SELinux status.\n"); return -1; } } printf_tab("SELinux status:"); rc = is_selinux_enabled(); switch (rc) { case 1: printf("enabled\n"); break; case 0: printf("disabled\n"); return 0; break; default: printf("unknown (%s)\n", strerror(errno)); return 0; break; } printf_tab("SELinuxfs mount:"); if (selinux_mnt != NULL) { printf("%s\n", selinux_mnt); } else { printf("not mounted\n\n"); printf("Please mount selinuxfs for proper results.\n"); return -1; } printf_tab("SELinux root directory:"); root_dir = selinux_path(); if (root_dir == NULL) { printf("error (%s)\n", strerror(errno)); return -1; } /* The path has a trailing '/' so duplicate to edit */ root_path = strdup(root_dir); if (!root_path) { printf("malloc error (%s)\n", strerror(errno)); return -1; } /* actually blank the '/' */ root_path[strlen(root_path) - 1] = '\0'; printf("%s\n", root_path); free(root_path); /* Dump all the path information */ printf_tab("Loaded policy name:"); pol_path = strdup(selinux_policy_root()); if (pol_path) { pol_name = basename(pol_path); puts(pol_name); free(pol_path); } else { printf("error (%s)\n", strerror(errno)); } printf_tab("Current mode:"); rc = security_getenforce(); switch (rc) { case 1: printf("enforcing\n"); break; case 0: printf("permissive\n"); break; default: printf("unknown (%s)\n", strerror(errno)); break; } printf_tab("Mode from config file:"); if (selinux_getenforcemode(&rc) == 0) { switch (rc) { case 1: printf("enforcing\n"); break; case 0: printf("permissive\n"); break; case -1: printf("disabled\n"); break; } } else { printf("error (%s)\n", strerror(errno)); } printf_tab("Policy MLS status:"); rc = is_selinux_mls_enabled(); switch (rc) { case 0: printf("disabled\n"); break; case 1: printf("enabled\n"); break; default: printf("error (%s)\n", strerror(errno)); break; } printf_tab("Policy deny_unknown status:"); rc = security_deny_unknown(); switch (rc) { case 0: printf("allowed\n"); break; case 1: printf("denied\n"); break; default: printf("error (%s)\n", strerror(errno)); break; } rc = security_policyvers(); printf_tab("Max kernel policy version:"); if (rc < 0) printf("unknown (%s)\n", strerror(errno)); else printf("%d\n", rc); if (show_bools) { /* show booleans */ if (security_get_boolean_names(&bools, &nbool) >= 0) { printf("\nPolicy booleans:\n"); for (i = 0; i < nbool; i++) { if (strlen(bools[i]) + 1 > COL) COL = strlen(bools[i]) + 1; } for (i = 0; i < nbool; i++) { printf_tab(bools[i]); rc = security_get_boolean_active(bools[i]); switch (rc) { case 1: printf("on"); break; case 0: printf("off"); break; default: printf("unknown (%s)", strerror(errno)); break; } c = security_get_boolean_pending(bools[i]); if (c != rc) switch (c) { case 1: printf(" (activate pending)"); break; case 0: printf(" (inactivate pending)"); break; default: printf(" (pending error: %s)", strerror(errno)); break; } printf("\n"); /* free up the booleans */ free(bools[i]); } free(bools); } } /* only show contexts if -v is given */ if (!verbose) return 0; load_checks(pc, &npc, fc, &nfc); printf("\nProcess contexts:\n"); printf_tab("Current context:"); if (getcon(&context) >= 0) { printf("%s\n", context); freecon(context); } else printf("unknown (%s)\n", strerror(errno)); printf_tab("Init context:"); if (getpidcon(1, &context) >= 0) { printf("%s\n", context); freecon(context); } else printf("unknown (%s)\n", strerror(errno)); for (i = 0; i < npc; i++) { rc = pidof(pc[i]); if (rc > 0) { if (getpidcon(rc, &context) < 0) continue; printf_tab(pc[i]); printf("%s\n", context); freecon(context); } } printf("\nFile contexts:\n"); /* controlling term */ printf_tab("Controlling terminal:"); if (lgetfilecon(cterm, &context) >= 0) { printf("%s\n", context); freecon(context); } else { printf("unknown (%s)\n", strerror(errno)); } for (i = 0; i < nfc; i++) { if (lgetfilecon(fc[i], &context) >= 0) { printf_tab(fc[i]); /* check if this is a symlink */ if (lstat(fc[i], &m)) { printf ("%s (could not check link status (%s)!)\n", context, strerror(errno)); freecon(context); continue; } if (S_ISLNK(m.st_mode)) { /* print link target context */ printf("%s -> ", context); freecon(context); if (getfilecon(fc[i], &context) >= 0) { printf("%s\n", context); freecon(context); } else { printf("unknown (%s)\n", strerror(errno)); } } else { printf("%s\n", context); freecon(context); } } } return 0; }
/* selinux_prepare_fork - Initialize context switching * * Returns * - 0 if everything is OK, * - +1 if the code should continue, even if SELinux wouldn't allow * (for instance due to permissive mode) * - -1 if the code should not continue */ int selinux_prepare_fork(char * name) { #ifndef SELINUX return 0; #else char * newcon = 0; char * curcon = 0; struct av_decision avd; int rc; int permissive = 0; int dom_permissive = 0; char * sename = 0; char * selevel = 0; /* * See if SELinux is enabled. * If not, then we can immediately tell the code * that everything is OK. */ rc = is_selinux_enabled(); if (rc == 0) { out(DEBUG, "SELinux is not enabled.\n"); return 0; } else if (rc == -1) { out(WARN, "Could not check SELinux state (is_selinux_enabled() failed)\n"); return 1; }; out(DEBUG, "SELinux is enabled.\n"); /* * See if SELinux is in enforcing mode * or permissive mode */ rc = security_getenforce(); if (rc == 0) { permissive = 1; } else if (rc == 1) { permissive = 0; } else { out(WARN, "Could not check SELinux mode (security_getenforce() failed)\n"); } out(DEBUG, "SELinux mode is %s\n", permissive ? "permissive" : "enforcing"); /* * Get the current SELinux context of the process. * Always interesting to log this for end users * trying to debug a possible issue. */ rc = getcon(&curcon); if (rc) { out(WARN, "Could not get current SELinux context (getcon() failed)\n"); if (permissive) return +1; else return -1; }; out(DEBUG, "Currently in SELinux context \"%s\"\n", (char *) curcon); /* * Get the SELinux user given the Linux user * name passed on to this function. */ rc = getseuserbyname(name, &sename, &selevel); if (rc) { out(WARN, "Could not find SELinux user for Linux user \"%s\" (getseuserbyname() failed)\n", name); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux user for Linux user \"%s\" is \"%s\"\n", name, sename); /* * Find out what the context is that this process should transition * to. */ rc = get_default_context(sename, NULL, &newcon); if (rc) { out(WARN, "Could not deduce default context for SELinux user \"%s\" given our current context (\"%s\")\n", sename, (char *) curcon); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux context to transition to is \"%s\"\n", (char *) newcon); /* * Now let's look if we are allowed to transition to the new context. * We currently only check the transition access for the process class. However, * transitioning is a bit more complex (execute rights on target context, * entrypoint of that context for the new domain, no constraints like target * domain not being a valid one, MLS constraints, etc.). */ rc = security_compute_av_flags(curcon, newcon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd); if (rc) { out(WARN, "Could not deduce rights for transitioning \"%s\" -> \"%s\" (security_compute_av_flags() failed)\n", (char *) curcon, (char *) newcon); freecon(curcon); freecon(newcon); if (permissive) return +1; else return -1; }; /* Validate the response * * We are interested in two things: * - Is the transition allowed, but also * - Is the permissive flag set * * If the permissive flag is set, then we * know the current domain is permissive * (even if the rest of the system is in * enforcing mode). */ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) { out(DEBUG, "The SELINUX_AVD_FLAGS_PERMISSIVE flag is set, so domain is permissive.\n"); dom_permissive = 1; }; if (!(avd.allowed & PROCESS__TRANSITION)) { // The transition is denied if (permissive) { out(DEBUG, "Transition is not allowed by SELinux, but permissive mode is enabled. Continuing.\n"); }; if (dom_permissive) { out(DEBUG, "Transition is not allowed by SELinux, but domain is in permissive mode. Continuing.\n"); }; if ((permissive == 0) && (dom_permissive == 0)) { out(WARN, "The domain transition is not allowed and we are not in permissive mode.\n"); freecon(curcon); freecon(newcon); return -1; }; }; /* * Set the context for the fork (process execution). */ rc = setexeccon(newcon); if (rc) { out(WARN, "Could not set execution context (setexeccon() failed)\n"); freecon(curcon); freecon(newcon); if ((permissive) || (dom_permissive)) return +1; else return -1; }; freecon(newcon); freecon(curcon); return 0; #endif };