mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-04 00:05:26 +00:00
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 <xemul@parallels.com> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
This commit is contained in:
committed by
Cyrill Gorcunov
parent
447388d79b
commit
097bc0b967
66
cr-dump.c
66
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,16 +532,20 @@ 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 (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)) {
|
||||
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)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
16
parasite.c
16
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;
|
||||
|
||||
Reference in New Issue
Block a user