From: Eugene Syromyatnikov Date: Mon, 3 Jul 2017 19:29:28 +0000 (+0200) Subject: tests: add multi-process check to qual_fault.test X-Git-Tag: v4.18~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da160ae8ed31da0ff018b5b2c72ce84a26b32920;p=strace tests: add multi-process check to qual_fault.test Check that syscall counters used for tampering are per-tcb. * tests/qual_fault.c: Include for open(), for PATH_MAX, and for wait(). (expfd): Rename to exp_fd, remove const qualifier and initialization. (gotfd): Rename to got_fd, remove const qualifier and initialization. (out_fd): New variable, for the expected strace output. (open_file): New helper function. (main): Remove st, add num_procs, proc, exp_prefix, got_prefix, out_prefix, pid_prefix. Remove stat asserts, update argc assert. Add num_procs, exp_prefix, got_prefix, out_prefix, pid_prefix initialization. Add per-process loop, open expfd, gotfd, out_fd, pidfd in each one, print process's pid to pidfd, print exit message to out_fd. Add wait() call for each forked process. * tests/qual_fault.test (N): increase to 100 in order to check concurrent process execution. (check_fault_injection): Take additional argument for the process count, pass it to qual_fault, add filename variables for expected strace output and pid file, pass them to qual_fault. Specify -ff parameter to strace invocation. Compare write and strace output for the each process. Update all check_fault_injection invocation with process count argument, add an invocation with 4 concurrent processes. * tests/init.sh (TIMEOUT_DURATION): Raise from 120 to 300. Co-authored-by: Dmitry V. Levin --- diff --git a/tests/init.sh b/tests/init.sh index 013a33d9..2d4d0b41 100644 --- a/tests/init.sh +++ b/tests/init.sh @@ -366,7 +366,7 @@ else STRACE=../strace fi -: "${TIMEOUT_DURATION:=120}" +: "${TIMEOUT_DURATION:=300}" : "${SLEEP_A_BIT:=sleep 1}" [ -z "${VERBOSE-}" ] || diff --git a/tests/qual_fault.c b/tests/qual_fault.c index ab692cb8..05401dec 100644 --- a/tests/qual_fault.c +++ b/tests/qual_fault.c @@ -32,15 +32,19 @@ #include #include +#include #include #include #include #include +#include #include #include +#include -static const int expfd = 4; -static const int gotfd = 5; +static int exp_fd; +static int got_fd; +static int out_fd; #define DEFAULT_ERRNO ENOSYS @@ -58,13 +62,13 @@ invoke(int fail) int rc; if (!fail) { - rc = write(expfd, io.iov_base, io.iov_len); + rc = write(exp_fd, io.iov_base, io.iov_len); if (rc != (int) io.iov_len) perror_msg_and_fail("write"); } errno = 0; - rc = writev(gotfd, &io, 1); + rc = writev(got_fd, &io, 1); if (fail) { if (!(rc == -1 && errno == err)) @@ -74,11 +78,11 @@ invoke(int fail) if (is_raw) tprintf("writev(%#x, %p, 0x1) = -1 (errno %d)" - " (INJECTED)\n", gotfd, &io, err); + " (INJECTED)\n", got_fd, &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); + got_fd, buf, (int) io.iov_len, errstr); } else { if (rc != (int) io.iov_len) perror_msg_and_fail("expected %d" @@ -86,23 +90,35 @@ invoke(int fail) (int) io.iov_len, rc, errno); if (is_raw) - tprintf("writev(%#x, %p, 0x1) = %#x\n", gotfd, &io, rc); + tprintf("writev(%#x, %p, 0x1) = %#x\n", + got_fd, &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); + got_fd, buf, (int) io.iov_len, + (int) io.iov_len); } } -int -main(int argc, char *argv[]) +static int +open_file(const char *prefix, int proc) { - struct stat st; + static const int open_flags = O_WRONLY | O_TRUNC | O_CREAT; + static char path[PATH_MAX + 1]; + + snprintf(path, sizeof(path), "%s.%d", prefix, proc); - assert(fstat(expfd, &st) == 0); - assert(fstat(gotfd, &st) == 0); + int fd = open(path, open_flags, 0600); + if (fd < 0) + perror_msg_and_fail("open: %s", path); + + return fd; +} - assert(argc == 6); +int +main(int argc, char *argv[]) +{ + assert(argc == 11); is_raw = !strcmp("raw", argv[1]); @@ -125,25 +141,71 @@ main(int argc, char *argv[]) first = atoi(argv[3]); step = atoi(argv[4]); iter = atoi(argv[5]); + int num_procs = atoi(argv[6]); + char *exp_prefix = argv[7]; + char *got_prefix = argv[8]; + char *out_prefix = argv[9]; + char *pid_prefix = argv[10]; assert(first > 0); assert(step >= 0); + assert(num_procs > 0); + + int proc; + for (proc = 0; proc < num_procs; ++proc) { + int ret = fork(); + + if (ret < 0) + perror_msg_and_fail("fork"); - tprintf("%s", ""); + if (ret > 0) { + int pidfd = open_file(pid_prefix, proc); - int i; - for (i = 1; i <= iter; ++i) { - int fail = 0; - if (first > 0) { - --first; - if (first == 0) { - fail = 1; - first = step; + char pidstr[sizeof(ret) * 3]; + int len = snprintf(pidstr, sizeof(pidstr), "%d", ret); + assert(len > 0 && len < (int) sizeof(pidstr)); + assert(write(pidfd, pidstr, len) == len); + + close(pidfd); + + continue; + } + + tprintf("%s", ""); + + exp_fd = open_file(exp_prefix, proc); + got_fd = open_file(got_prefix, proc); + out_fd = open_file(out_prefix, proc); + + /* This magic forces tprintf to write where we want it. */ + dup2(out_fd, 3); + + int i; + for (i = 1; i <= iter; ++i) { + int fail = 0; + if (first > 0) { + --first; + if (first == 0) { + fail = 1; + first = step; + } } + invoke(fail); } - invoke(fail); + + tprintf("%s\n", "+++ exited with 0 +++"); + return 0; + } + + for (proc = 0; proc < num_procs; ++proc) { + int status; + int ret = wait(&status); + if (ret <= 0) + perror_msg_and_fail("wait %d", proc); + if (status) + error_msg_and_fail("wait: pid=%d status=%d", + ret, status); } - tprintf("%s\n", "+++ exited with 0 +++"); return 0; } diff --git a/tests/qual_fault.test b/tests/qual_fault.test index f8e57d2b..12b0a850 100755 --- a/tests/qual_fault.test +++ b/tests/qual_fault.test @@ -35,16 +35,17 @@ # F+ # F+S -N=16 +N=100 check_fault_injection() { - local trace fault err first step extra + local trace fault err first step procs extra trace=$1; shift fault=$1; shift err=$1; shift first=$1; shift step=$1; shift + procs=$1; shift extra="$*" local when= @@ -74,30 +75,39 @@ check_fault_injection() outexp="$NAME.out.exp" outgot="$NAME.out.got" + outout="$NAME.out.out" + outpid="$NAME.pid" - run_strace -a11 -e trace=$trace \ + run_strace -a11 -ff -e trace=$trace \ "$@" -e fault=$fault$when$error $extra \ ../$NAME $raw "$err" "$first" "$step" $N \ - > "$EXP" 4> "$outexp" 5> "$outgot" + "$procs" "$outexp" "$outgot" "$outout" "$outpid" - match_diff "$EXP" "$LOG" - match_diff "$outexp" "$outgot" + for i in $(seq 0 $((procs - 1)) ) + do + pid=$(cat "$outpid.$i") + + match_diff "$outout.$i" "$LOG.$pid" + match_diff "$outexp.$i" "$outgot.$i" + done } for err in '' ENOSYS 22 einval; do for fault in writev desc,51; do check_fault_injection \ - writev $fault "$err" '' '' -efault=chdir + writev $fault "$err" '' '' 1 -efault=chdir check_fault_injection \ - writev $fault "$err" '' '' -efault=chdir -efault=none + writev $fault "$err" '' '' 1 -efault=chdir -efault=none for F in 1 2 3 5 7 11; do check_fault_injection \ - writev $fault "$err" $F '' + writev $fault "$err" $F '' 1 check_fault_injection \ - writev $fault "$err" $F + + writev $fault "$err" $F + 1 for S in 1 2 3 5 7 11; do check_fault_injection \ - writev $fault "$err" $F $S + writev $fault "$err" $F $S 1 + check_fault_injection \ + writev $fault "$err" $F $S 4 done done done