From: Dmitry V. Levin Date: Wed, 16 Nov 2016 17:27:46 +0000 (+0000) Subject: tests: check syscall fault injection X-Git-Tag: v4.15~124 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=622af42dc336719518773a149b5abb2d58c1521d;p=strace tests: check syscall fault injection * tests/fault_injection.c: New file. * tests/fault_injection.test: New test. * tests/fault_syntax.test: Likewise. * tests/.gitignore: Add fault_injection. * tests/Makefile.am (check_PROGRAMS): Likewise. (MISC_TESTS): Add fault_injection.test and fault_syntax.test. --- diff --git a/tests/.gitignore b/tests/.gitignore index 0366c9c4..6fc3cd1f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -52,6 +52,7 @@ fadvise64_64 fallocate fanotify_init fanotify_mark +fault_injection fchdir fchmod fchmodat diff --git a/tests/Makefile.am b/tests/Makefile.am index 0f047793..df5ddb21 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -112,6 +112,7 @@ check_PROGRAMS = \ fallocate \ fanotify_init \ fanotify_mark \ + fault_injection \ fchdir \ fchmod \ fchmodat \ @@ -785,6 +786,8 @@ MISC_TESTS = \ detach-running.test \ detach-sleeping.test \ detach-stopped.test \ + fault_injection.test \ + fault_syntax.test \ filter-unavailable.test \ fork-f.test \ ksysent.test \ diff --git a/tests/fault_injection.c b/tests/fault_injection.c new file mode 100644 index 00000000..3305d0ff --- /dev/null +++ b/tests/fault_injection.c @@ -0,0 +1,153 @@ +/* + * Check that fault injection works properly. + * + * Copyright (c) 2016 Dmitry V. Levin + * 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 +#include +#include +#include +#include +#include +#include +#include + +static const int expfd = 4; +static const int gotfd = 5; + +#ifndef __s390__ +# define DEFAULT_ERRNO ENOSYS +#else /* __s390__ */ +/* Invalid syscall number causes EPERM instead of traditional ENOSYS. */ +# define DEFAULT_ERRNO EPERM +#endif + +static const char *errstr; +static int is_raw, err, first, step, iter, try; + +static void +invoke(int fail) +{ + static char buf[sizeof(int) * 3 + 3]; + const struct iovec io = { + .iov_base = buf, + .iov_len = sprintf(buf, "%d.", ++try) + }; + int rc; + + if (!fail) { + rc = write(expfd, io.iov_base, io.iov_len); + if (rc != (int) io.iov_len) + perror_msg_and_fail("write"); + } + + errno = 0; + rc = writev(gotfd, &io, 1); + + if (fail) { + if (!(rc == -1 && errno == err)) + perror_msg_and_fail("expected errno %d" + ", got rc == %d, errno == %d", + err, rc, errno); + + if (is_raw) + tprintf("writev(%#x, %p, 0x1) = -1 (errno %d)" + " (INJECTED)\n", gotfd, &io, err); + else + tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)" + " = -1 %s (%m) (INJECTED)\n", + gotfd, buf, (int) io.iov_len, errstr); + } else { + if (rc != (int) io.iov_len) + perror_msg_and_fail("expected %d" + ", got rc == %d, errno == %d", + (int) io.iov_len, rc, errno); + + if (is_raw) + tprintf("writev(%#x, %p, 0x1) = %#x\n", gotfd, &io, rc); + else + tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)" + " = %d\n", + gotfd, buf, (int) io.iov_len, (int) io.iov_len); + } +} + +int +main(int argc, char *argv[]) +{ + struct stat st; + + assert(fstat(expfd, &st) == 0); + assert(fstat(gotfd, &st) == 0); + + assert(argc == 6); + + is_raw = !strcmp("raw", argv[1]); + + errstr = argv[2]; + err = atoi(errstr); + assert(err >= 0); + + if (!err) { + if (!*errstr) + err = DEFAULT_ERRNO; + else if (!strcmp(errstr, "EINVAL")) + err = EINVAL; + else + err = ENOSYS; + } + + errno = err; + errstr = errno2name(); + + first = atoi(argv[3]); + step = atoi(argv[4]); + iter = atoi(argv[5]); + + assert(first > 0); + assert(step >= 0); + + tprintf("%s", ""); + + int i; + for (i = 1; i <= iter; ++i) { + int fail = 0; + if (first > 0) { + --first; + if (first == 0) { + fail = 1; + first = step; + } + } + invoke(fail); + } + + tprintf("%s\n", "+++ exited with 0 +++"); + return 0; +} diff --git a/tests/fault_injection.test b/tests/fault_injection.test new file mode 100755 index 00000000..bf6006f0 --- /dev/null +++ b/tests/fault_injection.test @@ -0,0 +1,101 @@ +#!/bin/sh +# +# Check that fault injection works properly. +# +# Copyright (c) 2016 Dmitry V. Levin +# 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=.}/init.sh" + +# +# F +# F+ +# F+S + +N=16 + +check_fault_injection() +{ + local trace fault err first step + trace=$1; shift + fault=$1; shift + err=$1; shift + first=$1; shift + step=$1; shift + + local when= + if [ -z "$first$step" ]; then + first=1 + step=1 + else + case "$step" in + '') when=":when=$first"; step=0 ;; + +) when=":when=$first+"; step=1 ;; + *) when=":when=$first+$step" ;; + esac + fi + + local error= + local raw=reg + set -- + case "$err" in + '') ;; + [123456789]*) + error=":error=$err" + raw=raw + set -- -e raw=all + ;; + *) error=":error=$err" ;; + esac + + outexp="$NAME.out.exp" + outgot="$NAME.out.got" + + run_strace -a11 -e trace=$trace \ + -e fault=$fault$when$error "$@" \ + ./$NAME $raw "$err" "$first" "$step" $N \ + > "$EXP" 4> "$outexp" 5> "$outgot" + + match_diff "$EXP" "$LOG" + match_diff "$outexp" "$outgot" + rm -f "$EXP" "$outexp" "$outgot" +} + +for err in '' ENOSYS 22 EINVAL; do + for fault in writev 51,desc; do + check_fault_injection \ + writev $fault "$err" '' '' + for F in 1 2 3 5 7 11; do + check_fault_injection \ + writev $fault "$err" $F '' + check_fault_injection \ + writev $fault "$err" $F + + for S in 1 2 3 5 7 11; do + check_fault_injection \ + writev $fault "$err" $F $S + done + done + done +done diff --git a/tests/fault_syntax.test b/tests/fault_syntax.test new file mode 100755 index 00000000..97766d25 --- /dev/null +++ b/tests/fault_syntax.test @@ -0,0 +1,101 @@ +#!/bin/sh +# +# Check -e fault= syntax. +# +# Copyright (c) 2016 Dmitry V. Levin +# 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=.}/init.sh" + +# +# F +# F+ +# F+S + +fail_with() +{ + dump_log_and_fail_with \ + "strace -e fault=$* failed to handle an argument error properly" +} + +for arg in invalid_syscall_name \ + invalid_syscall_name:when=3 \ + -1 \ + -1:when=4 \ + -2 \ + -2:when=5 \ + 32767 \ + 32767:when=6 \ + chdir:42 \ + chdir:42:when=7 \ + chdir:invalid \ + chdir:invalid:when=8 \ + chdir:error= \ + chdir:error=:when=10 \ + chdir:error=invalid_error_name \ + chdir:error=invalid_error_name:when=11 \ + chdir:error=-1 \ + chdir:error=-1:when=12 \ + chdir:error=-2 \ + chdir:error=-2:when=13 \ + chdir:error=3+ \ + chdir:error=3+:when=14 \ + chdir:error=4096 \ + chdir:error=4096:when=15 \ + chdir:when=7:error=invalid_error_name \ + chdir:when= \ + chdir:when=:error=19 \ + chdir:when=0 \ + chdir:when=0:error=20 \ + chdir:when=-1 \ + chdir:when=-1:error=21 \ + chdir:when=-2+ \ + chdir:when=-2+:error=22 \ + chdir:when=-3+0 \ + chdir:when=-3+0:error=23 \ + chdir:when=4- \ + chdir:when=4-:error=24 \ + chdir:when=5+- \ + chdir:when=5+-:error=25 \ + chdir:when=6++ \ + chdir:when=6++:error=26 \ + chdir:when=7+0 \ + chdir:when=7+0:error=27 \ + chdir:when=8+-1 \ + chdir:when=8+-1:error=28 \ + chdir:when=9+1+ \ + chdir:when=9+1+:error=29 \ + chdir:when=65536 \ + chdir:when=65536:error=30 \ + chdir:when=1+65536 \ + chdir:when=1+65536:error=31 \ + ; do + $STRACE -e fault="$arg" true 2> "$LOG" && + fail_with "$arg" + LC_ALL=C grep -F 'invalid fault argument' < "$LOG" > /dev/null || + fail_with "$arg" +done + +exit 0