1 /* Testing s390x PTRACE_SINGLEBLOCK ptrace request.
2    Copyright (C) 2017-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/wait.h>
24 #include <sys/types.h>
25 #include <sys/uio.h>
26 #include <elf.h>
27 #include <support/xunistd.h>
28 #include <support/check.h>
29 #include <string.h>
30 #include <errno.h>
31 
32 /* Ensure that we use the PTRACE_SINGLEBLOCK definition from glibc ptrace.h
33    in tracer_func.  We need the kernel ptrace.h for structs ptrace_area
34    and gregset_t.  */
35 #include <sys/ptrace.h>
36 static const enum __ptrace_request req_singleblock = PTRACE_SINGLEBLOCK;
37 #include <asm/ptrace.h>
38 
39 static void
tracee_func(int pid)40 tracee_func (int pid)
41 {
42   /* Dump the mapping information for manual inspection of the printed
43      tracee addresses.  */
44   char str[80];
45   sprintf (str, "cat /proc/%d/maps", pid);
46   puts (str);
47   system (str);
48   fflush (stdout);
49 
50   TEST_VERIFY_EXIT (ptrace (PTRACE_TRACEME) == 0);
51   /* Stop tracee.  Afterwards the tracer_func can operate.  */
52   kill (pid, SIGSTOP);
53 
54   puts ("The PTRACE_SINGLEBLOCK of the tracer will stop after: "
55 	"brasl %r14,<puts@plt>!");
56 }
57 
58 static void
tracer_func(int pid)59 tracer_func (int pid)
60 {
61   unsigned long last_break;
62   ptrace_area parea;
63   gregset_t regs;
64   struct iovec parea2;
65   gregset_t regs2;
66 
67   int status;
68   int ret;
69 #define MAX_CHARS_IN_BUF 4096
70   char buf[MAX_CHARS_IN_BUF + 1];
71   size_t buf_count;
72 
73   while (1)
74     {
75       /* Wait for the tracee to be stopped or exited.  */
76       wait (&status);
77       if (WIFEXITED (status))
78 	break;
79 
80       /* Get information about tracee: gprs, last breaking address.  */
81       parea.len = sizeof (regs);
82       parea.process_addr = (unsigned long) &regs;
83       parea.kernel_addr = 0;
84       TEST_VERIFY_EXIT (ptrace (PTRACE_PEEKUSR_AREA, pid, &parea) == 0);
85       TEST_VERIFY_EXIT (ptrace (PTRACE_GET_LAST_BREAK, pid, NULL, &last_break)
86 			== 0);
87 
88       parea2.iov_len = sizeof (regs2);
89       parea2.iov_base = &regs2;
90       TEST_VERIFY_EXIT (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &parea2)
91 			== 0);
92       TEST_VERIFY_EXIT (parea2.iov_len == sizeof (regs2));
93 
94       /* Test if gprs obtained by PTRACE_PEEKUSR_AREA and PTRACE_GETREGESET
95 	 have the same values.  */
96       TEST_VERIFY_EXIT (memcmp (&regs, &regs2, sizeof (regs)) == 0);
97 
98       printf ("child IA: %p last_break: %p\n",
99 	      (void *) regs[1], (void *) last_break);
100 
101       /* Execute tracee until next taken branch.
102 
103 	 Note:
104 	 Before the commit which introduced this testcase,
105 	 <glibc>/sysdeps/unix/sysv/linux/s390/sys/ptrace.h
106 	 uses ptrace-request 12 for PTRACE_GETREGS,
107 	 but <kernel>/include/uapi/linux/ptrace.h
108 	 uses 12 for PTRACE_SINGLEBLOCK.
109 
110 	 The s390 kernel has no support for PTRACE_GETREGS!
111 	 Thus glibc ptrace.h is adjusted to match kernel ptrace.h.
112 
113 	 The glibc sys/ptrace.h header contains the identifier
114 	 PTRACE_SINGLEBLOCK in enum __ptrace_request.  In contrast, the kernel
115 	 asm/ptrace.h header defines PTRACE_SINGLEBLOCK.
116 
117 	 This test ensures, that PTRACE_SINGLEBLOCK defined in glibc
118 	 works as expected.  If the kernel would interpret it as
119 	 PTRACE_GETREGS, then the tracee will not make any progress
120 	 and this testcase will time out or the ptrace call will fail with
121 	 different errors.  */
122 
123       /* Ptrace request 12 is first done with data argument pointing to
124 	 a buffer:
125 	 -If request 12 is interpreted as PTRACE_GETREGS, it will store the regs
126 	 to buffer without an error.
127 
128 	 -If request 12 is interpreted as PTRACE_SINGLEBLOCK, it will fail
129 	 as data argument is used as signal-number and the address of
130 	 buf is no valid signal.
131 
132 	 -If request 12 is not implemented, it will also fail.
133 
134 	 Here the test expects that the buffer is untouched and an error is
135 	 returned.  */
136       memset (buf, 'a', MAX_CHARS_IN_BUF);
137       ret = ptrace (req_singleblock, pid, NULL, buf);
138       buf [MAX_CHARS_IN_BUF] = '\0';
139       buf_count = strspn (buf, "a");
140       TEST_VERIFY_EXIT (buf_count == MAX_CHARS_IN_BUF);
141       TEST_VERIFY_EXIT (ret == -1);
142 
143       /* If request 12 is interpreted as PTRACE_GETREGS, the first ptrace
144 	 call will touch the buffer which is detected by this test.  */
145       errno = 0;
146       ret = ptrace (req_singleblock, pid, NULL, NULL);
147       if (ret == 0)
148 	{
149 	  /* The kernel has support for PTRACE_SINGLEBLOCK ptrace request. */
150 	  TEST_VERIFY_EXIT (errno == 0);
151 	}
152       else
153 	{
154 	  /* The kernel (< 3.15) has no support for PTRACE_SINGLEBLOCK ptrace
155 	     request. */
156 	  TEST_VERIFY_EXIT (errno == EIO);
157 	  TEST_VERIFY_EXIT (ret == -1);
158 
159 	  /* Just continue tracee until it exits normally.  */
160 	  TEST_VERIFY_EXIT (ptrace (PTRACE_CONT, pid, NULL, NULL) == 0);
161 	}
162     }
163 }
164 
165 static int
do_test(void)166 do_test (void)
167 {
168   int pid;
169   pid = xfork ();
170   if (pid)
171     tracer_func (pid);
172   else
173     tracee_func (getpid ());
174 
175   return EXIT_SUCCESS;
176 }
177 
178 #include <support/test-driver.c>
179