int sys_setreuid(struct lwp *l, const struct sys_setreuid_args *uap, register_t *retval) { /* { syscallarg(uid_t) ruid; syscallarg(uid_t) euid; } */ kauth_cred_t cred = l->l_cred; uid_t ruid, euid, svuid; ruid = SCARG(uap, ruid); euid = SCARG(uap, euid); if (ruid == -1) ruid = kauth_cred_getuid(cred); if (euid == -1) euid = kauth_cred_geteuid(cred); /* Saved uid is set to the new euid if the ruid changed */ svuid = (ruid == kauth_cred_getuid(cred)) ? -1 : euid; return do_setresuid(l, ruid, euid, svuid, ID_R_EQ_R | ID_R_EQ_E | ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); }
/* ARGSUSED */ int sys_seteuid(struct lwp *l, const struct sys_seteuid_args *uap, register_t *retval) { /* { syscallarg(uid_t) euid; } */ return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S); }
/* ARGSUSED */ int sys_setuid(struct lwp *l, const struct sys_setuid_args *uap, register_t *retval) { /* { syscallarg(uid_t) uid; } */ uid_t uid = SCARG(uap, uid); return do_setresuid(l, uid, uid, uid, ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R); }
int main(int argc, char **argv) { enum { NNP = CHAR_MAX + 1, RUID, EUID, RGID, EGID, REUID, REGID, CLEAR_GROUPS, KEEP_GROUPS, GROUPS, INHCAPS, LISTCAPS, CAPBSET, SECUREBITS, SELINUX_LABEL, APPARMOR_PROFILE }; static const struct option longopts[] = { {"dump", no_argument, 0, 'd'}, {"nnp", no_argument, 0, NNP}, {"no-new-privs", no_argument, 0, NNP}, {"inh-caps", required_argument, 0, INHCAPS}, {"list-caps", no_argument, 0, LISTCAPS}, {"ruid", required_argument, 0, RUID}, {"euid", required_argument, 0, EUID}, {"rgid", required_argument, 0, RGID}, {"egid", required_argument, 0, EGID}, {"reuid", required_argument, 0, REUID}, {"regid", required_argument, 0, REGID}, {"clear-groups", no_argument, 0, CLEAR_GROUPS}, {"keep-groups", no_argument, 0, KEEP_GROUPS}, {"groups", required_argument, 0, GROUPS}, {"bounding-set", required_argument, 0, CAPBSET}, {"securebits", required_argument, 0, SECUREBITS}, {"selinux-label", required_argument, 0, SELINUX_LABEL}, {"apparmor-profile", required_argument, 0, APPARMOR_PROFILE}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {NULL, 0, 0, 0} }; static const ul_excl_t excl[] = { /* keep in same order with enum definitions */ {CLEAR_GROUPS, KEEP_GROUPS, GROUPS}, {0} }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; int c; struct privctx opts; 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; opts.ruid = get_user(optarg, _("failed to parse ruid")); 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; opts.ruid = opts.euid = get_user(optarg, _("failed to parse reuid")); 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 GROUPS: if (opts.have_groups) errx(EXIT_FAILURE, _("duplicate --groups option")); parse_groups(&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 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(stdout); case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case '?': usage(stderr); default: errx(EXIT_FAILURE, _("unrecognized option '%c'"), c); } } 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.have_groups) errx(EXIT_FAILURE, _("--[re]gid requires --keep-groups, --clear-groups, or --groups")); if (opts.nnp) if (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.clear_groups) { gid_t x = 0; if (setgroups(0, &x) != 0) err(SETPRIV_EXIT_PRIVERR, _("setgroups failed")); } if (opts.have_securebits) if (prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0) err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed")); if (opts.bounding_set) { do_caps(CAPNG_BOUNDING_SET, 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(CAPNG_INHERITABLE, opts.caps_to_inherit); if (capng_apply(CAPNG_SELECT_CAPS) != 0) err(SETPRIV_EXIT_PRIVERR, _("apply capabilities")); } execvp(argv[optind], argv + optind); err(EXIT_FAILURE, _("cannot execute: %s"), argv[optind]); }