1*ef5ccd6cSJohn Marino /* Linux-specific ptrace manipulation routines.
2*ef5ccd6cSJohn Marino Copyright (C) 2012-2013 Free Software Foundation, Inc.
3*ef5ccd6cSJohn Marino
4*ef5ccd6cSJohn Marino This file is part of GDB.
5*ef5ccd6cSJohn Marino
6*ef5ccd6cSJohn Marino This program is free software; you can redistribute it and/or modify
7*ef5ccd6cSJohn Marino it under the terms of the GNU General Public License as published by
8*ef5ccd6cSJohn Marino the Free Software Foundation; either version 3 of the License, or
9*ef5ccd6cSJohn Marino (at your option) any later version.
10*ef5ccd6cSJohn Marino
11*ef5ccd6cSJohn Marino This program is distributed in the hope that it will be useful,
12*ef5ccd6cSJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*ef5ccd6cSJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*ef5ccd6cSJohn Marino GNU General Public License for more details.
15*ef5ccd6cSJohn Marino
16*ef5ccd6cSJohn Marino You should have received a copy of the GNU General Public License
17*ef5ccd6cSJohn Marino along with this program. If not, see <http://www.gnu.org/licenses/>. */
18*ef5ccd6cSJohn Marino
19*ef5ccd6cSJohn Marino #ifdef GDBSERVER
20*ef5ccd6cSJohn Marino #include "server.h"
21*ef5ccd6cSJohn Marino #else
22*ef5ccd6cSJohn Marino #include "defs.h"
23*ef5ccd6cSJohn Marino #include "gdb_string.h"
24*ef5ccd6cSJohn Marino #endif
25*ef5ccd6cSJohn Marino
26*ef5ccd6cSJohn Marino #include "linux-ptrace.h"
27*ef5ccd6cSJohn Marino #include "linux-procfs.h"
28*ef5ccd6cSJohn Marino #include "buffer.h"
29*ef5ccd6cSJohn Marino #include "gdb_assert.h"
30*ef5ccd6cSJohn Marino #include "gdb_wait.h"
31*ef5ccd6cSJohn Marino
32*ef5ccd6cSJohn Marino /* Find all possible reasons we could fail to attach PID and append these
33*ef5ccd6cSJohn Marino newline terminated reason strings to initialized BUFFER. '\0' termination
34*ef5ccd6cSJohn Marino of BUFFER must be done by the caller. */
35*ef5ccd6cSJohn Marino
36*ef5ccd6cSJohn Marino void
linux_ptrace_attach_warnings(pid_t pid,struct buffer * buffer)37*ef5ccd6cSJohn Marino linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer)
38*ef5ccd6cSJohn Marino {
39*ef5ccd6cSJohn Marino pid_t tracerpid;
40*ef5ccd6cSJohn Marino
41*ef5ccd6cSJohn Marino tracerpid = linux_proc_get_tracerpid (pid);
42*ef5ccd6cSJohn Marino if (tracerpid > 0)
43*ef5ccd6cSJohn Marino buffer_xml_printf (buffer, _("warning: process %d is already traced "
44*ef5ccd6cSJohn Marino "by process %d\n"),
45*ef5ccd6cSJohn Marino (int) pid, (int) tracerpid);
46*ef5ccd6cSJohn Marino
47*ef5ccd6cSJohn Marino if (linux_proc_pid_is_zombie (pid))
48*ef5ccd6cSJohn Marino buffer_xml_printf (buffer, _("warning: process %d is a zombie "
49*ef5ccd6cSJohn Marino "- the process has already terminated\n"),
50*ef5ccd6cSJohn Marino (int) pid);
51*ef5ccd6cSJohn Marino }
52*ef5ccd6cSJohn Marino
53*ef5ccd6cSJohn Marino #if defined __i386__ || defined __x86_64__
54*ef5ccd6cSJohn Marino
55*ef5ccd6cSJohn Marino /* Address of the 'ret' instruction in asm code block below. */
56*ef5ccd6cSJohn Marino extern void (linux_ptrace_test_ret_to_nx_instr) (void);
57*ef5ccd6cSJohn Marino
58*ef5ccd6cSJohn Marino #include <sys/reg.h>
59*ef5ccd6cSJohn Marino #include <sys/mman.h>
60*ef5ccd6cSJohn Marino #include <signal.h>
61*ef5ccd6cSJohn Marino #include <stdint.h>
62*ef5ccd6cSJohn Marino
63*ef5ccd6cSJohn Marino #endif /* defined __i386__ || defined __x86_64__ */
64*ef5ccd6cSJohn Marino
65*ef5ccd6cSJohn Marino /* Test broken off-trunk Linux kernel patchset for NX support on i386. It was
66*ef5ccd6cSJohn Marino removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
67*ef5ccd6cSJohn Marino
68*ef5ccd6cSJohn Marino Test also x86_64 arch for PaX support. */
69*ef5ccd6cSJohn Marino
70*ef5ccd6cSJohn Marino static void
linux_ptrace_test_ret_to_nx(void)71*ef5ccd6cSJohn Marino linux_ptrace_test_ret_to_nx (void)
72*ef5ccd6cSJohn Marino {
73*ef5ccd6cSJohn Marino #if defined __i386__ || defined __x86_64__
74*ef5ccd6cSJohn Marino pid_t child, got_pid;
75*ef5ccd6cSJohn Marino gdb_byte *return_address, *pc;
76*ef5ccd6cSJohn Marino long l;
77*ef5ccd6cSJohn Marino int status, kill_status;
78*ef5ccd6cSJohn Marino
79*ef5ccd6cSJohn Marino return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE,
80*ef5ccd6cSJohn Marino MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
81*ef5ccd6cSJohn Marino if (return_address == MAP_FAILED)
82*ef5ccd6cSJohn Marino {
83*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
84*ef5ccd6cSJohn Marino strerror (errno));
85*ef5ccd6cSJohn Marino return;
86*ef5ccd6cSJohn Marino }
87*ef5ccd6cSJohn Marino
88*ef5ccd6cSJohn Marino /* Put there 'int3'. */
89*ef5ccd6cSJohn Marino *return_address = 0xcc;
90*ef5ccd6cSJohn Marino
91*ef5ccd6cSJohn Marino child = fork ();
92*ef5ccd6cSJohn Marino switch (child)
93*ef5ccd6cSJohn Marino {
94*ef5ccd6cSJohn Marino case -1:
95*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
96*ef5ccd6cSJohn Marino strerror (errno));
97*ef5ccd6cSJohn Marino return;
98*ef5ccd6cSJohn Marino
99*ef5ccd6cSJohn Marino case 0:
100*ef5ccd6cSJohn Marino l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
101*ef5ccd6cSJohn Marino if (l != 0)
102*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
103*ef5ccd6cSJohn Marino strerror (errno));
104*ef5ccd6cSJohn Marino else
105*ef5ccd6cSJohn Marino {
106*ef5ccd6cSJohn Marino #if defined __i386__
107*ef5ccd6cSJohn Marino asm volatile ("pushl %0;"
108*ef5ccd6cSJohn Marino ".globl linux_ptrace_test_ret_to_nx_instr;"
109*ef5ccd6cSJohn Marino "linux_ptrace_test_ret_to_nx_instr:"
110*ef5ccd6cSJohn Marino "ret"
111*ef5ccd6cSJohn Marino : : "r" (return_address) : "%esp", "memory");
112*ef5ccd6cSJohn Marino #elif defined __x86_64__
113*ef5ccd6cSJohn Marino asm volatile ("pushq %0;"
114*ef5ccd6cSJohn Marino ".globl linux_ptrace_test_ret_to_nx_instr;"
115*ef5ccd6cSJohn Marino "linux_ptrace_test_ret_to_nx_instr:"
116*ef5ccd6cSJohn Marino "ret"
117*ef5ccd6cSJohn Marino : : "r" ((uint64_t) (uintptr_t) return_address)
118*ef5ccd6cSJohn Marino : "%rsp", "memory");
119*ef5ccd6cSJohn Marino #else
120*ef5ccd6cSJohn Marino # error "!__i386__ && !__x86_64__"
121*ef5ccd6cSJohn Marino #endif
122*ef5ccd6cSJohn Marino gdb_assert_not_reached ("asm block did not terminate");
123*ef5ccd6cSJohn Marino }
124*ef5ccd6cSJohn Marino
125*ef5ccd6cSJohn Marino _exit (1);
126*ef5ccd6cSJohn Marino }
127*ef5ccd6cSJohn Marino
128*ef5ccd6cSJohn Marino errno = 0;
129*ef5ccd6cSJohn Marino got_pid = waitpid (child, &status, 0);
130*ef5ccd6cSJohn Marino if (got_pid != child)
131*ef5ccd6cSJohn Marino {
132*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
133*ef5ccd6cSJohn Marino (long) got_pid, strerror (errno));
134*ef5ccd6cSJohn Marino return;
135*ef5ccd6cSJohn Marino }
136*ef5ccd6cSJohn Marino
137*ef5ccd6cSJohn Marino if (WIFSIGNALED (status))
138*ef5ccd6cSJohn Marino {
139*ef5ccd6cSJohn Marino if (WTERMSIG (status) != SIGKILL)
140*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
141*ef5ccd6cSJohn Marino (int) WTERMSIG (status));
142*ef5ccd6cSJohn Marino else
143*ef5ccd6cSJohn Marino warning (_("Cannot call inferior functions, Linux kernel PaX "
144*ef5ccd6cSJohn Marino "protection forbids return to non-executable pages!"));
145*ef5ccd6cSJohn Marino return;
146*ef5ccd6cSJohn Marino }
147*ef5ccd6cSJohn Marino
148*ef5ccd6cSJohn Marino if (!WIFSTOPPED (status))
149*ef5ccd6cSJohn Marino {
150*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
151*ef5ccd6cSJohn Marino status);
152*ef5ccd6cSJohn Marino return;
153*ef5ccd6cSJohn Marino }
154*ef5ccd6cSJohn Marino
155*ef5ccd6cSJohn Marino /* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */
156*ef5ccd6cSJohn Marino if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
157*ef5ccd6cSJohn Marino {
158*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: "
159*ef5ccd6cSJohn Marino "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
160*ef5ccd6cSJohn Marino (int) WSTOPSIG (status));
161*ef5ccd6cSJohn Marino return;
162*ef5ccd6cSJohn Marino }
163*ef5ccd6cSJohn Marino
164*ef5ccd6cSJohn Marino errno = 0;
165*ef5ccd6cSJohn Marino #if defined __i386__
166*ef5ccd6cSJohn Marino l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL);
167*ef5ccd6cSJohn Marino #elif defined __x86_64__
168*ef5ccd6cSJohn Marino l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (RIP * 8), NULL);
169*ef5ccd6cSJohn Marino #else
170*ef5ccd6cSJohn Marino # error "!__i386__ && !__x86_64__"
171*ef5ccd6cSJohn Marino #endif
172*ef5ccd6cSJohn Marino if (errno != 0)
173*ef5ccd6cSJohn Marino {
174*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: %s"),
175*ef5ccd6cSJohn Marino strerror (errno));
176*ef5ccd6cSJohn Marino return;
177*ef5ccd6cSJohn Marino }
178*ef5ccd6cSJohn Marino pc = (void *) (uintptr_t) l;
179*ef5ccd6cSJohn Marino
180*ef5ccd6cSJohn Marino kill (child, SIGKILL);
181*ef5ccd6cSJohn Marino ptrace (PTRACE_KILL, child, NULL, NULL);
182*ef5ccd6cSJohn Marino
183*ef5ccd6cSJohn Marino errno = 0;
184*ef5ccd6cSJohn Marino got_pid = waitpid (child, &kill_status, 0);
185*ef5ccd6cSJohn Marino if (got_pid != child)
186*ef5ccd6cSJohn Marino {
187*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: "
188*ef5ccd6cSJohn Marino "PTRACE_KILL waitpid returned %ld: %s"),
189*ef5ccd6cSJohn Marino (long) got_pid, strerror (errno));
190*ef5ccd6cSJohn Marino return;
191*ef5ccd6cSJohn Marino }
192*ef5ccd6cSJohn Marino if (!WIFSIGNALED (kill_status))
193*ef5ccd6cSJohn Marino {
194*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: "
195*ef5ccd6cSJohn Marino "PTRACE_KILL status %d is not WIFSIGNALED!"),
196*ef5ccd6cSJohn Marino status);
197*ef5ccd6cSJohn Marino return;
198*ef5ccd6cSJohn Marino }
199*ef5ccd6cSJohn Marino
200*ef5ccd6cSJohn Marino /* + 1 is there as x86* stops after the 'int3' instruction. */
201*ef5ccd6cSJohn Marino if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
202*ef5ccd6cSJohn Marino {
203*ef5ccd6cSJohn Marino /* PASS */
204*ef5ccd6cSJohn Marino return;
205*ef5ccd6cSJohn Marino }
206*ef5ccd6cSJohn Marino
207*ef5ccd6cSJohn Marino /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */
208*ef5ccd6cSJohn Marino if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
209*ef5ccd6cSJohn Marino {
210*ef5ccd6cSJohn Marino /* PASS */
211*ef5ccd6cSJohn Marino return;
212*ef5ccd6cSJohn Marino }
213*ef5ccd6cSJohn Marino
214*ef5ccd6cSJohn Marino if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
215*ef5ccd6cSJohn Marino warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
216*ef5ccd6cSJohn Marino "address %p nor is the return instruction %p!"),
217*ef5ccd6cSJohn Marino pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
218*ef5ccd6cSJohn Marino else
219*ef5ccd6cSJohn Marino warning (_("Cannot call inferior functions on this system - "
220*ef5ccd6cSJohn Marino "Linux kernel with broken i386 NX (non-executable pages) "
221*ef5ccd6cSJohn Marino "support detected!"));
222*ef5ccd6cSJohn Marino #endif /* defined __i386__ || defined __x86_64__ */
223*ef5ccd6cSJohn Marino }
224*ef5ccd6cSJohn Marino
225*ef5ccd6cSJohn Marino /* Display possible problems on this system. Display them only once per GDB
226*ef5ccd6cSJohn Marino execution. */
227*ef5ccd6cSJohn Marino
228*ef5ccd6cSJohn Marino void
linux_ptrace_init_warnings(void)229*ef5ccd6cSJohn Marino linux_ptrace_init_warnings (void)
230*ef5ccd6cSJohn Marino {
231*ef5ccd6cSJohn Marino static int warned = 0;
232*ef5ccd6cSJohn Marino
233*ef5ccd6cSJohn Marino if (warned)
234*ef5ccd6cSJohn Marino return;
235*ef5ccd6cSJohn Marino warned = 1;
236*ef5ccd6cSJohn Marino
237*ef5ccd6cSJohn Marino linux_ptrace_test_ret_to_nx ();
238*ef5ccd6cSJohn Marino }
239