[PATCH v7 7/8] tests: check fd filter

Eugene Syromiatnikov esyr at redhat.com
Mon Aug 14 02:13:47 UTC 2017


On Fri, Aug 11, 2017 at 05:43:52PM +0700, Nikolay Marchuk wrote:
> * tests/filtering_fd-syntax.test: New file.
> * tests/filtering_fd.c: Likewise.
> * tests/filtering_fd.test: Likewise.
> * tests/options-syntax.test: Remove fd filtering checks.
> * tests/.gitignore: Add filtering_fd.
> * tests/Makefile.am (check_PROGRAMS): Add filtering_fd.
> (MISC_TESTS): Add filering_fd-syntax.test, filtering_fd.test.
> ---
>  tests/.gitignore               |   1 +
>  tests/Makefile.am              |   3 +
>  tests/filtering_fd-syntax.test |  71 +++++++++++++++
>  tests/filtering_fd.c           | 202 +++++++++++++++++++++++++++++++++++++++++
>  tests/filtering_fd.test        |  29 ++++++
>  tests/options-syntax.test      |  11 ---
>  6 files changed, 306 insertions(+), 11 deletions(-)
>  create mode 100755 tests/filtering_fd-syntax.test
>  create mode 100644 tests/filtering_fd.c
>  create mode 100755 tests/filtering_fd.test
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 16c2ca07..d08bea1d 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -70,6 +70,7 @@ fflush
>  file_handle
>  file_ioctl
>  filter-unavailable
> +filtering_fd
>  finit_module
>  flock
>  fork-f
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 6b90d710..5db04749 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -92,6 +92,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
>  	execve-v \
>  	execveat-v \
>  	filter-unavailable \
> +	filtering_fd \
>  	fork-f \
>  	getpid	\
>  	getppid	\
> @@ -257,6 +258,8 @@ MISC_TESTS = \
>  	detach-stopped.test \
>  	filter-unavailable.test \
>  	fflush.test \
> +	filtering_fd-syntax.test \
> +	filtering_fd.test \
>  	filtering_syscall-syntax.test \
>  	get_regs.test \
>  	interactive_block.test \
> diff --git a/tests/filtering_fd-syntax.test b/tests/filtering_fd-syntax.test
> new file mode 100755
> index 00000000..c885aa88
> --- /dev/null
> +++ b/tests/filtering_fd-syntax.test
> @@ -0,0 +1,71 @@
> +#!/bin/sh
> +#
> +# Check fd set parsing syntax.
> +#
> +# Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a at gmail.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.
> +
> +. "${srcdir=.}/syntax.sh"
> +
> +check_fd_invalid()
> +{
> +	check_e "invalid descriptor '$1'" -e "trace(fd $2 && fd 0)"
> +	check_e "invalid descriptor '$1'" -e "read=$2"
> +	check_e "invalid descriptor '$1'" -e "write=$2"
> +}
> +
> +for arg in '' , ,, \
> +	   \! \
> +	   -1 -42 \
> +	   not_fd \
> +	   2147483648 \
> +	   4294967296 \
> +	   ; do
> +	check_fd_invalid "$arg" "$arg"
> +done
> +
> +check_fd_invalid '!' '0,!'
> +
> +check_e "invalid descriptor '!'" -e "trace(fd !, && fd 0)"
> +check_e "invalid descriptor '!,'" -e "read=!,"
> +check_e "invalid descriptor '!,'" -e "write=!,"
> +
> +check_fd_inversion()
> +{
> +	check_e "invalid descriptor '!$1'" -e "trace(fd !$2 && fd 0)"
> +	check_e "invalid descriptor '$1'" -e "read=!$2"
> +	check_e "invalid descriptor '$1'" -e "write=!$2"
> +}
> +
> +for arg in -1 -42 \
> +	   not_fd \
> +	   2147483648 \
> +	   4294967296 \
> +	   ; do
> +	check_fd_inversion "$arg" "$arg"
> +done
> +
> +check_e "invalid descriptor '!1'" -e "trace(fd \!1)"
> +check_e "invalid descriptor '!2'" -e "trace(fd \!2)"
> diff --git a/tests/filtering_fd.c b/tests/filtering_fd.c
> new file mode 100644
> index 00000000..f09a6782
> --- /dev/null
> +++ b/tests/filtering_fd.c
> @@ -0,0 +1,202 @@
> +/*
> + * Check decoding of non-standard fd filters
> + *
> + * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a at gmail.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>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <sys/mman.h>
> +
> +#define FD_TRACED_DEFAULT 5
> +
> +#ifdef __NR_dup2
> +void
> +test_dup2(int fd_base)
> +{
> +	int rc = dup2(fd_base, -1);
> +	printf("dup2(%d, -1) = %s\n", fd_base, sprintrc(rc));
> +	dup2(fd_base + 1, -1);
> +
> +	rc = dup2(-1, fd_base);
> +	printf("dup2(-1, %d) = %s\n", fd_base, sprintrc(rc));
> +	dup2(-1, fd_base + 1);
> +}
> +#else
> +void
> +test_dup2(int fd_base)
> +{
> +}
You can write it in a single line:

    void test_dup2(int fd_base) {}

but it's more lake a matter of taste.

> +#endif
> +
> +#ifdef __NR_linkat
> +void
> +test_linkat(int fd_base)
> +{
> +	int rc = linkat(fd_base, "old", -1, "new", 0);
> +	printf("linkat(%d, \"old\", -1, \"new\", 0) = %s\n",
> +	       fd_base, sprintrc(rc));
> +	linkat(fd_base + 1, "old", -1, "new", 0);
> +
> +	rc = linkat(-1, "old", fd_base, "new", 0);
> +	printf("linkat(-1, \"old\", %d, \"new\", 0) = %s\n",
> +	       fd_base, sprintrc(rc));
> +	linkat(-1, "old", fd_base + 1, "new", 0);
> +}
> +#else
> +void
> +test_linkat(int fd_base)
> +{
> +}
> +#endif
> +
> +#ifdef __NR_symlinkat
> +void
> +test_symlinkat(int fd_base)
> +{
> +	int rc = symlinkat("new", fd_base, "old");
> +	printf("symlinkat(\"new\", %d, \"old\") = %s\n",
> +	       fd_base, sprintrc(rc));
> +	symlinkat("new", fd_base + 1, "old");
> +}
> +#else
> +void
> +test_symlinkat(int fd_base)
> +{
> +}
> +#endif
> +
> +#ifdef __NR_epoll_ctl
> +# include <sys/epoll.h>
> +void
> +test_epoll(int fd_base)
> +{
> +	int rc = epoll_ctl(-1, EPOLL_CTL_ADD, fd_base, NULL);
> +	printf("epoll_ctl(-1, EPOLL_CTL_ADD, %d, NULL) = %s\n",
> +	       fd_base, sprintrc(rc));
> +	epoll_ctl(-1, EPOLL_CTL_ADD, fd_base + 1, NULL);
> +}
> +#else
> +void
> +test_epoll(int fd_base)
> +{
> +}
> +#endif
> +
> +#if defined HAVE_SYS_FANOTIFY_H && defined HAVE_FANOTIFY_MARK && \
> +	defined __NR_fanotify_mark
> +# include <sys/fanotify.h>
> +void
> +test_fanotify_mark(int fd_base)
> +{
> +	int rc = fanotify_mark(-1, 0, 0, fd_base, ".");
> +	printf("fanotify_mark(-1, 0, 0, %d, \".\") = %s\n",
> +	       fd_base, sprintrc(rc));
> +	fanotify_mark(-1, 0, 0, fd_base + 1, ".");
> +}
> +#else
> +void
> +test_fanotify_mark(int fd_base)
> +{
> +}
> +#endif
> +
> +#if defined __NR_select || defined __NR__newselect
> +# include <sys/select.h>
> +void
> +test_select(int fd_base)
> +{
> +	int rc;
> +	fd_set positive_set, negative_set;
> +
> +	FD_ZERO(&positive_set);
> +	FD_SET(fd_base, &positive_set);
> +	FD_ZERO(&negative_set);
> +	FD_SET(fd_base + 1, &negative_set);
> +# ifndef __NR__newselect
> +	rc = syscall(__NR_select, fd_base + 1, &positive_set, NULL, NULL, NULL);
> +	printf("select(%d, [%d], NULL, NULL, NULL) = %s\n",
> +	       fd_base + 1, fd_base, sprintrc(rc));
> +	syscall(__NR_select, fd_base + 2, &negative_set, NULL, NULL,NULL);
> +# else
> +	rc = syscall(__NR__newselect, fd_base + 1, &positive_set, NULL, NULL,
> +		     NULL);
> +	printf("_newselect(%d, [%d], NULL, NULL, NULL) = %s\n",
> +	       fd_base + 1, fd_base, sprintrc(rc));
> +	syscall(__NR__newselect, fd_base + 2, &negative_set, NULL, NULL, NULL);
> +# endif
> +}
> +#else
> +void
> +test_select(int fd_base)
> +{
> +}
> +#endif
> +
> +#ifdef __NR_poll
> +# include <poll.h>
> +void
> +test_poll(int fd_base)
> +{
> +	struct pollfd positive_fds = {.fd = fd_base, .events = POLLIN};
> +	struct pollfd negative_fds = {.fd = fd_base + 1, .events = POLLIN};
> +
> +	poll(&positive_fds, 1, 1);
> +	printf("poll([{fd=%d, events=POLLIN}], 1, 1) = 1 "
> +	       "([{fd=%d, revents=POLLNVAL}])\n", fd_base, fd_base);
> +	poll(&negative_fds, 1, 1);
> +}
> +#else
> +void
> +test_poll(int fd_base)
> +{
> +}
> +#endif
> +
> +int
> +main(int argc, char **argv)
> +{
> +	const char *const name = argc > 1 ? argv[1] : "mmap";
> +	int fd_base = argc > 2 ? atoi(argv[2]) : FD_TRACED_DEFAULT;
Ugh. strtol is better than atoi.

> +
> +
Excess empty line.

> +	test_dup2(fd_base);
> +	test_linkat(fd_base);
> +	mmap(NULL, 0, PROT_NONE, MAP_FILE, fd_base, 0);
> +	printf("%s(NULL, 0, PROT_NONE, MAP_FILE, %d, 0) = -1 EBADF (%m)\n",
> +	       name, fd_base);
> +	test_symlinkat(fd_base);
> +	test_epoll(fd_base);
> +	test_fanotify_mark(fd_base);
> +	test_select(fd_base);
> +	test_poll(fd_base);
I'm not quite sure in which order these are sorted. If there's no
particular order, moving mmap() to the beginning or end of the check
call part would be preferable.

> +
> +	puts("+++ exited with 0 +++");
> +	return 0;
> +}
> diff --git a/tests/filtering_fd.test b/tests/filtering_fd.test
> new file mode 100755
> index 00000000..5c0b1743
> --- /dev/null
> +++ b/tests/filtering_fd.test
> @@ -0,0 +1,29 @@
> +#!/bin/sh
> +
> +# Check fd filtering
> +
> +. "${srcdir=.}/init.sh"
> +
> +check_prog grep
> +check_prog sed
> +run_prog > /dev/null
> +
> +fd_base=5
> +
> +syscall=
> +for n in mmap mmap2; do
> +	$STRACE -e$n -h > /dev/null && syscall=$syscall,$n
> +done
> +run_strace -e "trace(syscall $syscall && fd $fd_base)" $args > /dev/null
> +
> +if grep '^mmap(NULL, 0, PROT_NONE,' < "$LOG" > /dev/null; then
> +	mmap=mmap
> +elif grep '^mmap2(NULL, 0, PROT_NONE,' < "$LOG" > /dev/null; then
> +	mmap=mmap2
> +else
> +	dump_log_and_fail_with "mmap/mmap2 not found in $STRACE $args output"
> +fi
> +
> +run_prog "../$NAME" "$mmap" "$fd_base" > /dev/null
> +run_strace -a12 -e "trace(fd $fd_base)" $args > "$EXP"
> +match_diff "$LOG" "$EXP"
> diff --git a/tests/options-syntax.test b/tests/options-syntax.test
> index 47f6b66e..f13506ea 100755
> --- a/tests/options-syntax.test
> +++ b/tests/options-syntax.test
> @@ -37,17 +37,6 @@ check_e "Invalid process id: 'a'" -p 1,a
>  check_e "Syscall 'chdir' for -b isn't supported" -b chdir
>  check_e "Syscall 'chdir' for -b isn't supported" -b execve -b chdir
>  
> -check_e "invalid descriptor '-1'" -eread=-1
> -check_e "invalid descriptor '-42'" -ewrite=-42
> -check_e "invalid descriptor '2147483648'" -eread=2147483648
> -check_e "invalid descriptor '4294967296'" -ewrite=4294967296
> -check_e "invalid descriptor 'foo'" -eread=foo
> -check_e "invalid descriptor ''" -ewrite=
> -check_e "invalid descriptor ','" -eread=,
> -check_e "invalid descriptor '!'" -ewrite='!'
> -check_e "invalid descriptor '!'" -eread='0,!'
> -check_e "invalid descriptor '!,'" -ewrite='!,'
Note that added checks have quite a different syntax than these.

> -
>  check_h 'must have PROG [ARGS] or -p PID'
>  check_h 'PROG [ARGS] must be specified with -D' -D -p $$
>  check_h '-c and -C are mutually exclusive' -c -C true
> -- 
> 2.11.0




More information about the Strace-devel mailing list