tests: add prctl-name.test, prctl-pdeathsig.test and prctl-tsc.test

Eugene Syromyatnikov evgsyr at gmail.com
Mon Nov 21 12:46:59 UTC 2016


Hello.

Thank you for your contribution. Thanks to it, several bugs in current prctl
decoder implementation have been revealed. Please take a look

On Thu, Nov 17, 2016 at 09:17:27PM +0800, JingPiao Chen wrote:
> From 8995d87f0c27d40d574f032bf483f6ae2b5f7375 Mon Sep 17 00:00:00 2001
> From: JingPiao Chen <chenjingpiao at foxmail.com>
> Date: Thu, 17 Nov 2016 21:15:51 +0800
> Subject: [PATCH] tests: add prctl-name.test, prctl-pdeathsig.test and
>  prctl-tsc.test
> 
> 
> * tests/prctl-name.c:New file.

Missing space.

> * tests/prctl-name.test: Likewise.

The established description format for the new *.test files is "New test".

> * tests/prctl-pdeathsig.c:Likewise.
> * tests/prctl-pdeathsig.test: Likewise.
> * tests/prctl-tsc.c: Likewise.
> * tests/prctl-tsc.test: Likewise

Summing up two previous notes, this part of commit message could be
rewritten as follows:

[[
* tests/prctl-name.c: New file.
* tests/prctl-pdeathsig.c:Likewise.
* tests/prctl-tsc.c: Likewise.
* tests/prctl-name.test: New test.
* tests/prctl-pdeathsig.test: Likewise.
* tests/prctl-tsc.test: Likewise
]]

