From a724acf57115ea8f425d596ddc20acfd1f05fdcd Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Mon, 29 Apr 2013 16:32:24 +0400 Subject: [PATCH] restore: handle errors of setting credentials (v2) v2: handle errors from setXids and securebits manipulations handle errors of restoring creds after finishing CR_STATE_RESTORE_CREDS, because a sigchild handler is already restored in this moment. Only the current process is killed in a error case. Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- cr-restore.c | 12 ++++++++ include/restorer.h | 1 + pie/restorer.c | 71 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/cr-restore.c b/cr-restore.c index f1cb7067f..d9f074b68 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -56,6 +56,7 @@ #include "cpu.h" #include "file-lock.h" #include "page-read.h" +#include "sysctl.h" #include "protobuf.h" #include "protobuf/sa.pb-c.h" @@ -1464,6 +1465,17 @@ static int prepare_creds(int pid, struct task_restore_core_args *args) int fd, ret; CredsEntry *ce; + struct sysctl_req req[] = { + { "kernel/cap_last_cap", &args->cap_last_cap, CTL_U32 }, + { }, + }; + + ret = sysctl_op(req, CTL_READ); + if (ret < 0) { + pr_err("Failed to read max IPC message size\n"); + return -1; + } + fd = open_image(CR_FD_CREDS, O_RSTR, pid); if (fd < 0) return fd; diff --git a/include/restorer.h b/include/restorer.h index ef19d64f6..6a9da84e9 100644 --- a/include/restorer.h +++ b/include/restorer.h @@ -120,6 +120,7 @@ struct task_restore_core_args { uint32_t cap_prm[CR_CAP_SIZE]; uint32_t cap_eff[CR_CAP_SIZE]; uint32_t cap_bnd[CR_CAP_SIZE]; + uint32_t cap_last_cap; MmEntry mm; auxv_t mm_saved_auxv[AT_VECTOR_SIZE]; diff --git a/pie/restorer.c b/pie/restorer.c index 4feea0c61..b92b54d11 100644 --- a/pie/restorer.c +++ b/pie/restorer.c @@ -40,6 +40,7 @@ static struct task_entries *task_entries; static futex_t thread_inprogress; static futex_t zombies_inprogress; +static int cap_last_cap; extern void cr_restore_rt (void) asm ("__cr_restore_rt") __attribute__ ((visibility ("hidden"))); @@ -74,9 +75,9 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) sys_exit_group(1); } -static void restore_creds(CredsEntry *ce) +static int restore_creds(CredsEntry *ce) { - int b, i; + int b, i, ret; struct cap_header hdr; struct cap_data data[_LINUX_CAPABILITY_U32S_3]; @@ -89,7 +90,11 @@ static void restore_creds(CredsEntry *ce) * lose caps bits when changing xids. */ - sys_prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP, 0, 0, 0); + ret = sys_prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP, 0, 0, 0); + if (ret) { + pr_err("Unable to set SECURE_NO_SETUID_FIXUP: %d\n", ret); + return -1; + } /* * Second -- restore xids. Since we still have the CAP_SETUID @@ -97,17 +102,40 @@ static void restore_creds(CredsEntry *ce) * to override the setresXid settings. */ - sys_setresuid(ce->uid, ce->euid, ce->suid); + ret = sys_setresuid(ce->uid, ce->euid, ce->suid); + if (ret) { + pr_err("Unable to set real, effective and saved user ID: %d\n", ret); + return -1; + } + sys_setfsuid(ce->fsuid); - sys_setresgid(ce->gid, ce->egid, ce->sgid); + if (sys_setfsuid(-1) != ce->fsuid) { + pr_err("Unable to set fsuid\n"); + return -1; + } + + ret = sys_setresgid(ce->gid, ce->egid, ce->sgid); + if (ret) { + pr_err("Unable to set real, effective and saved group ID: %d\n", ret); + return -1; + } + sys_setfsgid(ce->fsgid); + if (sys_setfsgid(-1) != ce->fsgid) { + pr_err("Unable to set fsgid\n"); + return -1; + } /* * Third -- restore securebits. We don't need them in any * special state any longer. */ - sys_prctl(PR_SET_SECUREBITS, ce->secbits, 0, 0, 0); + ret = sys_prctl(PR_SET_SECUREBITS, ce->secbits, 0, 0, 0); + if (ret) { + pr_err("Unable to set PR_SET_SECUREBITS: %d\n", ret); + return -1; + } /* * Fourth -- trim bset. This can only be done while @@ -116,11 +144,17 @@ static void restore_creds(CredsEntry *ce) for (b = 0; b < CR_CAP_SIZE; b++) { for (i = 0; i < 32; i++) { + if (b * 32 + i > cap_last_cap) + break; if (ce->cap_bnd[b] & (1 << i)) /* already set */ continue; - - sys_prctl(PR_CAPBSET_DROP, i + b * 32, 0, 0, 0); + ret = sys_prctl(PR_CAPBSET_DROP, i + b * 32, 0, 0, 0); + if (ret) { + pr_err("Unable to drop capability %d: %d\n", + i + b * 32, ret); + return -1; + } } } @@ -140,7 +174,13 @@ static void restore_creds(CredsEntry *ce) data[i].inh = ce->cap_inh[i]; } - sys_capset(&hdr, data); + ret = sys_capset(&hdr, data); + if (ret) { + pr_err("Unable to restore capabilities: %d\n", ret); + return -1; + } + + return 0; } static void restore_sched_info(struct rst_sched_param *p) @@ -242,6 +282,7 @@ long __export_restore_thread(struct thread_restore_args *args) struct rt_sigframe *rt_sigframe; unsigned long new_sp; int my_pid = sys_gettid(); + int ret; if (my_pid != args->pid) { pr_err("Thread pid mismatch %d/%d\n", my_pid, args->pid); @@ -255,8 +296,9 @@ long __export_restore_thread(struct thread_restore_args *args) mutex_unlock(&args->ta->rst_lock); - restore_creds(&args->ta->creds); - + ret = restore_creds(&args->ta->creds); + if (ret) + goto core_restore_end; pr_info("%ld: Restored\n", sys_gettid()); @@ -466,6 +508,8 @@ long __export_restore_task(struct task_restore_core_args *args) log_set_fd(args->logfd); log_set_loglevel(args->loglevel); + cap_last_cap = args->cap_last_cap; + pr_info("Switched to the restorer %d\n", my_pid); for (vma_entry = args->self_vmas; vma_entry->start != 0; vma_entry++) { @@ -778,12 +822,15 @@ long __export_restore_task(struct task_restore_core_args *args) * thus restore* creds _after_ all of the above. */ - restore_creds(&args->creds); + ret = restore_creds(&args->creds); futex_set_and_wake(&thread_inprogress, args->nr_threads); restore_finish_stage(CR_STATE_RESTORE_CREDS); + if (ret) + BUG(); + /* Wait until children stop to use args->task_entries */ futex_wait_while_gt(&thread_inprogress, 1);