diff mbox

S390: Sync ptrace.h with kernel. [BZ #21539]

Message ID 7ce52670-669c-d9c0-dcf0-4d328bbeda79@linux.vnet.ibm.com
State Superseded
Headers show

Commit Message

Stefan Liebler July 4, 2017, 8:22 a.m. UTC
On 06/30/2017 12:09 PM, Florian Weimer wrote:
> On 06/19/2017 03:10 PM, Stefan Liebler wrote:
>>      	* sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c:
>>      	New file.
> 
> The test fails for me like this on s390x:
> 
> [root@ibm-z-25 build]# bash testrun.sh misc/tst-ptrace-singleblock
> cat /proc/23548/maps
> 80000000-80004000 r-xp 00000000 fd:00 1883202
> /root/build/misc/tst-ptrace-singleblock
> 80004000-80005000 r--p 00003000 fd:00 1883202
> /root/build/misc/tst-ptrace-singleblock
> 80005000-80006000 rw-p 00004000 fd:00 1883202
> /root/build/misc/tst-ptrace-singleblock
> 2aa00794000-2aa007ba000 r-xp 00000000 fd:00 34794498
> /root/build/elf/ld.so
> 2aa007ba000-2aa007bb000 r--p 00025000 fd:00 34794498
> /root/build/elf/ld.so
> 2aa007bb000-2aa007bd000 rw-p 00026000 fd:00 34794498
> /root/build/elf/ld.so
> 3fffd1e9000-3fffd1ea000 rw-s 00000000 00:04 146001
> /dev/zero (deleted)
> 3fffd1ea000-3fffd1ec000 rw-p 00000000 00:00 0
> 3fffd1ec000-3fffd38d000 r-xp 00000000 fd:00 34794501
> /root/build/libc.so
> 3fffd38d000-3fffd391000 r--p 001a0000 fd:00 34794501
> /root/build/libc.so
> 3fffd391000-3fffd393000 rw-p 001a4000 fd:00 34794501
> /root/build/libc.so
> 3fffd393000-3fffd39a000 rw-p 00000000 00:00 0
> 3ffffe62000-3fffff83000 rw-p 00000000 00:00 0
> [stack]
> child IA: 0x3fffd22ac62 last_break: 0x2aa0079e218
> error: ../sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c:111: not
> true: ptrace (req_singleblock, pid, NULL, NULL) == 0
> The PTRACE_SINGLEBLOCK of the tracer will stop after: brasl %r14,<puts@plt>!
> error: 1 test failures
> [root@ibm-z-25 build]#
> 
> Relevant package versions:
> 
> kernel-3.10.0-689.el7.s390x
> kernel-headers-3.10.0-689.el7.s390x
> devtoolset-6-gcc-6.3.1-3.1.el7.s390x
> 
> Please let me know if you need additional information to debug this.
> 
> Thanks,
> Florian
> 

Uuups. I also see this behaviour on a RHEL 7.3 machine.
We've checked that request 12 wasn't used in s390 kernel for other 
meanings as PTRACE_SINGLEBLOCK. But we've missed the fact, that it has 
been introduced with kernel 3.15. On older kernels -1 is returned with 
errno EIO.

Please have a look at the attached patch. I've adjusted the test:

Now ptrace request 12 is first done with data argument pointing to
a buffer:
-If request 12 is interpreted as PTRACE_GETREGS, it will store the regs
to buffer without an error. Here the test expects that the buffer is
untouched and an error is returned.

-If request 12 is interpreted as PTRACE_SINGLEBLOCK, it will fail
as data argument is no valid signal.

-If request 12 is not implemented, it will also fail.


Afterwards the request 12 is done with zero data argument:
-If the kernel has support for PTRACE_SINGLEBLOCK (then the kernel
header asm/ptrace.h defines this macro), the ptrace call is not allowed
to fail and has to continue the tracee until next taken branch.

-If the kernel has no support for PTRACE_SINGLEBLOCK, the ptrace call
has to fail with EIO. Then I continue the tracee with PTRACE_CONT.

-If the request 12 is interpreted as PTRACE_GETREGS, it will fail too.
It fails with EFAULT on intel / power as data argument is NULL.
According to the man-page: "Unfortunately, under Linux, different
variations of this fault will return EIO or EFAULT more or less
arbitrarily".
But if request 12 is interpreted as PTRACE_GETREGS, the first ptrace
call will touch the buffer which is detected by this test.

Any thoughts?
If this change is okay, I'll commit it.

Thanks.
Stefan


ChangeLog:

	* sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c:
	Support running on kernels without PTRACE_SINGLEBLOCK.

Comments

Florian Weimer July 4, 2017, 9:41 a.m. UTC | #1
On 07/04/2017 10:22 AM, Stefan Liebler wrote:
> +      /* Ptrace request 12 is done with zero data argument:
> +	 -If the kernel has support for PTRACE_SINGLEBLOCK (then the kernel
> +	 header asm/ptrace.h defines this macro), the ptrace call is not allowed
> +	 to fail and has to continue the tracee until next taken branch.

I think this is still bogus.  We can compile with newer kernel headers
than the host kernel, and this will cause the test to fail.

Thanks,
Florian
Stefan Liebler July 4, 2017, 3:37 p.m. UTC | #2
On 07/04/2017 11:41 AM, Florian Weimer wrote:
> On 07/04/2017 10:22 AM, Stefan Liebler wrote:
>> +      /* Ptrace request 12 is done with zero data argument:
>> +	 -If the kernel has support for PTRACE_SINGLEBLOCK (then the kernel
>> +	 header asm/ptrace.h defines this macro), the ptrace call is not allowed
>> +	 to fail and has to continue the tracee until next taken branch.
> 
> I think this is still bogus.  We can compile with newer kernel headers
> than the host kernel, and this will cause the test to fail.
> 
> Thanks,
> Florian
> 

Okay.
So I can check the return value of the second ptrace (req_singleblock, 
pid, NULL, NULL) call at runtime to determine the kernel-support:

       errno = 0;
       ret = ptrace (req_singleblock, pid, NULL, NULL);
       if (ret == 0)
	{
	  /* The kernel has support for PTRACE_SINGLEBLOCK ptrace request. */
	  TEST_VERIFY_EXIT (errno == 0);
	}
       else
	{
	  /* The kernel (< 3.15) has no support for PTRACE_SINGLEBLOCK ptrace
	     request. */
	  TEST_VERIFY_EXIT (errno == EIO);
	  TEST_VERIFY_EXIT (ret == -1);

	  /* Just continue tracee until it exits normally.  */
	  TEST_VERIFY_EXIT (ptrace (PTRACE_CONT, pid, NULL, NULL) == 0);
	}