> * tests/.gitignore: Add prctl-name, prctl-pdeathsig and prctl-tsc.
> * tests/Makefile.am (check_PROGRAMS): Likewise.
> (DECODER_TESTS): Add prctl-name.test, prctl-pdeathsig.test and prctl-tsc.test
> ---
>  tests/.gitignore           |  3 +++
>  tests/Makefile.am          |  6 +++++
>  tests/prctl-name.c         | 63 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/prctl-name.test      |  6 +++++
>  tests/prctl-pdeathsig.c    | 61 ++++++++++++++++++++++++++++++++++++++++++++
>  tests/prctl-pdeathsig.test |  6 +++++
>  tests/prctl-tsc.c          | 60 +++++++++++++++++++++++++++++++++++++++++++
>  tests/prctl-tsc.test       |  6 +++++
>  8 files changed, 211 insertions(+)
>  create mode 100644 tests/prctl-name.c
>  create mode 100755 tests/prctl-name.test
>  create mode 100644 tests/prctl-pdeathsig.c
>  create mode 100755 tests/prctl-pdeathsig.test
>  create mode 100644 tests/prctl-tsc.c
>  create mode 100755 tests/prctl-tsc.test
> 
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 6fc3cd1..8497dfa 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -207,8 +207,11 @@ pkey_free
>  pkey_mprotect
>  poll
>  ppoll
> +prctl-name
> +prctl-pdeathsig
>  prctl-seccomp-filter-v
>  prctl-seccomp-strict
> +prctl-tsc
>  pread64-pwrite64
>  preadv
>  preadv-pwritev
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index df5ddb2..744ed25 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -265,8 +265,11 @@ check_PROGRAMS = \
>  	pkey_mprotect \
>  	poll \
>  	ppoll \
> +	prctl-name \
> +	prctl-pdeathsig \
>  	prctl-seccomp-filter-v \
>  	prctl-seccomp-strict \
> +	prctl-tsc \
>  	pread64-pwrite64 \
>  	preadv \
>  	preadv-pwritev \
> @@ -637,8 +640,11 @@ DECODER_TESTS = \
>  	pkey_mprotect.test \
>  	poll.test \
>  	ppoll.test \
> +	prctl-name.test \
> +	prctl-pdeathsig.test \
>  	prctl-seccomp-filter-v.test \
>  	prctl-seccomp-strict.test \
> +	prctl-tsc.test \
>  	pread64-pwrite64.test \
>  	preadv-pwritev.test \
>  	preadv2-pwritev2.test \
> diff --git a/tests/prctl-name.c b/tests/prctl-name.c
> new file mode 100644
> index 0000000..a508969
> --- /dev/null
> +++ b/tests/prctl-name.c
> @@ -0,0 +1,63 @@
> +/*

It is recommended to have a brief description of the file in the beginning of
this comment block. For example, "Check decoding of prctl
PR_GET_NAME/PR_SET_NAME operations."

> + * Copyright (c) 2016 JingPiao Chen <chenjingpiao at foxmail.com>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "tests.h"
> +#include <asm/unistd.h>
> +
> +#ifdef HAVE_PRCTL
> +# include <sys/prctl.h>
> +#endif
> +
> +#if defined HAVE_PRCTL && defined PR_GET_NAME && defined PR_SET_NAME
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +int
> +main(void)
> +{
> +	char setname[16] = "test-set-name";
> +	char getname[16];

It is preferred to use tail_alloc()-based allocations in order to check
correctness of behaviour comparing to what kernel does regarding reading
data from process's address space. Please have a look:
https://github.com/strace/strace/blob/master/tests/preadv-pwritev.c#L68
https://github.com/strace/strace/blob/master/tests/perf_event_open.c#L182
https://github.com/strace/strace/blob/master/tests/aio.c#L230

> +	long rc;
> +
> +	rc = syscall(__NR_prctl, PR_SET_NAME, setname);
> +	printf("prctl(PR_SET_NAME, \"%s\\0\\0\\0\") = %s\n",
> +			setname, sprintrc(rc));

Note that this behaviour is not what expected judging by prctl(2) and
kernel/sys.c. Please take a look at
https://github.com/strace/strace/commit/43017ef466a8540c09e95da9b602e4e56dca8a94
for a fix.

> +
> +	rc = syscall(__NR_prctl, PR_GET_NAME, getname);
> +	printf("prctl(PR_GET_NAME, \"%s\")       = %s\n",

Traditionally, the alignment produced by -a option is not included in
expected output produced by test; value of -a parameter is set in
accordance with shortest function call output instead.

> +			getname, sprintrc(rc));
> +
> +	puts("+++ exited with 0 +++");
> +	return 0;
> +}
> +
> +#else
> +
> +SKIP_MAIN_UNDEFINED("HAVE_PRCTL && PR_GET_NAME && PR_SET_NAME")
> +
> +#endif

Overall, this test is doesn't check the following corner cases:
 * Inaccessibility of data pointed by arg2
 * Partial inaccessibility of data pointed by arg2
 * Limit on amount of data read by kernel (kernel does not read more than
   TASK_COMM_LEN - 1 bytes and termin)

After fixing up the bug this code revealed, Dmitry decided to rewrite it from
scratch:
https://github.com/strace/strace/blob/master/tests/prctl-name.c

> diff --git a/tests/prctl-name.test b/tests/prctl-name.test
> new file mode 100755
> index 0000000..fae18b3
> --- /dev/null
> +++ b/tests/prctl-name.test
> @@ -0,0 +1,6 @@
> +#!/bin/sh
> +
> +# Check prctl PR_GET_NAME PR_SET_NAME decoding.
> +
> +. "${srcdir=.}/init.sh"
> +run_strace_match_diff -a42 -e trace=prctl
> diff --git a/tests/prctl-pdeathsig.c b/tests/prctl-pdeathsig.c
> new file mode 100644
> index 0000000..db2e7b3
> --- /dev/null
> +++ b/tests/prctl-pdeathsig.c
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright (c) 2016 JingPiao Chen <chenjingpiao at foxmail.com>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "tests.h"
> +#include <asm/unistd.h>
> +
> +#ifdef HAVE_PRCTL
> +# include <sys/prctl.h>
> +#endif
> +
> +#if defined HAVE_PRCTL && defined PR_GET_PDEATHSIG && defined PR_SET_PDEATHSIG
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/signal.h>
> +
> +int
> +main(void)
> +{
> +	int pdeathsig;
> +	long rc;
> +
> +	rc = syscall(__NR_prctl, PR_SET_PDEATHSIG, SIGINT);
> +	printf("prctl(PR_SET_PDEATHSIG, SIGINT)   = %s\n", sprintrc(rc));

Excessive whitespace, as noted above.

> +
> +	rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, &pdeathsig);
> +	printf("prctl(PR_GET_PDEATHSIG, [SIGINT]) = %s\n", sprintrc(rc));

Note that the expected output of this call is depended on success of this and
the previous call (it may fail due to seccomp restrictions, for example).
As a result, it should be checked somehow, for example:

 	int pdeathsig;
 	long rc;
 
-	rc = syscall(__NR_prctl, PR_SET_PDEATHSIG, SIGINT);
+	if ((rc = syscall(__NR_prctl, PR_SET_PDEATHSIG, SIGINT)))
+		perror_msg_and_skip("prctl(PR_SET_PDEATHSIG)");
 	printf("prctl(PR_SET_PDEATHSIG, SIGINT) = %s\n", sprintrc(rc));
 
-	rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, &pdeathsig);
+	if ((rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, &pdeathsig)))
+		perror_msg_and_skip("prctl(PR_GET_PDEATHSIG)");
 	printf("prctl(PR_GET_PDEATHSIG, [SIGINT]) = %s\n", sprintrc(rc));
 
 	puts("+++ exited with 0 +++");

> +
> +	puts("+++ exited with 0 +++");
> +	return 0;
> +}
> +
> +#else
> +
> +SKIP_MAIN_UNDEFINED("HAVE_PRCTL && PR_GET_PDEATHSIG && PR_SET_PDEATHSIG")
> +
> +#endif

This test also lacks checks for unknown signal value, for argument size (see
https://github.com/strace/strace/commit/aeff861218c14cbc5b5bf2c0f1f4ad497bc70a0b
; this is important due to the fact that long and kernel_ulong_t have different
size on X32/N32 ABIs, and prctl does not implement compat syscall for these
ABIs) and for inaccessibility of pointer. For example:

--- a/tests/prctl-pdeathsig.c
+++ b/tests/prctl-pdeathsig.c
@@ -38,17 +38,32 @@
 # include <unistd.h>
 # include <sys/signal.h>
 
+# include "kernel_types.h"
+
 int
 main(void)
 {
-	int pdeathsig;
+	static const kernel_ulong_t bogus_signal =
+		(kernel_ulong_t) 0xbadc0deddeadfeedULL;
+
+	int *pdeathsig = tail_alloc(sizeof(*pdeathsig));
 	long rc;
 
+	rc = syscall(__NR_prctl, PR_SET_PDEATHSIG, bogus_signal);
+	printf("prctl(PR_SET_PDEATHSIG, %llu) = %s\n",
+	       (unsigned long long) bogus_signal, sprintrc(rc));
+
 	if ((rc = syscall(__NR_prctl, PR_SET_PDEATHSIG, SIGINT)))
 		perror_msg_and_skip("prctl(PR_SET_PDEATHSIG)");
 	printf("prctl(PR_SET_PDEATHSIG, SIGINT) = %s\n", sprintrc(rc));
 
-	if ((rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, &pdeathsig)))
+	rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, NULL);
+	printf("prctl(PR_GET_PDEATHSIG, NULL) = %s\n", sprintrc(rc));
+
+	rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, pdeathsig + 1);
+	printf("prctl(PR_GET_PDEATHSIG, %p) = %s\n",
+	       pdeathsig + 1, sprintrc(rc));
+
+	if ((rc = syscall(__NR_prctl, PR_GET_PDEATHSIG, pdeathsig)))
 		perror_msg_and_skip("prctl(PR_GET_PDEATHSIG)");
 	printf("prctl(PR_GET_PDEATHSIG, [SIGINT]) = %s\n", sprintrc(rc));
 

> diff --git a/tests/prctl-pdeathsig.test b/tests/prctl-pdeathsig.test
> new file mode 100755
> index 0000000..5e0be13
> --- /dev/null
> +++ b/tests/prctl-pdeathsig.test
> @@ -0,0 +1,6 @@
> +#!/bin/sh
> +
> +# Check prctl PR_GET_PDEATHSIG PR_SET_PDEATHSIG decoding.
> +
> +. "${srcdir=.}/init.sh"
> +run_strace_match_diff -a34 -e trace=prctl
> diff --git a/tests/prctl-tsc.c b/tests/prctl-tsc.c
> new file mode 100644
> index 0000000..ea8bf61
> --- /dev/null
> +++ b/tests/prctl-tsc.c
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (c) 2016 JingPiao Chen <chenjingpiao at foxmail.com>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "tests.h"
> +#include <asm/unistd.h>
> +
> +#ifdef HAVE_PRCTL
> +# include <sys/prctl.h>
> +#endif
> +
> +#if defined HAVE_PRCTL && defined PR_GET_TSC && defined PR_SET_TSC
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +int
> +main(void)
> +{
> +	int tsc;
> +	long rc;
> +
> +	rc = syscall(__NR_prctl, PR_SET_TSC, PR_TSC_SIGSEGV);
> +	printf("prctl(PR_SET_TSC, PR_TSC_SIGSEGV)   = %s\n", sprintrc(rc));
> +
> +	rc = syscall(__NR_prctl, PR_GET_TSC, &tsc);
> +	printf("prctl(PR_GET_TSC, [PR_TSC_SIGSEGV]) = %s\n", sprintrc(rc));

Note that this command is arch-specific and would fail on architectures other
than x86 (in addition to other possibilities of tampering call execution by
various security modules).

> +
> +	puts("+++ exited with 0 +++");
> +	return 0;
> +}
> +
> +#else
> +
> +SKIP_MAIN_UNDEFINED("HAVE_PRCTL && PR_GET_TSC && PR_SET_TSC")
> +
> +#endif

Notes regarding possible corner cases are generally the same as for the previous
test.

> diff --git a/tests/prctl-tsc.test b/tests/prctl-tsc.test
> new file mode 100755
> index 0000000..c6fe65f
> --- /dev/null
> +++ b/tests/prctl-tsc.test
> @@ -0,0 +1,6 @@
> +#!/bin/sh
> +
> +# Check prctl PR_GET_TSC PR_SET_TSC decoding.
> +
> +. "${srcdir=.}/init.sh"
> +run_strace_match_diff -a36 -e trace=prctl
> -- 
> 2.7.4

> ------------------------------------------------------------------------------

> _______________________________________________
> Strace-devel mailing list
> Strace-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/strace-devel





More information about the Strace-devel mailing list