From 097bc0b9672cf97c87efc203de0e2cc33fa20f19 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 17 Feb 2012 22:56:36 +0400 Subject: [PATCH] dump: Collect mem+regs+sigmask atomically The ptrace seize doesn't prevent signals from delivery. That said, we should block the signals in the target task before dumping anything which is signals-related, i.e. memory and registers. But once we've blocked signals, we should dump registers before unblocking them, since any postponed signal will screw things up. Signed-off-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov --- cr-dump.c | 72 +++++++++++++++-------------------------- include/parasite.h | 1 + include/syscall-codes.h | 1 + include/syscall.h | 7 ++++ include/types.h | 16 +++++++++ parasite.c | 16 ++++++++- 6 files changed, 66 insertions(+), 47 deletions(-) diff --git a/cr-dump.c b/cr-dump.c index 66f44ba52..642755e6f 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -481,32 +481,6 @@ static int dump_task_creds(pid_t pid, #define assign_reg(dst, src, e) dst.e = (__typeof__(dst.e))src.e #define assign_array(dst, src, e) memcpy(&dst.e, &src.e, sizeof(dst.e)) -static int get_task_sigmask(pid_t pid, u64 *task_sigset) -{ - FILE *file; - int ret = -1; - - /* - * Now signals. - */ - file = fopen_proc(pid, "status"); - if (!file) - goto err; - - while (fgets(loc_buf, sizeof(loc_buf), file)) { - if (!strncmp(loc_buf, "SigBlk:", 7)) { - char *end; - *task_sigset = strtol(&loc_buf[8], &end, 16); - ret = 0; - break; - } - } - - fclose(file); -err: - return ret; -} - static int get_task_auxv(pid_t pid, struct core_entry *core) { int fd = open_proc(pid, "auxv"); @@ -558,15 +532,19 @@ err: return ret; } -static int get_task_regs(pid_t pid, struct core_entry *core) +static int get_task_regs(pid_t pid, struct core_entry *core, struct parasite_ctl *ctl) { user_fpregs_struct_t fpregs = {-1}; user_regs_struct_t regs = {-1}; int ret = -1; - if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { - pr_err("Can't obtain GP registers for %d\n", pid); - goto err; + if (ctl) + regs = ctl->regs_orig; + else { + if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { + pr_err("Can't obtain GP registers for %d\n", pid); + goto err; + } } if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) { @@ -658,7 +636,8 @@ static int dump_task_core(struct core_entry *core, struct cr_fdset *fdset) } static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat, - struct parasite_dump_misc *misc, struct cr_fdset *cr_fdset) + struct parasite_dump_misc *misc, struct parasite_ctl *ctl, + struct cr_fdset *cr_fdset) { struct core_entry *core = xzalloc(sizeof(*core)); int ret = -1; @@ -672,7 +651,7 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat, goto err; pr_info("Dumping GP/FPU registers ... "); - ret = get_task_regs(pid, core); + ret = get_task_regs(pid, core, ctl); if (ret) goto err_free; pr_info("OK\n"); @@ -699,11 +678,8 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat, core->tc.mm_brk = misc->brk; - pr_info("Obtainting sigmask ... "); - ret = get_task_sigmask(pid, &core->tc.blk_sigset); - if (ret) - goto err_free; - pr_info("OK\n"); + BUILD_BUG_ON(sizeof(core->tc.blk_sigset) != sizeof(k_rtsigset_t)); + memcpy(&core->tc.blk_sigset, &misc->blocked, sizeof(k_rtsigset_t)); pr_info("Obtainting task auvx ... "); ret = get_task_auxv(pid, core); @@ -1066,7 +1042,7 @@ static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset) goto err; pr_info("Dumping GP/FPU registers ... "); - ret = get_task_regs(pid, core); + ret = get_task_regs(pid, core, NULL); if (ret) goto err_free; if (ptrace(PTRACE_GET_TID_ADDRESS, pid, NULL, &core->clear_tid_address)) { @@ -1204,6 +1180,18 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset) goto err; } + ret = dump_task_core_all(pid, &pps_buf, &misc, parasite_ctl, cr_fdset); + if (ret) { + pr_err("Dump core (pid: %d) failed with %d\n", pid, ret); + goto err; + } + + ret = dump_task_threads(item); + if (ret) { + pr_err("Can't dump threads\n"); + goto err; + } + ret = parasite_cure_seized(parasite_ctl); if (ret) { pr_err("Can't cure (pid: %d) from parasite\n", pid); @@ -1228,12 +1216,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset) goto err; } - ret = dump_task_core_all(pid, &pps_buf, &misc, cr_fdset); - if (ret) { - pr_err("Dump core (pid: %d) failed with %d\n", pid, ret); - goto err; - } - ret = finalize_core(pid, &vma_area_list, cr_fdset); if (ret) { pr_err("Finalizing core (pid: %d) failed with %d\n", pid, ret); @@ -1242,8 +1224,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset) free_mappings(&vma_area_list); - ret = dump_task_threads(item); - err: close_pid_proc(); err_free: diff --git a/include/parasite.h b/include/parasite.h index 96b78c111..59eff7dc7 100644 --- a/include/parasite.h +++ b/include/parasite.h @@ -87,6 +87,7 @@ struct parasite_dump_misc { unsigned int secbits; unsigned long brk; + k_rtsigset_t blocked; }; /* diff --git a/include/syscall-codes.h b/include/syscall-codes.h index 28def9900..2a470c66c 100644 --- a/include/syscall-codes.h +++ b/include/syscall-codes.h @@ -13,6 +13,7 @@ #define __NR_munmap 11 #define __NR_brk 12 #define __NR_rt_sigaction 13 +#define __NR_rt_sigprocmask 14 #define __NR_rt_sigreturn 15 #define __NR_mincore 27 #define __NR_shmat 30 diff --git a/include/syscall.h b/include/syscall.h index 02e5ee6cb..f759587c3 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -241,6 +241,13 @@ static always_inline long sys_rt_sigreturn(void) return syscall0(__NR_rt_sigreturn); } +static always_inline long sys_sigprocmask(int how, k_rtsigset_t *set, + k_rtsigset_t *old) +{ + return syscall4(__NR_rt_sigprocmask, how, (unsigned long)set, + (unsigned long)old, (unsigned long)sizeof(k_rtsigset_t)); +} + static always_inline long sys_set_thread_area(user_desc_t *info) { return syscall1(__NR_set_thread_area, (long)info); diff --git a/include/types.h b/include/types.h index 5d93dac92..dea51e1c3 100644 --- a/include/types.h +++ b/include/types.h @@ -98,6 +98,22 @@ typedef struct { rt_sigset_t rt_sa_mask; } rt_sigaction_t; +#define _KNSIG 64 +# define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +static inline void ksigfillset(k_rtsigset_t *set) +{ + int i; + for (i = 0; i < _KNSIG_WORDS; i++) + set->sig[i] = (unsigned long)-1; +} + typedef struct { unsigned int entry_number; unsigned int base_addr; diff --git a/parasite.c b/parasite.c index a77a94f87..d77a24a82 100644 --- a/parasite.c +++ b/parasite.c @@ -358,12 +358,16 @@ err_close: return ret; } +static k_rtsigset_t old_blocked; +static int reset_blocked = 0; + static int dump_misc(struct parasite_dump_misc *args) { parasite_status_t *st = &args->status; args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0); args->brk = sys_brk(0); + args->blocked = old_blocked; SET_PARASITE_STATUS(st, 0, 0); return 0; @@ -372,6 +376,7 @@ static int dump_misc(struct parasite_dump_misc *args) static int init(struct parasite_init_args *args) { int ret; + k_rtsigset_t to_block; tsock = sys_socket(PF_UNIX, SOCK_DGRAM, 0); if (tsock < 0) { @@ -383,7 +388,14 @@ static int init(struct parasite_init_args *args) return -1; } - return 0; + ksigfillset(&to_block); + ret = sys_sigprocmask(SIG_SETMASK, &to_block, &old_blocked); + if (ret < 0) + reset_blocked = ret; + else + reset_blocked = 1; + + return ret; } static int set_logfd() @@ -394,6 +406,8 @@ static int set_logfd() static int fini() { + if (reset_blocked == 1) + sys_sigprocmask(SIG_SETMASK, &old_blocked, NULL); sys_close(logfd); sys_close(tsock); return 0;