Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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]);
}