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

login
register
mail settings
Submitter Stefan Liebler
Date July 4, 2017, 8:22 a.m.
Message ID <7ce52670-669c-d9c0-dcf0-4d328bbeda79@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/21397/
State Superseded
Headers show

Comments

Stefan Liebler - July 4, 2017, 8:22 a.m.
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.
Florian Weimer - July 4, 2017, 9:41 a.m.
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.
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

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
     }
 }