Commit 097bc0b9 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Cyrill Gorcunov

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: 's avatarPavel Emelyanov <xemul@parallels.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
parent 447388d7
...@@ -481,32 +481,6 @@ static int dump_task_creds(pid_t pid, ...@@ -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_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)) #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) static int get_task_auxv(pid_t pid, struct core_entry *core)
{ {
int fd = open_proc(pid, "auxv"); int fd = open_proc(pid, "auxv");
...@@ -558,16 +532,20 @@ err: ...@@ -558,16 +532,20 @@ err:
return ret; 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_fpregs_struct_t fpregs = {-1};
user_regs_struct_t regs = {-1}; user_regs_struct_t regs = {-1};
int ret = -1; int ret = -1;
if (ctl)
regs = ctl->regs_orig;
else {
if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) { if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
pr_err("Can't obtain GP registers for %d\n", pid); pr_err("Can't obtain GP registers for %d\n", pid);
goto err; goto err;
} }
}
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) { if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) {
pr_err("Can't obtain FPU registers for %d\n", pid); pr_err("Can't obtain FPU registers for %d\n", pid);
...@@ -658,7 +636,8 @@ static int dump_task_core(struct core_entry *core, struct cr_fdset *fdset) ...@@ -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, 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)); struct core_entry *core = xzalloc(sizeof(*core));
int ret = -1; int ret = -1;
...@@ -672,7 +651,7 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat, ...@@ -672,7 +651,7 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat,
goto err; goto err;
pr_info("Dumping GP/FPU registers ... "); pr_info("Dumping GP/FPU registers ... ");
ret = get_task_regs(pid, core); ret = get_task_regs(pid, core, ctl);
if (ret) if (ret)
goto err_free; goto err_free;
pr_info("OK\n"); pr_info("OK\n");
...@@ -699,11 +678,8 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat, ...@@ -699,11 +678,8 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat,
core->tc.mm_brk = misc->brk; core->tc.mm_brk = misc->brk;
pr_info("Obtainting sigmask ... "); BUILD_BUG_ON(sizeof(core->tc.blk_sigset) != sizeof(k_rtsigset_t));
ret = get_task_sigmask(pid, &core->tc.blk_sigset); memcpy(&core->tc.blk_sigset, &misc->blocked, sizeof(k_rtsigset_t));
if (ret)
goto err_free;
pr_info("OK\n");
pr_info("Obtainting task auvx ... "); pr_info("Obtainting task auvx ... ");
ret = get_task_auxv(pid, core); ret = get_task_auxv(pid, core);
...@@ -1066,7 +1042,7 @@ static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset) ...@@ -1066,7 +1042,7 @@ static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset)
goto err; goto err;
pr_info("Dumping GP/FPU registers ... "); pr_info("Dumping GP/FPU registers ... ");
ret = get_task_regs(pid, core); ret = get_task_regs(pid, core, NULL);
if (ret) if (ret)
goto err_free; goto err_free;
if (ptrace(PTRACE_GET_TID_ADDRESS, pid, NULL, &core->clear_tid_address)) { 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) ...@@ -1204,6 +1180,18 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
goto err; 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); ret = parasite_cure_seized(parasite_ctl);
if (ret) { if (ret) {
pr_err("Can't cure (pid: %d) from parasite\n", pid); 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) ...@@ -1228,12 +1216,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
goto err; 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); ret = finalize_core(pid, &vma_area_list, cr_fdset);
if (ret) { if (ret) {
pr_err("Finalizing core (pid: %d) failed with %d\n", pid, 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) ...@@ -1242,8 +1224,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
free_mappings(&vma_area_list); free_mappings(&vma_area_list);
ret = dump_task_threads(item);
err: err:
close_pid_proc(); close_pid_proc();
err_free: err_free:
......
...@@ -87,6 +87,7 @@ struct parasite_dump_misc { ...@@ -87,6 +87,7 @@ struct parasite_dump_misc {
unsigned int secbits; unsigned int secbits;
unsigned long brk; unsigned long brk;
k_rtsigset_t blocked;
}; };
/* /*
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define __NR_munmap 11 #define __NR_munmap 11
#define __NR_brk 12 #define __NR_brk 12
#define __NR_rt_sigaction 13 #define __NR_rt_sigaction 13
#define __NR_rt_sigprocmask 14
#define __NR_rt_sigreturn 15 #define __NR_rt_sigreturn 15
#define __NR_mincore 27 #define __NR_mincore 27
#define __NR_shmat 30 #define __NR_shmat 30
......
...@@ -241,6 +241,13 @@ static always_inline long sys_rt_sigreturn(void) ...@@ -241,6 +241,13 @@ static always_inline long sys_rt_sigreturn(void)
return syscall0(__NR_rt_sigreturn); 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) static always_inline long sys_set_thread_area(user_desc_t *info)
{ {
return syscall1(__NR_set_thread_area, (long)info); return syscall1(__NR_set_thread_area, (long)info);
......
...@@ -98,6 +98,22 @@ typedef struct { ...@@ -98,6 +98,22 @@ typedef struct {
rt_sigset_t rt_sa_mask; rt_sigset_t rt_sa_mask;
} rt_sigaction_t; } 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 { typedef struct {
unsigned int entry_number; unsigned int entry_number;
unsigned int base_addr; unsigned int base_addr;
......
...@@ -358,12 +358,16 @@ err_close: ...@@ -358,12 +358,16 @@ err_close:
return ret; return ret;
} }
static k_rtsigset_t old_blocked;
static int reset_blocked = 0;
static int dump_misc(struct parasite_dump_misc *args) static int dump_misc(struct parasite_dump_misc *args)
{ {
parasite_status_t *st = &args->status; parasite_status_t *st = &args->status;
args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0); args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
args->brk = sys_brk(0); args->brk = sys_brk(0);
args->blocked = old_blocked;
SET_PARASITE_STATUS(st, 0, 0); SET_PARASITE_STATUS(st, 0, 0);
return 0; return 0;
...@@ -372,6 +376,7 @@ static int dump_misc(struct parasite_dump_misc *args) ...@@ -372,6 +376,7 @@ static int dump_misc(struct parasite_dump_misc *args)
static int init(struct parasite_init_args *args) static int init(struct parasite_init_args *args)
{ {
int ret; int ret;
k_rtsigset_t to_block;
tsock = sys_socket(PF_UNIX, SOCK_DGRAM, 0); tsock = sys_socket(PF_UNIX, SOCK_DGRAM, 0);
if (tsock < 0) { if (tsock < 0) {
...@@ -383,7 +388,14 @@ static int init(struct parasite_init_args *args) ...@@ -383,7 +388,14 @@ static int init(struct parasite_init_args *args)
return -1; 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() static int set_logfd()
...@@ -394,6 +406,8 @@ static int set_logfd() ...@@ -394,6 +406,8 @@ static int set_logfd()
static int fini() static int fini()
{ {
if (reset_blocked == 1)
sys_sigprocmask(SIG_SETMASK, &old_blocked, NULL);
sys_close(logfd); sys_close(logfd);
sys_close(tsock); sys_close(tsock);
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment