This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch+7.5] Fix assertion fail on PaX gentoo (PR 14564)
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: Pedro Alves <palves at redhat dot com>
- Cc: gdb-patches at sourceware dot org, Anton Kochkov <anton dot kochkov at gmail dot com>
- Date: Mon, 10 Sep 2012 17:46:23 +0200
- Subject: Re: [patch+7.5] Fix assertion fail on PaX gentoo (PR 14564)
- References: <20120909142245.GA26626@host2.jankratochvil.net> <504DF20E.102@redhat.com>
On Mon, 10 Sep 2012 15:58:38 +0200, Pedro Alves wrote:
> On 09/09/2012 03:22 PM, Jan Kratochvil wrote:
> > + if (WIFSIGNALED (status))
> > + {
> > + gdb_assert (WTERMSIG (status) == SIGKILL);
>
> This, and the other assertions in the function make a little
> nervous. It seems like one should be able to make them trigger
> by sending a signal to gdb's process group, or "killall gdb" at
> the wrong time? E.g., a SIGTERM, a SIGINT, or a SIGSTOP? The
> linux_test_for_tracefork family of functions seems to warn
> instead of asserting if something unexpected comes out of
> ptrace/waitpid. Might be a good idea for this function too?
Yes.
Thanks,
Jan
gdb/
2012-09-10 Jan Kratochvil <jan.kratochvil@redhat.com>
* common/linux-ptrace.c: Change __i386__ to __i386__ || __x86_64__.
(linux_ptrace_test_ret_to_nx): Extend comment for x86_64. Change
__i386__ to __i386__ || __x86_64__. Extend code also for __x86_64__.
Extend code also for PaX support. Convert all gdb_assert to warning
calls.
diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c
index fdec5d6..ae17786 100644
--- a/gdb/common/linux-ptrace.c
+++ b/gdb/common/linux-ptrace.c
@@ -49,7 +49,7 @@ linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer)
(int) pid);
}
-#ifdef __i386__
+#if defined __i386__ || defined __x86_64__
/* Address of the 'ret' instruction in asm code block below. */
extern void (linux_ptrace_test_ret_to_nx_instr) (void);
@@ -60,15 +60,17 @@ extern void (linux_ptrace_test_ret_to_nx_instr) (void);
#include <sys/wait.h>
#include <stdint.h>
-#endif /* __i386__ */
+#endif /* defined __i386__ || defined __x86_64__ */
/* Test broken off-trunk Linux kernel patchset for NX support on i386. It was
- removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd. */
+ removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
+
+ Test also x86_64 arch for PaX support. */
static void
linux_ptrace_test_ret_to_nx (void)
{
-#ifdef __i386__
+#if defined __i386__ || defined __x86_64__
pid_t child, got_pid;
gdb_byte *return_address, *pc;
long l;
@@ -101,39 +103,105 @@ linux_ptrace_test_ret_to_nx (void)
strerror (errno));
else
{
+#if defined __i386__
asm volatile ("pushl %0;"
".globl linux_ptrace_test_ret_to_nx_instr;"
"linux_ptrace_test_ret_to_nx_instr:"
"ret"
: : "r" (return_address) : "%esp", "memory");
+#elif defined __x86_64__
+ asm volatile ("pushq %0;"
+ ".globl linux_ptrace_test_ret_to_nx_instr;"
+ "linux_ptrace_test_ret_to_nx_instr:"
+ "ret"
+ : : "r" (return_address) : "%rsp", "memory");
+#else
+# error "!__i386__ && !__x86_64__"
+#endif
gdb_assert_not_reached ("asm block did not terminate");
}
_exit (1);
}
+ errno = 0;
got_pid = waitpid (child, &status, 0);
- gdb_assert (got_pid == child);
- gdb_assert (WIFSTOPPED (status));
+ if (got_pid != child)
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
+ (long) got_pid, strerror (errno));
+ return;
+ }
+
+ if (WIFSIGNALED (status))
+ {
+ if (WTERMSIG (status) != SIGKILL)
+ warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
+ (int) WTERMSIG (status));
+ else
+ warning (_("Cannot call inferior functions, Linux kernel PaX "
+ "protection forbids return to non-executable pages!"));
+ return;
+ }
+
+ if (!WIFSTOPPED (status))
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
+ status);
+ return;
+ }
/* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */
- gdb_assert (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == SIGSEGV);
+ if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: "
+ "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
+ (int) WSTOPSIG (status));
+ return;
+ }
errno = 0;
+#if defined __i386__
l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL);
- gdb_assert (errno == 0);
+#elif defined __x86_64__
+ l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (RIP * 8), NULL);
+#else
+# error "!__i386__ && !__x86_64__"
+#endif
+ if (errno != 0)
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: %s"),
+ strerror (errno));
+ return;
+ }
pc = (void *) (uintptr_t) l;
if (ptrace (PTRACE_KILL, child, NULL, NULL) != 0)
- warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_KILL: %s"),
- strerror (errno));
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_KILL: %s"),
+ strerror (errno));
+ return;
+ }
else
{
int kill_status;
+ errno = 0;
got_pid = waitpid (child, &kill_status, 0);
- gdb_assert (got_pid == child);
- gdb_assert (WIFSIGNALED (kill_status));
+ if (got_pid != child)
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: "
+ "PTRACE_KILL waitpid returned %ld: %s"),
+ (long) got_pid, strerror (errno));
+ return;
+ }
+ if (!WIFSIGNALED (kill_status))
+ {
+ warning (_("linux_ptrace_test_ret_to_nx: "
+ "PTRACE_KILL status %d is not WIFSIGNALED!"),
+ status);
+ return;
+ }
}
/* + 1 is there as x86* stops after the 'int3' instruction. */
@@ -150,11 +218,14 @@ linux_ptrace_test_ret_to_nx (void)
return;
}
- gdb_assert ((void (*) (void)) pc == &linux_ptrace_test_ret_to_nx_instr);
-
- warning (_("Cannot call inferior functions, you have broken "
- "Linux kernel i386 NX (non-executable pages) support!"));
-#endif /* __i386__ */
+ if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
+ warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
+ "address %p nor is the return instruction %p!"),
+ pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
+ else
+ warning (_("Cannot call inferior functions, you have broken "
+ "Linux kernel i386 NX (non-executable pages) support!"));
+#endif /* defined __i386__ || defined __x86_64__ */
}
/* Display possible problems on this system. Display them only once per GDB