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,
#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, &regs)) {
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, &regs)) {
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:
......
......@@ -87,6 +87,7 @@ struct parasite_dump_misc {
unsigned int secbits;
unsigned long brk;
k_rtsigset_t blocked;
};
/*
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
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