Then the test runs on kernels with / without support for 
PTRACE_SINGLEBLOCK. The first ptrace call ensures that request 12 is not 
interpreted as PTRACE_GETREGS.

Bye.
Stefan
diff mbox

Patch

commit 5e668ce6055d6c690dec773b41c11a801265cd21
Author: Stefan Liebler <stli@linux.vnet.ibm.com>
Date:   Tue Jul 4 10:20:05 2017 +0200

    S390: Fix tst-ptrace-singleblock if kernel does not support PTRACE_SINGLEBLOCK.
    
    The request PTRACE_SINGLEBLOCK was introduced  in Linux 3.15.  Thus the ptrace call
    will fail on older kernels.
    Thus the test is now testing PTRACE_SINGLEBLOCK with data argument pointing to a
    buffer on stack which is assumed to fail.  If the request would be interpreted as
    PTRACE_GETREGS, then the ptrace call will not fail and the regs are written to buf.
    
    If we run with a kernel with support for PTRACE_SINGLEBLOCK a ptrace call with
    data=NULL, is not allowed to fail.  If we run with a kernel without support for
    PTRACE_SINGLEBLOCK a ptrace call with data=NULL, has to fail with EIO.
    
    ChangeLog:
    
    	* sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c:
    	Support running on kernels without PTRACE_SINGLEBLOCK.

diff --git a/sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c b/sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c
index 95a2f55..65858cb 100644
--- a/sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c
+++ b/sysdeps/unix/sysv/linux/s390/tst-ptrace-singleblock.c
@@ -26,6 +26,8 @@ 
 #include <elf.h>
 #include <support/xunistd.h>
 #include <support/check.h>
