redmine

Added options "--privileged-uid" and "--privileged-gid"

... ... @@ -128,6 +128,8 @@ enum flags_enum {
CANCEL_SYSCALLS = 44|OPTION_LONGOPTONLY,
EXITONSYNCSKIP = 45|OPTION_LONGOPTONLY,
DETACH_IPC = 46|OPTION_LONGOPTONLY,
PRIVILEGEDUID = 47|OPTION_LONGOPTONLY,
PRIVILEGEDGID = 48|OPTION_LONGOPTONLY,
};
typedef enum flags_enum flags_t;
... ... @@ -300,6 +302,8 @@ struct ctx {
size_t pid_str_len;
uid_t uid;
gid_t gid;
uid_t privileged_uid;
gid_t privileged_gid;
uid_t synchandler_uid;
gid_t synchandler_gid;
#ifdef CAPABILITIES_SUPPORT
... ...
... ... @@ -79,6 +79,8 @@ static const struct option long_options[] =
{"pid-file", required_argument, NULL, PIDFILE},
{"uid", required_argument, NULL, UID},
{"gid", required_argument, NULL, GID},
{"privileged-uid", required_argument, NULL, PRIVILEGEDUID},
{"privileged-gid", required_argument, NULL, PRIVILEGEDGID},
{"sync-handler-uid", required_argument, NULL, SYNCHANDLERUID},
{"sync-handler-gid", required_argument, NULL, SYNCHANDLERGID},
{"chroot", required_argument, NULL, CHROOT},
... ... @@ -1047,6 +1049,30 @@ static int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsour
break;
}
# endif
case PRIVILEGEDUID: {
struct passwd *pwd = getpwnam(arg);
ctx_p->flags[param_id]++;
if (pwd == NULL) {
ctx_p->privileged_uid = (unsigned int)xstrtol(arg, &ret);
break;
}
ctx_p->privileged_uid = pwd->pw_uid;
break;
}
case PRIVILEGEDGID: {
struct group *grp = getgrnam(arg);
ctx_p->flags[param_id]++;
if (grp == NULL) {
ctx_p->privileged_gid = (unsigned int)xstrtol(arg, &ret);
break;
}
ctx_p->privileged_gid = grp->gr_gid;
break;
}
case SYNCHANDLERUID: {
struct passwd *pwd = getpwnam(arg);
ctx_p->flags[param_id]++;
... ... @@ -2339,8 +2365,6 @@ int main(int _argc, char *_argv[]) {
#ifdef CAPABILITIES_SUPPORT
ctx_p->flags[CAP_PRESERVE] = CAP_PRESERVE_TRY;
ctx_p->caps = DEFAULT_PRESERVE_CAPABILITIES;
ctx_p->synchandler_uid = getuid();
ctx_p->synchandler_gid = getgid();
ctx_p->flags[CAPS_INHERIT] = DEFAULT_CAPS_INHERIT;
ctx_p->flags[DETACH_IPC] = DEFAULT_DETACH_IPC;
parse_parameter(ctx_p, LABEL, strdup(DEFAULT_LABEL), PS_DEFAULTS);
... ... @@ -2373,6 +2397,16 @@ int main(int _argc, char *_argv[]) {
if(nret) ret = nret;
}
if (!ctx_p->flags[PRIVILEGEDUID])
ctx_p->privileged_uid = getuid();
if (!ctx_p->flags[PRIVILEGEDGID])
ctx_p->privileged_gid = getgid();
if (!ctx_p->flags[SYNCHANDLERUID])
ctx_p->synchandler_uid = ctx_p->privileged_uid;
if (!ctx_p->flags[SYNCHANDLERGID])
ctx_p->synchandler_gid = ctx_p->privileged_gid;
#ifdef CGROUP_SUPPORT
if (ctx_p->cg_groupname == NULL) {
ctx_p->cg_groupname = parameter_expand(ctx_p, strdup(DEFAULT_CG_GROUPNAME), 2, NULL, NULL, parameter_get, ctx_p);
... ... @@ -2819,26 +2853,24 @@ int main(int _argc, char *_argv[]) {
if (ctx_p->flags[GID]) {
int rc;
debug(3, "Trying to drop gid to %i", ctx_p->gid);
rc = setgid(ctx_p->gid);
debug(3, "Trying to drop effective gid to %i", ctx_p->gid);
rc = setegid(ctx_p->gid);
if (rc && (ctx_p->flags[GID] != UGID_PRESERVE)) {
error("Cannot setgid(%u)", ctx_p->gid);
error("Cannot setegid(%u)", ctx_p->gid);
ret = errno;
}
if (!rc) debug(4, "success");
}
if (ctx_p->flags[UID]) {
int rc;
debug(3, "Trying to drop uid to %i", ctx_p->uid);
rc = setuid(ctx_p->uid);
debug(3, "Trying to drop effective uid to %i", ctx_p->uid);
rc = seteuid(ctx_p->uid);
if (rc && (ctx_p->flags[UID] != UGID_PRESERVE)) {
error("Cannot setuid(%u)", ctx_p->uid);
error("Cannot seteuid(%u)", ctx_p->uid);
ret = errno;
}
if (!rc) debug(4, "success");
}
if (main_statusfile_f == NULL && ctx_p->statusfile != NULL) {
... ...
... ... @@ -1260,6 +1260,26 @@ found), otherwise the option is not set by default;
.PP
.RE
.B \-\-privileged\-uid
.I sync\-handler\-uid
.RS
An user ID to be used for the privileged process
.BR "" "(see " "--splitting=process" ")".
The default value is "$UID".
.PP
.RE
.B \-\-privileged\-gid
.I sync\-handler\-gid
.RS
A group ID to be used for the privileged process
.BR "" "(see " "--splitting=process" ")".
The default value is "$GID".
.PP
.RE
.B \-\-sync\-handler\-uid
.I sync\-handler\-uid
.RS
... ... @@ -1269,7 +1289,8 @@ An user ID to be used for
See
.BR \-\-preserve\-capabilities .
The default value is "$UID".
The default value is same as for
.BR \-\-privileged-uid .
.PP
.RE
... ... @@ -1282,7 +1303,8 @@ A group ID to be used for
See
.BR \-\-preserve\-capabilities .
The default value is "$GID".
The default value is same as for
.BR \-\-privileged-gid .
.PP
.RE
... ...
... ... @@ -133,6 +133,8 @@ int nonprivileged_seccomp_init(ctx_t *ctx_p) {
.filter = filter_w_mprotect_table,
};
debug(5, "enabling the seccomp");
filter_p = (ctx_p->flags[PERMIT_MPROTECT] ? &filter_w_mprotect : &filter);
SAFE (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), return -1);
... ... @@ -143,7 +145,7 @@ int nonprivileged_seccomp_init(ctx_t *ctx_p) {
#endif
int (*privileged_fork_execvp)(const char *file, char *const argv[]);
int (*privileged_kill_child)(pid_t pid, int sig);
int (*privileged_kill_child)(pid_t pid, int sig, char ignoreerrors);
#ifdef CAPABILITIES_SUPPORT
pid_t helper_pid = 0;
... ... @@ -219,6 +221,7 @@ struct pa_fork_execvp_arg {
struct pa_kill_child_arg {
pid_t pid;
int signal;
char ignoreerrors;
};
struct pa_waitpid_arg {
... ... @@ -444,13 +447,14 @@ int cap_drop(ctx_t *ctx_p, __u32 caps) {
}
#endif
int __privileged_kill_child_itself(pid_t child_pid, int signal) {
int __privileged_kill_child_itself(pid_t child_pid, int signal, char ignoreerrors) {
// Checking if it's a child
if (waitpid(child_pid, NULL, WNOHANG)>=0) {
debug(3, "Sending signal %u to child process with pid %u.",
signal, child_pid);
if (kill(child_pid, signal)) {
error("Got error while kill(%u, %u)", child_pid, signal);
if (!ignoreerrors)
error("Got error while kill(%u, %u)", child_pid, signal);
return errno;
}
... ... @@ -534,14 +538,18 @@ int privileged_execvp_check_arguments(struct pa_options *opts, const char *u_fil
critical_on (!argc);
// Checking the execution file
if (pa_strcmp(argv[0], u_file, isexpanded[0]))
continue;
if (pa_strcmp(argv[0], u_file, isexpanded[0])) {
debug(1, "The file to be executed didn't match (argv[0] != u_file): \"%s\" != \"%s\"", argv[0], u_file);
break;
}
// Checking arguments
i = 1;
while (i < argc) {
if (pa_strcmp(argv[i], u_argv[i], isexpanded[i]))
if (pa_strcmp(argv[i], u_argv[i], isexpanded[i])) {
debug(1, "An argument #%i didn't match (argv[%i] != u_argv[%i]): \"%s\" != \"%s\"", argv[i], argv[i]);
break;
}
i++;
}
... ... @@ -577,6 +585,7 @@ int privileged_execvp_check_arguments(struct pa_options *opts, const char *u_fil
}
}
debug(1, "a_i == %i; SHARGS_MAX == %i; u_argc == %i", SHARGS_MAX, a_i, u_argc);
critical("Arguments are wrong. This should happend only on hacking attack.");
return EPERM;
}
... ... @@ -1017,8 +1026,16 @@ int privileged_handler(ctx_t *ctx_p)
error("Cannot fork().");
break;
case 0:
debug(4, "setgid(%u) == %i", exec_gid, setgid(exec_gid));
debug(4, "setuid(%u) == %i", exec_uid, setuid(exec_uid));
#ifdef ANTIPARANOID
if (ctx_p->privileged_gid != exec_gid)
#endif
debug(4, "setgid(%u) == %i", exec_gid, setgid(exec_gid));
#ifdef ANTIPARANOID
if (ctx_p->privileged_uid != exec_uid)
#endif
debug(4, "setuid(%u) == %i", exec_uid, setuid(exec_uid));
debug(3, "execvp(\"%s\", argv)", file);
exit(execvp(file, argv));
}
... ... @@ -1029,7 +1046,7 @@ int privileged_handler(ctx_t *ctx_p)
case PA_KILL_CHILD: {
debug(20, "PA_KILL_CHILD");
struct pa_kill_child_arg *arg_p = (void *)&cmd_p->arg.kill_child;
cmd_ret_p->ret = (void *)(long)__privileged_kill_child_itself(arg_p->pid, arg_p->signal);
cmd_ret_p->ret = (void *)(long)__privileged_kill_child_itself(arg_p->pid, arg_p->signal, arg_p->ignoreerrors);
break;
}
# ifdef CGROUP_SUPPORT
... ... @@ -1544,12 +1561,13 @@ int __privileged_fork_setuid_execvp_threadsplit(
return (long)ret;
}
int __privileged_kill_child_wrapper(pid_t pid, int signal)
int __privileged_kill_child_wrapper(pid_t pid, int signal, char ignoreerrors)
{
void *ret = (void *)(long)-1;
cmd_p->arg.kill_child.pid = pid;
cmd_p->arg.kill_child.signal = signal;
cmd_p->arg.kill_child.pid = pid;
cmd_p->arg.kill_child.signal = signal;
cmd_p->arg.kill_child.ignoreerrors = ignoreerrors;
privileged_action(
# ifdef HL_LOCK_TRIES_AUTO
... ... @@ -1781,14 +1799,43 @@ int privileged_init(ctx_t *ctx_p)
// Running the privileged helper
SAFE ( (helper_pid = fork_helper()) == -1, return errno);
if (!helper_pid)
if (!helper_pid) {
if (ctx_p->privileged_gid != ctx_p->gid) {
// SAFE ( cap_enable(CAP_TO_MASK(CAP_SETGID)), return errno; );
debug(3, "[privileged] Trying to set real gid to %i (ctx_p->privileged_gid)", ctx_p->privileged_gid);
SAFE( setgid(ctx_p->privileged_gid), return errno);
}
if (ctx_p->privileged_uid != ctx_p->uid) {
// SAFE ( cap_enable(CAP_TO_MASK(CAP_SETUID)), return errno; );
debug(3, "[privileged] Trying to set real uid to %i (ctx_p->privileged_uid)", ctx_p->privileged_uid);
SAFE( setuid(ctx_p->privileged_uid), return errno);
}
exit(privileged_handler(ctx_p));
}
break;
}
default:
critical("Invalid ctx_p->flags[SPLITTING]: %i", ctx_p->flags[SPLITTING]);
}
if (ctx_p->flags[GID] || ctx_p->flags[UID])
SAFE( seteuid(0), return errno);
if (ctx_p->flags[GID]) {
SAFE( setegid(0), return errno);
debug(3, "[non-privileged] Trying to drop real gid %i (ctx_p->gid)", getgid(), ctx_p->gid);
SAFE( setgid(ctx_p->gid), return errno );
}
if (ctx_p->flags[UID]) {
debug(3, "[non-privileged] Trying to drop real uid %i (ctx_p->uid)", getuid(), ctx_p->uid);
SAFE( setuid(ctx_p->uid), return errno );
}
# ifdef HL_LOCKS
if (ncpus == 1)
hl_shutdown(HLLOCK_HANDLER);
... ... @@ -1883,9 +1930,10 @@ int privileged_deinit(ctx_t *ctx_p)
case SM_PROCESS: {
int status;
if (!ctx_p->flags[SECCOMP_FILTER]) {
__privileged_kill_child_itself(helper_pid, SIGKILL);
debug(9, "waitpid(%u, ...)", helper_pid);
waitpid(helper_pid, &status, 0);
if (!__privileged_kill_child_itself(helper_pid, SIGKILL, 1)) {
debug(9, "waitpid(%u, ...)", helper_pid);
waitpid(helper_pid, &status, 0);
}
}
shm_free((void *)cmd_p);
shm_free((void *)cmd_ret_p);
... ...
... ... @@ -123,7 +123,8 @@ extern int privileged_check();
extern int (*_privileged_kill_child)(
pid_t pid,
int sig
int sig,
char ignoreerrors
);
extern int (*_privileged_fork_execvp)(
... ...
... ... @@ -3673,15 +3673,15 @@ int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
while (ctx_p->children) { // Killing children if non-pthread mode or/and (mode=="so" or mode=="rsyncso")
pid_t child_pid = ctx_p->child_pid[--ctx_p->children];
if (privileged_kill_child(child_pid, signal) == ENOENT)
if (privileged_kill_child(child_pid, signal, 0) == ENOENT)
continue;
if (signal != SIGQUIT)
if (privileged_kill_child(child_pid, SIGQUIT) == ENOENT)
if (privileged_kill_child(child_pid, SIGQUIT, 0) == ENOENT)
continue;
if (signal != SIGTERM)
if (privileged_kill_child(child_pid, SIGTERM) == ENOENT)
if (privileged_kill_child(child_pid, SIGTERM, 0) == ENOENT)
continue;
if (privileged_kill_child(child_pid, SIGKILL) == ENOENT)
if (privileged_kill_child(child_pid, SIGKILL, 0) == ENOENT)
continue;
}
break;
... ...