diff --git a/cr-restore.c b/cr-restore.c index 0b9d60116..f1cb7067f 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1159,6 +1159,8 @@ static inline int stage_participants(int next_stage) case CR_STATE_RESTORE: case CR_STATE_RESTORE_SIGCHLD: return task_entries->nr_threads; + case CR_STATE_RESTORE_CREDS: + return task_entries->nr_threads; } BUG(); @@ -1239,11 +1241,16 @@ static int restore_root_task(struct pstree_item *init, struct cr_options *opts) if (ret < 0) goto out; - pr_info("Wait until all tasks are restored\n"); + pr_info("Wait until all tasks restored sigchld handlers\n"); ret = restore_switch_stage(CR_STATE_RESTORE_SIGCHLD); if (ret < 0) goto out; + pr_info("Wait until all tasks are restored\n"); + ret = restore_switch_stage(CR_STATE_RESTORE_CREDS); + if (ret < 0) + goto out; + futex_wait_until(&task_entries->nr_in_progress, 0); /* Restore SIGCHLD here to skip SIGCHLD from a network sctip */ diff --git a/include/restorer.h b/include/restorer.h index 842cc5e96..ef19d64f6 100644 --- a/include/restorer.h +++ b/include/restorer.h @@ -164,6 +164,13 @@ enum { CR_STATE_RESTORE_PGID, CR_STATE_RESTORE, CR_STATE_RESTORE_SIGCHLD, + /* + * For security reason processes can be resumed only when all + * credentials are restored. Otherwise someone can attach to a + * process, which are not restored credentials yet and execute + * some code. + */ + CR_STATE_RESTORE_CREDS, CR_STATE_COMPLETE }; diff --git a/pie/restorer.c b/pie/restorer.c index 7cd7372a4..4feea0c61 100644 --- a/pie/restorer.c +++ b/pie/restorer.c @@ -53,6 +53,8 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) sys_getpid(), siginfo->si_pid, siginfo->si_pid); futex_dec_and_wake(&task_entries->nr_in_progress); futex_dec_and_wake(&zombies_inprogress); + task_entries->nr_threads--; + task_entries->nr_tasks--; mutex_unlock(&task_entries->zombie_lock); return; } @@ -264,6 +266,7 @@ long __export_restore_thread(struct thread_restore_args *args) goto core_restore_end; restore_finish_stage(CR_STATE_RESTORE_SIGCHLD); + restore_finish_stage(CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); new_sp = (long)rt_sigframe + SIGFRAME_OFFSET; @@ -757,13 +760,8 @@ long __export_restore_task(struct task_restore_core_args *args) if (ret) goto core_restore_end; - futex_set_and_wake(&thread_inprogress, args->nr_threads); - restore_finish_stage(CR_STATE_RESTORE_SIGCHLD); - /* Wait until children stop to use args->task_entries */ - futex_wait_while_gt(&thread_inprogress, 1); - if (args->siginfo_size) { ret = sys_munmap(args->siginfo, args->siginfo_size); if (ret < 0) { @@ -782,6 +780,13 @@ long __export_restore_task(struct task_restore_core_args *args) restore_creds(&args->creds); + futex_set_and_wake(&thread_inprogress, args->nr_threads); + + restore_finish_stage(CR_STATE_RESTORE_CREDS); + + /* Wait until children stop to use args->task_entries */ + futex_wait_while_gt(&thread_inprogress, 1); + log_set_fd(-1); /*