+#include <string.h>
+#include <errno.h>
 
 /* Ensure that we use the PTRACE_SINGLEBLOCK definition from glibc ptrace.h
    in tracer_func.  We need the kernel ptrace.h for structs ptrace_area
@@ -63,6 +65,10 @@  tracer_func (int pid)
   gregset_t regs2;
 
   int status;
+  int ret;
+#define MAX_CHARS_IN_BUF 4096
+  char buf[MAX_CHARS_IN_BUF + 1];
+  size_t buf_count;
 
   while (1)
     {
@@ -104,11 +110,67 @@  tracer_func (int pid)
 	 The s390 kernel has no support for PTRACE_GETREGS!
 	 Thus glibc ptrace.h is adjusted to match kernel ptrace.h.
 
+	 The glibc sys/ptrace.h header contains the identifier
+	 PTRACE_SINGLEBLOCK in enum __ptrace_request.  In contrast, the kernel
+	 asm/ptrace.h header defines PTRACE_SINGLEBLOCK.
+
 	 This test ensures, that PTRACE_SINGLEBLOCK defined in glibc
 	 works as expected.  If the kernel would interpret it as
 	 PTRACE_GETREGS, then the tracee will not make any progress
-	 and this testcase will time out.  */
-      TEST_VERIFY_EXIT (ptrace (req_singleblock, pid, NULL, NULL) == 0);
+	 and this testcase will time out or the ptrace call will fail with
+	 different errors.  */
+
+      /* Ptrace request 12 is first done with data argument pointing to
+	 a buffer:
+	 -If request 12 is interpreted as PTRACE_GETREGS, it will store the regs
+	 to buffer without an error.
+
+	 -If request 12 is interpreted as PTRACE_SINGLEBLOCK, it will fail
+	 as data argument is used as signal-number and the address of
+	 buf is no valid signal.
+
+	 -If request 12 is not implemented, it will also fail.
+
+	 Here the test expects that the buffer is untouched and an error is
+	 returned.  */
+      memset (buf, 'a', MAX_CHARS_IN_BUF);
+      ret = ptrace (req_singleblock, pid, NULL, buf);
+      buf [MAX_CHARS_IN_BUF] = '\0';
+      buf_count = strspn (buf, "a");
+      TEST_VERIFY_EXIT (buf_count == MAX_CHARS_IN_BUF);
+      TEST_VERIFY_EXIT (ret == -1);
+
+      /* Ptrace request 12 is done with zero data argument:
+	 -If the kernel has support for PTRACE_SINGLEBLOCK (then the kernel
+	 header asm/ptrace.h defines this macro), the ptrace call is not allowed
+	 to fail and has to continue the tracee until next taken branch.
+
+	 -If the kernel (<3.15) has no support for PTRACE_SINGLEBLOCK, the
+	 ptrace call has to fail with EIO. Then I continue the tracee with
+	 PTRACE_CONT.
+
+	 -If the request 12 is interpreted as PTRACE_GETREGS, it will fail too.
+	 It fails with EFAULT on intel / power as data argument is NULL.
+	 According to the man-page: "Unfortunately, under Linux, different
+	 variations of this fault will return EIO or EFAULT more or less
+	 arbitrarily".
+	 But if request 12 is interpreted as PTRACE_GETREGS, the first ptrace
+	 call will touch the buffer which is detected by this test.  */
+      errno = 0;
+      ret = ptrace (req_singleblock, pid, NULL, NULL);
+#ifdef PTRACE_SINGLEBLOCK
+      /* The kernel has support for PTRACE_SINGLEBLOCK ptrace request. */
+      TEST_VERIFY_EXIT (errno == 0);
+      TEST_VERIFY_EXIT (ret == 0);
+#else
+      /* The kernel (< 3.15) has no support for PTRACE_SINGLEBLOCK ptrace
+	 request. */
+      TEST_VERIFY_EXIT (errno == EIO);
+      TEST_VERIFY_EXIT (ret == -1);
+
+      /* Just continue tracee until it exits normally.  */
+      TEST_VERIFY_EXIT (ptrace (PTRACE_CONT, pid, NULL, NULL) == 0);
+#endif
     }
 }