int main(int argc, char *argv[]) { struct passwd *pw_entry; struct group *gr_entry; char *shell; int ch; static const struct option longopts[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); close_stdout_atexit(); while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1) switch (ch) { case 'V': print_version(EXIT_SUCCESS); case 'h': usage(); default: errtryhelp(EXIT_FAILURE); } if (!(pw_entry = getpwuid(getuid()))) err(EXIT_FAILURE, _("who are you?")); if (argc < 2) { if (setgid(pw_entry->pw_gid) < 0) err(EXIT_FAILURE, _("setgid failed")); } else { errno = 0; if (!(gr_entry = getgrnam(argv[1]))) { if (errno) err(EXIT_FAILURE, _("no such group")); else errx(EXIT_FAILURE, _("no such group")); } if (!allow_setgid(pw_entry, gr_entry)) errx(EXIT_FAILURE, _("permission denied")); if (setgid(gr_entry->gr_gid) < 0) err(EXIT_FAILURE, _("setgid failed")); } if (setuid(getuid()) < 0) err(EXIT_FAILURE, _("setuid failed")); fflush(NULL); shell = (pw_entry->pw_shell && *pw_entry->pw_shell ? pw_entry->pw_shell : _PATH_BSHELL); execl(shell, shell, (char *)0); errexec(shell); }
void __attribute__((__noreturn__)) exec_shell(void) { const char *shell = getenv("SHELL"); char *shellc = xstrdup(shell); const char *shell_basename; char *arg0; if (!shell) shell = DEFAULT_SHELL; shell_basename = basename(shellc); arg0 = xmalloc(strlen(shell_basename) + 2); arg0[0] = '-'; strcpy(arg0 + 1, shell_basename); execl(shell, arg0, NULL); errexec(shell); }
int main(int argc, char **argv) { pid_t pid = 0; int c, adj = 0, has_adj = 0; static const struct option longopts[] = { { "adjust", required_argument, NULL, 'n' }, { "pid", required_argument, NULL, 'p' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while ((c = getopt_long(argc, argv, "hn:p:V", longopts, NULL)) != -1) { switch (c) { case 'p': pid = strtos32_or_err(optarg, _("invalid PID argument")); break; case 'n': adj = strtos32_or_err(optarg, _("invalid adjust argument")); has_adj = 1; break; case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case 'h': usage(); default: errtryhelp(EXIT_FAILURE); } } if (optind < argc && pid) { warnx(_("invalid argument: %s"), argv[optind]); errtryhelp(EXIT_FAILURE); } if (!pid && argc - optind < 1) { warnx(_("no PID or COMMAND specified")); errtryhelp(EXIT_FAILURE); } if (optind < argc && !has_adj) { warnx(_("no OOM score adjust value specified")); errtryhelp(EXIT_FAILURE); } /* Show */ if (!has_adj) { printf(_("pid %d's current OOM score: %d\n"), pid, get_score(pid)); printf(_("pid %d's current OOM score adjust value: %d\n"), pid, get_score_adj(pid)); /* Change */ } else if (pid) { int old = get_score_adj(pid); if (set_score_adj(pid, adj)) err(EXIT_FAILURE, _("failed to set score adjust value")); printf(_("pid %d's OOM score adjust value changed from %d to %d\n"), pid, old, adj); /* Start new process */ } else { if (set_score_adj(getpid(), adj)) err(EXIT_FAILURE, _("failed to set score adjust value")); argv += optind; execvp(argv[0], argv); errexec(argv[0]); } return EXIT_SUCCESS; }
static int set_sched_one_by_setscheduler(struct chrt_ctl *ctl, pid_t pid) { struct sched_param sp = { .sched_priority = ctl->priority }; int policy = ctl->policy; errno = 0; # ifdef SCHED_RESET_ON_FORK if (ctl->reset_on_fork) policy |= SCHED_RESET_ON_FORK; # endif return sched_setscheduler(pid, policy, &sp); } #ifndef HAVE_SCHED_SETATTR static int set_sched_one(struct chrt_ctl *ctl, pid_t pid) { return set_sched_one_by_setscheduler(ctl, pid); } #else /* !HAVE_SCHED_SETATTR */ static int set_sched_one(struct chrt_ctl *ctl, pid_t pid) { struct sched_attr sa = { .size = sizeof(struct sched_attr) }; /* old API is good enough for non-deadline */ if (ctl->policy != SCHED_DEADLINE) return set_sched_one_by_setscheduler(ctl, pid); /* no changeed by chrt, follow the current setting */ sa.sched_nice = getpriority(PRIO_PROCESS, pid); /* use main() to check if the setting makes sense */ sa.sched_policy = ctl->policy; sa.sched_priority = ctl->priority; sa.sched_runtime = ctl->runtime; sa.sched_period = ctl->period; sa.sched_deadline = ctl->deadline; # ifdef SCHED_RESET_ON_FORK if (ctl->reset_on_fork) sa.sched_flags |= SCHED_RESET_ON_FORK; # endif errno = 0; return sched_setattr(pid, &sa, 0); } #endif /* HAVE_SCHED_SETATTR */ static void set_sched(struct chrt_ctl *ctl) { if (ctl->all_tasks) { pid_t tid; struct proc_tasks *ts = proc_open_tasks(ctl->pid); if (!ts) err(EXIT_FAILURE, _("cannot obtain the list of tasks")); while (!proc_next_tid(ts, &tid)) if (set_sched_one(ctl, tid) == -1) err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid); proc_close_tasks(ts); } else if (set_sched_one(ctl, ctl->pid) == -1) err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid); ctl->altered = 1; } int main(int argc, char **argv) { struct chrt_ctl _ctl = { .pid = -1, .policy = SCHED_RR }, *ctl = &_ctl; int c; static const struct option longopts[] = { { "all-tasks", no_argument, NULL, 'a' }, { "batch", no_argument, NULL, 'b' }, { "deadline", no_argument, NULL, 'd' }, { "fifo", no_argument, NULL, 'f' }, { "idle", no_argument, NULL, 'i' }, { "pid", no_argument, NULL, 'p' }, { "help", no_argument, NULL, 'h' }, { "max", no_argument, NULL, 'm' }, { "other", no_argument, NULL, 'o' }, { "rr", no_argument, NULL, 'r' }, { "sched-runtime", required_argument, NULL, 'T' }, { "sched-period", required_argument, NULL, 'P' }, { "sched-deadline", required_argument, NULL, 'D' }, { "reset-on-fork", no_argument, NULL, 'R' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, no_argument, NULL, 0 } }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while((c = getopt_long(argc, argv, "+abdD:fiphmoP:T:rRvV", longopts, NULL)) != -1) { switch (c) { case 'a': ctl->all_tasks = 1; break; case 'b': #ifdef SCHED_BATCH ctl->policy = SCHED_BATCH; #endif break; case 'd': #ifdef SCHED_DEADLINE ctl->policy = SCHED_DEADLINE; #endif break; case 'f': ctl->policy = SCHED_FIFO; break; case 'R': ctl->reset_on_fork = 1; break; case 'i': #ifdef SCHED_IDLE ctl->policy = SCHED_IDLE; #endif break; case 'm': show_min_max(); return EXIT_SUCCESS; case 'o': ctl->policy = SCHED_OTHER; break; case 'p': errno = 0; ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument")); break; case 'r': ctl->policy = SCHED_RR; break; case 'v': ctl->verbose = 1; break; case 'T': ctl->runtime = strtou64_or_err(optarg, _("invalid runtime argument")); break; case 'P': ctl->period = strtou64_or_err(optarg, _("invalid period argument")); break; case 'D': ctl->deadline = strtou64_or_err(optarg, _("invalid deadline argument")); break; case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case 'h': usage(); default: errtryhelp(EXIT_FAILURE); } } if (((ctl->pid > -1) && argc - optind < 1) || ((ctl->pid == -1) && argc - optind < 2)) { warnx(_("bad usage")); errtryhelp(EXIT_FAILURE); } if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) { show_sched_info(ctl); if (argc - optind == 1) return EXIT_SUCCESS; } errno = 0; ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument")); #ifdef SCHED_RESET_ON_FORK if (ctl->reset_on_fork && ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR) errx(EXIT_FAILURE, _("--reset-on-fork option is supported for " "SCHED_FIFO and SCHED_RR policies only")); #endif #ifdef SCHED_DEADLINE if ((ctl->runtime || ctl->deadline || ctl->period) && ctl->policy != SCHED_DEADLINE) errx(EXIT_FAILURE, _("--sched-{runtime,deadline,period} options " "are supported for SCHED_DEADLINE only")); if (ctl->policy == SCHED_DEADLINE) { /* The basic rule is runtime <= deadline <= period, so we can * make deadline and runtime optional on command line. Note we * don't check any values or set any defaults, it's kernel * responsibility. */ if (ctl->deadline == 0) ctl->deadline = ctl->period; if (ctl->runtime == 0) ctl->runtime = ctl->deadline; } #else if (ctl->runtime || ctl->deadline || ctl->period) errx(EXIT_FAILURE, _("SCHED_DEADLINE is unsupported")); #endif if (ctl->pid == -1) ctl->pid = 0; if (ctl->priority < sched_get_priority_min(ctl->policy) || sched_get_priority_max(ctl->policy) < ctl->priority) errx(EXIT_FAILURE, _("unsupported priority value for the policy: %d: see --max for valid range"), ctl->priority); set_sched(ctl); if (ctl->verbose) show_sched_info(ctl); if (!ctl->pid) { argv += optind + 1; execvp(argv[0], argv); errexec(argv[0]); } return EXIT_SUCCESS; }
int main(int argc, char **argv) { enum { NNP = CHAR_MAX + 1, RUID, EUID, RGID, EGID, REUID, REGID, CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS, INHCAPS, AMBCAPS, LISTCAPS, CAPBSET, SECUREBITS, PDEATHSIG, SELINUX_LABEL, APPARMOR_PROFILE }; static const struct option longopts[] = { { "dump", no_argument, NULL, 'd' }, { "nnp", no_argument, NULL, NNP }, { "no-new-privs", no_argument, NULL, NNP }, { "inh-caps", required_argument, NULL, INHCAPS }, { "ambient-caps", required_argument, NULL, AMBCAPS }, { "list-caps", no_argument, NULL, LISTCAPS }, { "ruid", required_argument, NULL, RUID }, { "euid", required_argument, NULL, EUID }, { "rgid", required_argument, NULL, RGID }, { "egid", required_argument, NULL, EGID }, { "reuid", required_argument, NULL, REUID }, { "regid", required_argument, NULL, REGID }, { "clear-groups", no_argument, NULL, CLEAR_GROUPS }, { "keep-groups", no_argument, NULL, KEEP_GROUPS }, { "init-groups", no_argument, NULL, INIT_GROUPS }, { "groups", required_argument, NULL, GROUPS }, { "bounding-set", required_argument, NULL, CAPBSET }, { "securebits", required_argument, NULL, SECUREBITS }, { "pdeathsig", required_argument, NULL, PDEATHSIG, }, { "selinux-label", required_argument, NULL, SELINUX_LABEL }, { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; static const ul_excl_t excl[] = { /* keep in same order with enum definitions */ {CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS}, {0} }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; int c; struct privctx opts; struct passwd *pw = NULL; int dumplevel = 0; int total_opts = 0; int list_caps = 0; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); memset(&opts, 0, sizeof(opts)); while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); total_opts++; switch (c) { case 'd': dumplevel++; break; case NNP: if (opts.nnp) errx(EXIT_FAILURE, _("duplicate --no-new-privs option")); opts.nnp = 1; break; case RUID: if (opts.have_ruid) errx(EXIT_FAILURE, _("duplicate ruid")); opts.have_ruid = 1; pw = get_passwd(optarg, &opts.ruid, _("failed to parse ruid")); if (pw) { passwd_copy(&opts.passwd, pw); opts.have_passwd = 1; } break; case EUID: if (opts.have_euid) errx(EXIT_FAILURE, _("duplicate euid")); opts.have_euid = 1; opts.euid = get_user(optarg, _("failed to parse euid")); break; case REUID: if (opts.have_ruid || opts.have_euid) errx(EXIT_FAILURE, _("duplicate ruid or euid")); opts.have_ruid = opts.have_euid = 1; pw = get_passwd(optarg, &opts.ruid, _("failed to parse reuid")); opts.euid = opts.ruid; if (pw) { passwd_copy(&opts.passwd, pw); opts.have_passwd = 1; } break; case RGID: if (opts.have_rgid) errx(EXIT_FAILURE, _("duplicate rgid")); opts.have_rgid = 1; opts.rgid = get_group(optarg, _("failed to parse rgid")); break; case EGID: if (opts.have_egid) errx(EXIT_FAILURE, _("duplicate egid")); opts.have_egid = 1; opts.egid = get_group(optarg, _("failed to parse egid")); break; case REGID: if (opts.have_rgid || opts.have_egid) errx(EXIT_FAILURE, _("duplicate rgid or egid")); opts.have_rgid = opts.have_egid = 1; opts.rgid = opts.egid = get_group(optarg, _("failed to parse regid")); break; case CLEAR_GROUPS: if (opts.clear_groups) errx(EXIT_FAILURE, _("duplicate --clear-groups option")); opts.clear_groups = 1; break; case KEEP_GROUPS: if (opts.keep_groups) errx(EXIT_FAILURE, _("duplicate --keep-groups option")); opts.keep_groups = 1; break; case INIT_GROUPS: if (opts.init_groups) errx(EXIT_FAILURE, _("duplicate --init-groups option")); opts.init_groups = 1; break; case GROUPS: if (opts.have_groups) errx(EXIT_FAILURE, _("duplicate --groups option")); parse_groups(&opts, optarg); break; case PDEATHSIG: if (opts.pdeathsig) errx(EXIT_FAILURE, _("duplicate --keep-pdeathsig option")); parse_pdeathsig(&opts, optarg); break; case LISTCAPS: list_caps = 1; break; case INHCAPS: if (opts.caps_to_inherit) errx(EXIT_FAILURE, _("duplicate --inh-caps option")); opts.caps_to_inherit = optarg; break; case AMBCAPS: if (opts.ambient_caps) errx(EXIT_FAILURE, _("duplicate --ambient-caps option")); opts.ambient_caps = optarg; break; case CAPBSET: if (opts.bounding_set) errx(EXIT_FAILURE, _("duplicate --bounding-set option")); opts.bounding_set = optarg; break; case SECUREBITS: if (opts.have_securebits) errx(EXIT_FAILURE, _("duplicate --securebits option")); parse_securebits(&opts, optarg); break; case SELINUX_LABEL: if (opts.selinux_label) errx(EXIT_FAILURE, _("duplicate --selinux-label option")); opts.selinux_label = optarg; break; case APPARMOR_PROFILE: if (opts.apparmor_profile) errx(EXIT_FAILURE, _("duplicate --apparmor-profile option")); opts.apparmor_profile = optarg; break; case 'h': usage(); case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; default: errtryhelp(EXIT_FAILURE); } } if (dumplevel) { if (total_opts != dumplevel || optind < argc) errx(EXIT_FAILURE, _("--dump is incompatible with all other options")); dump(dumplevel); return EXIT_SUCCESS; } if (list_caps) { if (total_opts != 1 || optind < argc) errx(EXIT_FAILURE, _("--list-caps must be specified alone")); list_known_caps(); return EXIT_SUCCESS; } if (argc <= optind) errx(EXIT_FAILURE, _("No program specified")); if ((opts.have_rgid || opts.have_egid) && !opts.keep_groups && !opts.clear_groups && !opts.init_groups && !opts.have_groups) errx(EXIT_FAILURE, _("--[re]gid requires --keep-groups, --clear-groups, --init-groups, or --groups")); if (opts.init_groups && !opts.have_ruid) errx(EXIT_FAILURE, _("--init-groups requires --ruid or --reuid")); if (opts.init_groups && !opts.have_passwd) errx(EXIT_FAILURE, _("uid %ld not found, --init-groups requires an user that " "can be found on the system"), (long) opts.ruid); if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) err(EXIT_FAILURE, _("disallow granting new privileges failed")); if (opts.selinux_label) do_selinux_label(opts.selinux_label); if (opts.apparmor_profile) do_apparmor_profile(opts.apparmor_profile); if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) err(EXIT_FAILURE, _("keep process capabilities failed")); /* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if * possible. */ bump_cap(CAP_SETPCAP); bump_cap(CAP_SETUID); bump_cap(CAP_SETGID); if (capng_apply(CAPNG_SELECT_CAPS) != 0) err(SETPRIV_EXIT_PRIVERR, _("activate capabilities")); if (opts.have_ruid || opts.have_euid) { do_setresuid(&opts); /* KEEPCAPS doesn't work for the effective mask. */ if (capng_apply(CAPNG_SELECT_CAPS) != 0) err(SETPRIV_EXIT_PRIVERR, _("reactivate capabilities")); } if (opts.have_rgid || opts.have_egid) do_setresgid(&opts); if (opts.have_groups) { if (setgroups(opts.num_groups, opts.groups) != 0) err(SETPRIV_EXIT_PRIVERR, _("setgroups failed")); } else if (opts.init_groups) { if (initgroups(opts.passwd.pw_name, opts.passwd.pw_gid) != 0) err(SETPRIV_EXIT_PRIVERR, _("initgroups failed")); } else if (opts.clear_groups) { gid_t x = 0; if (setgroups(0, &x) != 0) err(SETPRIV_EXIT_PRIVERR, _("setgroups failed")); } if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0) err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed")); if (opts.bounding_set) { do_caps(CAP_TYPE_BOUNDING, opts.bounding_set); errno = EPERM; /* capng doesn't set errno if we're missing CAP_SETPCAP */ if (capng_apply(CAPNG_SELECT_BOUNDS) != 0) err(SETPRIV_EXIT_PRIVERR, _("apply bounding set")); } if (opts.caps_to_inherit) { do_caps(CAP_TYPE_INHERITABLE, opts.caps_to_inherit); if (capng_apply(CAPNG_SELECT_CAPS) != 0) err(SETPRIV_EXIT_PRIVERR, _("apply capabilities")); } if (opts.ambient_caps) { do_caps(CAP_TYPE_AMBIENT, opts.ambient_caps); } /* Clear or set parent death signal */ if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0 : opts.pdeathsig) != 0) err(SETPRIV_EXIT_PRIVERR, _("set parent death signal failed")); execvp(argv[optind], argv + optind); errexec(argv[optind]); }