diff --git a/NEWS b/NEWS index e307dd35690ec13fa79f97fa3462d3ba9eda51f5..d516ea0dd203996222763b6cef08f2be6c0182f5 100644 --- a/NEWS +++ b/NEWS @@ -536,6 +536,10 @@ documents those changes that are of interest to users and admins. -- Remove some use of cr_enabled flag in slurmctld job record, use new flag "test_only" in select_g_job_test() instead. +* Changes in SLURM 1.0.17 +========================= + -- Set correct user groups for task epilogs. + * Changes in SLURM 1.0.16 ========================= -- For "srun --attach=X" to other users job, report an error and exit (it diff --git a/src/slurmd/common/run_script.c b/src/slurmd/common/run_script.c index 0d4d10606c75d9fcc02ce2ac60766046c91670a8..0759d150a04f3d23f306766a30c5351614f2848e 100644 --- a/src/slurmd/common/run_script.c +++ b/src/slurmd/common/run_script.c @@ -52,18 +52,17 @@ /* - * Run a prolog or epilog script - * name IN: class of program (prolog, epilog, etc.), - * if prefix is "user" then also set uid + * Run a prolog or epilog script (does NOT drop privileges) + * name IN: class of program (prolog, epilog, etc.), * path IN: pathname of program to run - * jobid, uid IN: info on associated job + * jobid IN: info on associated job * max_wait IN: maximum time to wait in seconds, -1 for no limit - * env IN: environment variables to use on exec, sets minimal environment + * env IN: environment variables to use on exec, sets minimal environment * if NULL - * RET 0 on success, -1 on failure. + * RET 0 on success, -1 on failure. */ int -run_script(const char *name, const char *path, uint32_t jobid, uid_t uid, +run_script(const char *name, const char *path, uint32_t jobid, int max_wait, char **env) { int status, rc, opt; @@ -90,8 +89,6 @@ run_script(const char *name, const char *path, uint32_t jobid, uid_t uid, argv[0] = (char *)xstrdup(path); argv[1] = NULL; - if (strncmp(name, "user", 4) == 0) - setuid(uid); #ifdef SETPGRP_TWO_ARGS setpgrp(0, 0); #else diff --git a/src/slurmd/common/run_script.h b/src/slurmd/common/run_script.h index c5fc807ec331d38155a00350436cee325c5bb59f..f910043c59ab4734661f0b42afe0683fff7ab2b8 100644 --- a/src/slurmd/common/run_script.h +++ b/src/slurmd/common/run_script.h @@ -43,17 +43,16 @@ #include <inttypes.h> /* - * Run a prolog or epilog script + * Run a prolog or epilog script (does NOT drop privileges) * name IN: class of program (prolog, epilog, etc.), - * if prefix is "user" then also set uid * path IN: pathname of program to run - * jobid, uidIN: info on associated job + * jobid IN: info on associated job * max_wait IN: maximum time to wait in seconds, -1 for no limit * env IN: environment variables to use on exec, sets minimal environment * if NULL * RET 0 on success, -1 on failure. */ int run_script(const char *name, const char *path, uint32_t jobid, - uid_t uid, int max_wait, char **env); + int max_wait, char **env); #endif /* _RUN_SCRIPT_H */ diff --git a/src/slurmd/slurmd/req.c b/src/slurmd/slurmd/req.c index 0384ba8468aefc927a9bf9d619dfd11599c6b973..5add24739059774863dfa9ffe930ff02741c58ce 100644 --- a/src/slurmd/slurmd/req.c +++ b/src/slurmd/slurmd/req.c @@ -2207,8 +2207,7 @@ _run_prolog(uint32_t jobid, uid_t uid, char *bg_part_id) my_prolog = xstrdup(conf->prolog); slurm_mutex_unlock(&conf->config_mutex); - error_code = run_script("prolog", my_prolog, jobid, uid, - -1, my_env); + error_code = run_script("prolog", my_prolog, jobid, -1, my_env); xfree(my_prolog); _destroy_env(my_env); @@ -2226,8 +2225,7 @@ _run_epilog(uint32_t jobid, uid_t uid, char *bg_part_id) my_epilog = xstrdup(conf->epilog); slurm_mutex_unlock(&conf->config_mutex); - error_code = run_script("epilog", my_epilog, jobid, uid, - -1, my_env); + error_code = run_script("epilog", my_epilog, jobid, -1, my_env); xfree(my_epilog); _destroy_env(my_env); diff --git a/src/slurmd/slurmstepd/mgr.c b/src/slurmd/slurmstepd/mgr.c index 37aecf773e2925984c22a701bc6c43c4c2a1c9a7..554e952e5f04cc1eafa75c13ed0b8b33a9e58018 100644 --- a/src/slurmd/slurmstepd/mgr.c +++ b/src/slurmd/slurmstepd/mgr.c @@ -173,6 +173,8 @@ static void _setargs(slurmd_job_t *job); static void _random_sleep(slurmd_job_t *job); static char *_sprint_task_cnt(batch_job_launch_msg_t *msg); +static int _run_script_as_user(const char *name, const char *path, + slurmd_job_t *job, int max_wait, char **env); /* * Batch job mangement prototypes: @@ -1099,17 +1101,18 @@ _wait_for_any_task(slurmd_job_t *job, bool waitflag) setup_env(job->envtp); job->env = job->envtp->env; if (job->task_epilog) { - run_script("user task_epilog", - job->task_epilog, - job->jobid, job->uid, 2, job->env); + _run_script_as_user("user task_epilog", + job->task_epilog, + job, 2, job->env); } if (conf->task_epilog) { char *my_epilog; slurm_mutex_lock(&conf->config_mutex); my_epilog = xstrdup(conf->task_epilog); slurm_mutex_unlock(&conf->config_mutex); - run_script("slurm task_epilog", my_epilog, - job->jobid, job->uid, -1, job->env); + _run_script_as_user("slurm task_epilog", + my_epilog, + job, -1, job->env); xfree(my_epilog); } job->envtp->procid = i; @@ -1125,7 +1128,6 @@ _wait_for_any_task(slurmd_job_t *job, bool waitflag) done: return completed; } - static void _wait_for_all_tasks(slurmd_job_t *job) @@ -1598,3 +1600,85 @@ _initgroups(slurmd_job_t *job) } return 0; } + +/* + * Run a script as a specific user, with the specified uid, gid, and + * extended groups. + * + * name IN: class of program (task prolog, task epilog, etc.), + * path IN: pathname of program to run + * job IN: slurd job structue, used to get uid, gid, and groups + * max_wait IN: maximum time to wait in seconds, -1 for no limit + * env IN: environment variables to use on exec, sets minimal environment + * if NULL + * + * RET 0 on success, -1 on failure. + */ +int +_run_script_as_user(const char *name, const char *path, slurmd_job_t *job, + int max_wait, char **env) +{ + int status, rc, opt; + pid_t cpid; + + xassert(env); + if (path == NULL || path[0] == '\0') + return 0; + + debug("[job %u] attempting to run %s [%s]", job->jobid, name, path); + + if ((cpid = fork()) < 0) { + error ("executing %s: fork: %m", name); + return -1; + } + if (cpid == 0) { + struct priv_state sprivs; + char *argv[2]; + + argv[0] = (char *)xstrdup(path); + argv[1] = NULL; + + if (_drop_privileges(job, true, &sprivs) < 0) { + error("run_script_as_user _drop_privileges: %m"); + /* child process, should not return */ + exit(127); + } + + if (_become_user(job, &sprivs) < 0) { + error("run_script_as_user _become_user failed: %m"); + /* child process, should not return */ + exit(127); + } + + setpgrp(); + execve(path, argv, env); + error("execve(): %m"); + exit(127); + } + + if (max_wait < 0) + opt = 0; + else + opt = WNOHANG; + + while (1) { + rc = waitpid(cpid, &status, opt); + if (rc < 0) { + if (errno == EINTR) + continue; + error("waidpid: %m"); + return 0; + } else if (rc == 0) { + sleep(1); + if ((--max_wait) == 0) { + killpg(cpid, SIGKILL); + opt = 0; + } + } else { + killpg(cpid, SIGKILL); /* kill children too */ + return status; + } + } + + /* NOTREACHED */ +} diff --git a/src/slurmd/slurmstepd/task.c b/src/slurmd/slurmstepd/task.c index a54c7d69cd3b638e708e4fbd8841dff332d51a9a..dce2e536f11fbee7f6f505c15a3e9b0775f0707c 100644 --- a/src/slurmd/slurmstepd/task.c +++ b/src/slurmd/slurmstepd/task.c @@ -89,8 +89,8 @@ * Static prototype definitions. */ static void _make_tmpdir(slurmd_job_t *job); -static int _run_script(const char *name, const char *path, - slurmd_job_t *job); +static int _run_script_and_set_env(const char *name, const char *path, + slurmd_job_t *job); static void _update_env(char *buf, char ***env); /* Search for "export NAME=value" records in buf and @@ -127,16 +127,17 @@ _update_env(char *buf, char ***env) } /* - * Run a task prolog script - * name IN: class of program ("system prolog", "user prolog", etc.), - * if prefix is "user" then also set uid + * Run a task prolog script. Also read the stdout of the script and set + * environment variables in the task's environment as specified + * in the script's standard output. + * name IN: class of program ("system prolog", "user prolog", etc.) * path IN: pathname of program to run * job IN/OUT: pointer to associated job, can update job->env * if prolog * RET 0 on success, -1 on failure. */ static int -_run_script(const char *name, const char *path, slurmd_job_t *job) +_run_script_and_set_env(const char *name, const char *path, slurmd_job_t *job) { int status, rc, nread; pid_t cpid; @@ -348,11 +349,13 @@ exec_task(slurmd_job_t *job, int i, int waitfd) slurm_mutex_lock(&conf->config_mutex); my_prolog = xstrdup(conf->task_prolog); slurm_mutex_unlock(&conf->config_mutex); - _run_script("slurm task_prolog", my_prolog, job); + _run_script_and_set_env("slurm task_prolog", + my_prolog, job); xfree(my_prolog); } if (job->task_prolog) { - _run_script("user task_prolog", job->task_prolog, job); + _run_script_and_set_env("user task_prolog", + job->task_prolog, job); } if (job->env == NULL) {