int main(int argc, char **argv) { int pid, rc, status; security_context_t context_s; context_t context; if (argc != 3) { fprintf(stderr, "usage: %s newdomain program\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 = setexeccon(context_s); if (rc < 0) { fprintf(stderr, "%s: unable to set exec context to %s\n", argv[0], context_s); exit(-1); } pid = fork(); if (pid < 0) { perror("fork"); exit(-1); } else if (pid == 0) { rc = execv(argv[2], argv + 2); perror(argv[3]); exit(1); } pid = wait(&status); if (pid < 0) { perror("wait"); exit(1); } if (WIFEXITED(status)) { exit(WEXITSTATUS(status)); } exit(-1); }
void selinux_setup(char **argv) { char *new_context = NULL; char *curr_context = NULL; context_t curr_con; char *curr_t = NULL; char *run_init_t = NULL; /* Return, if selinux is disabled. */ if (is_selinux_enabled() < 1) { return; } if (read_context_file(RUN_INIT_FILE, &run_init_t) != 0) { /* assume a reasonable default, rather than bailing out */ run_init_t = xstrdup("run_init_t"); ewarn("Assuming SELinux run_init type is %s", run_init_t); } /* Get our current context. */ if (getcon(&curr_context) < 0) { if (errno == ENOENT) { /* should only hit this if proc is not mounted. this * happens on Gentoo right after init starts, when * the init script processing starts. */ goto out; } else { perror("getcon"); exit(1); } } /* extract the type from the context */ curr_con = context_new(curr_context); if (!curr_con) { free(curr_context); goto out; } curr_t = context_type_get(curr_con); if (!curr_t) { context_free(curr_con); free(curr_context); goto out; } curr_t = xstrdup(curr_t); /* dont need them anymore so free() now */ context_free(curr_con); free(curr_context); /* if we are not in the run_init domain, we should not do anything */ if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) { goto out; } free(curr_t); free(run_init_t); if (check_auth() != 0) { eerrorx("Authentication failed."); } /* Get the context for the script to be run in. */ if (read_context_file(INITRC_FILE, &new_context) != 0) { /* assume a reasonable default, rather than bailing out */ new_context = xstrdup("system_u:system_r:initrc_t"); ewarn("Assuming SELinux initrc context is %s", new_context); } /* Set the new context */ if (setexeccon(new_context) < 0) { eerrorx("Could not set SELinux exec context to %s.", new_context); } free(new_context); /* * exec will recycle ptys so try and use open_init_pty if it exists * which will open the pty with initrc_devpts_t, if it doesnt exist, * fall back to plain exec */ if (!access("/usr/sbin/open_init_pty", X_OK)) { if (execvp("/usr/sbin/open_init_pty", argv)) { perror("execvp"); exit(-1); } } else if (execvp(argv[1], argv + 1)) { perror("execvp"); exit(-1); } out: free(run_init_t); free(curr_t); }
int main(int argc, char **argv) { int pid, rc, status; security_context_t context_s; context_t context; if (argc != 3) { fprintf(stderr, "usage: %s newdomain program\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 = setexeccon(context_s); if (rc < 0) { fprintf(stderr, "%s: unable to set exec context to %s\n", argv[0], context_s); exit(-1); } pid = fork(); if (pid < 0) { perror("fork"); exit(-1); } else if (pid == 0) { signal(SIGTRAP, SIG_IGN); rc = ptrace(PTRACE_TRACEME, 0, 0, 0); if (rc < 0) { perror("ptrace: PTRACE_TRACEME"); exit(-1); } execv(argv[2], argv + 2); perror(argv[2]); exit(1); } repeat: pid = wait(&status); if (pid < 0) { perror("wait"); exit(-1); } if (WIFEXITED(status)) { fprintf(stderr, "Child exited with status %d.\n", WEXITSTATUS(status)); exit(WEXITSTATUS(status)); } if (WIFSTOPPED(status)) { fprintf(stderr, "Child stopped by signal %d.\n", WSTOPSIG(status)); rc = getpidcon(pid, &context_s); if (rc < 0) { perror("getpidcon"); exit(-1); } fprintf(stderr, "Child has context %s\n", context_s); fprintf(stderr, "..Resuming the child.\n"); rc = ptrace(PTRACE_CONT, pid, 0, 0); if (rc < 0) { perror("ptrace: PTRACE_CONT"); exit(-1); } goto repeat; } if (WIFSIGNALED(status)) { fprintf(stderr, "Child terminated by signal %d.\n", WTERMSIG(status)); fprintf(stderr, "..This is consistent with a ptrace permission denial - check the audit message.\n"); exit(1); } fprintf(stderr, "Unexpected exit status 0x%x\n", status); exit(-1); }
int main(int argc, char **argv) { int pid, rc, status, cloneflags; security_context_t context_s; context_t context; if (argc != 4) { fprintf(stderr, "usage: %s cloneflags newdomain program\n", argv[0]); exit(-1); } cloneflags = strtol(argv[1], NULL, 0); if (!cloneflags) { fprintf(stderr, "invalid clone flags %s\n", argv[1]); 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[2])) { 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 = setexeccon(context_s); if (rc < 0) { fprintf(stderr, "%s: unable to set exec context to %s\n", argv[0], context_s); exit(-1); } pid = ltp_clone_quick(cloneflags | SIGCHLD, clone_fn, argv); if (pid < 0) { perror("clone"); exit(-1); } pid = wait(&status); if (pid < 0) { perror("wait"); exit(-1); } if (WIFEXITED(status)) { fprintf(stderr, "Child exited with status %d.\n", WEXITSTATUS(status)); exit(WEXITSTATUS(status)); } if (WIFSTOPPED(status)) { fprintf(stderr, "Child stopped by signal %d.\n", WSTOPSIG(status)); fprintf(stderr, "..This shouldn't happen.\n"); fprintf(stderr, "..Killing the child.\n"); rc = kill(pid,SIGKILL); if (rc < 0) { perror("kill"); exit(-1); } exit(-1); } if (WIFSIGNALED(status)) { fprintf(stderr, "Child terminated by signal %d.\n", WTERMSIG(status)); fprintf(stderr, "..This is consistent with a share permission denial, check the audit message.\n"); exit(1); } fprintf(stderr, "Unexpected exit status 0x%x\n", status); exit(-1); }
void service_start(struct service *svc, const char *dynamic_args) { struct stat s; pid_t pid; int needs_console; int n; char *scon = NULL; int rc; /* 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; } if (is_selinux_enabled() > 0) { 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]); 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; } } } 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); setsockcreatecon(scon); 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); } } freecon(scon); scon = NULL; setsockcreatecon(NULL); 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); } } if (svc->seclabel) { if (is_selinux_enabled() > 0 && 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] = '\0'; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } freecon(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 (properties_inited()) notify_service_state(svc->name, "running"); }
void service_start(struct service *svc, const char *dynamic_args) { struct stat s; pid_t pid; int needs_console; char *scon = NULL; int rc; /* 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; } 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; } if (is_selinux_enabled() > 0) { 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]); 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); if (rc == 0 && !strcmp(scon, mycon)) { ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name); } freecon(mycon); freecon(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } } 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); 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); 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); } } freecon(scon); scon = NULL; 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); } } if (svc->seclabel) { if (is_selinux_enabled() > 0 && 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] = '\0'; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } freecon(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 (properties_inited()) notify_service_state(svc->name, "running"); }
static __attribute__ ((noreturn)) void allow(struct su_context *ctx) { char *arg0; int argc, err; umask(ctx->umask); int send_to_app = 1; // no need to log if called by root if (ctx->from.uid == AID_ROOT) send_to_app = 0; // dumpstate (which logs to logcat/shell) will spam the crap out of the system with su calls if (strcmp("/system/bin/dumpstate", ctx->from.bin) == 0) send_to_app = 0; if (send_to_app) send_result(ctx, ALLOW); char *binary; argc = ctx->to.optind; if (ctx->to.command) { binary = ctx->to.shell; ctx->to.argv[--argc] = ctx->to.command; ctx->to.argv[--argc] = "-c"; } else if (ctx->to.shell) { binary = ctx->to.shell; } else { if (ctx->to.argv[argc]) { binary = ctx->to.argv[argc++]; } else { binary = DEFAULT_SHELL; } } arg0 = strrchr (binary, '/'); arg0 = (arg0) ? arg0 + 1 : binary; if (ctx->to.login) { int s = strlen(arg0) + 2; char *p = malloc(s); if (!p) exit(EXIT_FAILURE); *p = '-'; strcpy(p + 1, arg0); arg0 = p; } populate_environment(ctx); set_identity(ctx->to.uid); #define PARG(arg) \ (argc + (arg) < ctx->to.argc) ? " " : "", \ (argc + (arg) < ctx->to.argc) ? ctx->to.argv[argc + (arg)] : "" LOGD("%u %s executing %u %s using binary %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s", ctx->from.uid, ctx->from.bin, ctx->to.uid, get_command(&ctx->to), binary, arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5), (ctx->to.optind + 6 < ctx->to.argc) ? " ..." : ""); if(ctx->to.context) { setexeccon(ctx->to.context); } else { setexeccon("u:r:su:s0"); } ctx->to.argv[--argc] = arg0; execvp(binary, ctx->to.argv + argc); err = errno; PLOGE("exec"); fprintf(stderr, "Cannot execute %s: %s\n", binary, strerror(err)); exit(EXIT_FAILURE); }