Commit 48fcc799 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

ptrace: flush breakpoints

Unfortunately the kernel doesn't flush hw breakpoints on
detaching ptrace. If a breakpoint is triggered without ptrace, it
will be killed by SIGTRAP.

Reported-by: Mr Jenkins
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 3b2ab35b
......@@ -113,4 +113,9 @@ static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif
......@@ -155,4 +155,9 @@ static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif
......@@ -540,3 +540,16 @@ int ptrace_set_breakpoint(pid_t pid, void *addr)
return 1;
}
int ptrace_flush_breakpoints(pid_t pid)
{
/* Disable the breakpoint */
if (ptrace(PTRACE_POKEUSER, pid,
offsetof(struct user, u_debugreg[DR_CONTROL]),
0)) {
pr_err("Unable to disable the breakpoint\n");
return -1;
}
return 0;
}
......@@ -146,6 +146,7 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, fpu_state_t *fpu_stat
static inline void restore_tls(tls_t *ptls) { (void)ptls; }
int ptrace_set_breakpoint(pid_t pid, void *addr);
int ptrace_flush_breakpoints(pid_t pid);
#endif
......@@ -1599,6 +1599,18 @@ static int attach_to_tasks(bool root_seized, enum trace_flags *flag)
return 0;
}
static int clear_breakpoints()
{
struct pstree_item *item;
int ret = 0, i;
for_each_pstree_item(item)
for (i = 0; i < item->nr_threads; i++)
ret |= ptrace_flush_breakpoints(item->threads[i].real);
return ret;
}
static void finalize_restore(int status)
{
struct pstree_item *item;
......@@ -1775,6 +1787,9 @@ static int restore_root_task(struct pstree_item *init)
ret = parasite_stop_on_syscall(task_entries->nr_threads,
__NR_rt_sigreturn, flag);
if (clear_breakpoints())
pr_err("Unable to flush breakpoints\n");
/*
* finalize_restore() always detaches from processes and
* they continue run through sigreturn.
......
......@@ -890,6 +890,9 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
if (parasite_stop_on_syscall(1, __NR_rt_sigreturn, flag))
return -1;
if (ptrace_flush_breakpoints(pid))
return -1;
/*
* All signals are unblocked now. The kernel notifies about leaving
* syscall before starting to deliver signals. All parasite code are
......
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