From: Dmitry V. Levin Date: Sun, 7 Feb 2016 14:37:53 +0000 (+0000) Subject: tests: extend coverage of execve and execveat syscalls X-Git-Tag: v4.12~579 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=23168c1e545e7d8d7cbadb5fb6f5a7ddf2e6e59f;p=strace tests: extend coverage of execve and execveat syscalls Check decoding of inaccessible or partially inaccessible arrays. * tests/execve-v.c: New file. * tests/execveat-v.c: Likewise. * tests/execve-v.test: New test. * tests/execveat-v.test: Likewise. * tests/execve.c: Rewrite. * tests/execveat.c: Likewise. * tests/execve.test: Likewise. * tests/execveat.test: Likewise. * tests/execve.expected: Remove. * tests/execve-v.expected: Likewise. * tests/execveat.expected: Likewise. * tests/execveat-v.expected: Likewise. * tests/.gitignore: Add execve-v and execveat-v. * tests/Makefile.am (check_PROGRAMS): Likewise. (TESTS): Add execve-v.test and execveat-v.test. (EXTRA_DIST): Remove execve.expected, execve-v.expected, execveat.expected, and execveat-v.expected. --- diff --git a/tests/.gitignore b/tests/.gitignore index f6347c0b..690242e2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -17,7 +17,9 @@ clock_xettime epoll_create1 eventfd execve +execve-v execveat +execveat-v fanotify_mark fcntl fcntl64 diff --git a/tests/Makefile.am b/tests/Makefile.am index 935b13ab..a28a46aa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -67,7 +67,9 @@ check_PROGRAMS = \ epoll_create1 \ eventfd \ execve \ + execve-v \ execveat \ + execveat-v \ fanotify_mark \ fcntl \ fcntl64 \ @@ -211,7 +213,9 @@ TESTS = \ epoll_create1.test \ eventfd.test \ execve.test \ + execve-v.test \ execveat.test \ + execveat-v.test \ fanotify_mark.test \ fcntl.test \ fcntl64.test \ @@ -328,10 +332,6 @@ EXTRA_DIST = init.sh run.sh match.awk \ caps.awk \ dumpio.expected \ eventfd.expected \ - execve.expected \ - execve-v.expected \ - execveat.expected \ - execveat-v.expected \ fanotify_mark.expected \ filter-unavailable.expected \ fstatat.c \ diff --git a/tests/execve-v.c b/tests/execve-v.c new file mode 100644 index 00000000..26bc9d61 --- /dev/null +++ b/tests/execve-v.c @@ -0,0 +1,3 @@ +/* This file is part of execve-v strace test. */ +#define VERBOSE_EXECVE +#include "execve.c" diff --git a/tests/execve-v.expected b/tests/execve-v.expected deleted file mode 100644 index 14fafb31..00000000 --- a/tests/execve-v.expected +++ /dev/null @@ -1 +0,0 @@ -execve\("execve\\nfilename", \["execve\\nfilename", "first", "second"\], \["foobar=1", "foo\\nbar=2"\]\) += -1 ENOENT .* diff --git a/tests/execve-v.test b/tests/execve-v.test new file mode 100755 index 00000000..599a80cb --- /dev/null +++ b/tests/execve-v.test @@ -0,0 +1,18 @@ +#!/bin/sh + +# Check verbose decoding of execve syscall. + +. "${srcdir=.}/init.sh" + +check_prog grep +run_prog > /dev/null + +OUT="$LOG.out" +EXP="$LOG.exp" +run_strace -veexecve $args > "$EXP" + +# Filter out execve() call made by strace. +grep -F test.execve < "$LOG" > "$OUT" +match_diff "$OUT" "$EXP" + +rm -f "$EXP" "$OUT" diff --git a/tests/execve.c b/tests/execve.c index 09599780..9c0cfe01 100644 --- a/tests/execve.c +++ b/tests/execve.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 2015 Dmitry V. Levin + * This file is part of execve strace test. + * + * Copyright (c) 2015-2016 Dmitry V. Levin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,17 +27,150 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "tests.h" +#include +#include #include -#define FILENAME "execve\nfilename" -static const char * const argv[] = - { FILENAME, "first", "second", NULL, NULL, NULL }; -static const char * const envp[] = - { "foobar=1", "foo\nbar=2", NULL , "", NULL , "", NULL, NULL}; +#define FILENAME "test.execve\nfilename" +#define Q_FILENAME "test.execve\\nfilename" + +static const char * const argv[] = { + FILENAME, "first", "second", (const char *) -1L, + (const char *) -2L, (const char *) -3L +}; +static const char * const q_argv[] = { + Q_FILENAME, "first", "second" +}; + +static const char * const envp[] = { + "foobar=1", "foo\nbar=2", (const char *) -1L, + (const char *) -2L, (const char *) -3L +}; +static const char * const q_envp[] = { + "foobar=1", "foo\\nbar=2" +}; int main(void) { - execve(FILENAME, (char * const *) argv, (char * const *) envp); + char ** const tail_argv = tail_memdup(argv, sizeof(argv)); + char ** const tail_envp = tail_memdup(envp, sizeof(envp)); + + execve(FILENAME, tail_argv, tail_envp); + printf("execve(\"%s\"" + ", [\"%s\", \"%s\", \"%s\", %p, %p, %p, ???]" +#ifdef VERBOSE_EXECVE + ", [\"%s\", \"%s\", %p, %p, %p, ???]" +#else + ", [/* 5 vars, unterminated */]" +#endif + ") = -1 %s (%m)\n", + Q_FILENAME, q_argv[0], q_argv[1], q_argv[2], + argv[3], argv[4], argv[5], +#ifdef VERBOSE_EXECVE + q_envp[0], q_envp[1], envp[2], envp[3], envp[4], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + tail_argv[ARRAY_SIZE(q_argv)] = NULL; + tail_envp[ARRAY_SIZE(q_envp)] = NULL; + + execve(FILENAME, tail_argv, tail_envp); + printf("execve(\"%s\", [\"%s\", \"%s\", \"%s\"]" +#ifdef VERBOSE_EXECVE + ", [\"%s\", \"%s\"]" +#else + ", [/* 2 vars */]" +#endif + ") = -1 %s (%m)\n", + Q_FILENAME, q_argv[0], q_argv[1], q_argv[2], +#ifdef VERBOSE_EXECVE + q_envp[0], q_envp[1], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + execve(FILENAME, tail_argv + 2, tail_envp + 1); + printf("execve(\"%s\", [\"%s\"]" +#ifdef VERBOSE_EXECVE + ", [\"%s\"]" +#else + ", [/* 1 var */]" +#endif + ") = -1 %s (%m)\n", + Q_FILENAME, q_argv[2], +#ifdef VERBOSE_EXECVE + q_envp[1], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + char **const empty = tail_alloc(sizeof(*empty)); + *empty = NULL; + + execve(FILENAME, empty, empty); + printf("execve(\"%s\", []" +#ifdef VERBOSE_EXECVE + ", []" +#else + ", [/* 0 vars */]" +#endif + ") = -1 %s (%m)\n", + Q_FILENAME, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + char str_a[] = "012345678901234567890123456789012"; + char str_b[] = "_abcdefghijklmnopqrstuvwxyz()[]{}"; +#define DEFAULT_STRLEN ((unsigned int) sizeof(str_a) - 2) + char **const a = tail_alloc(sizeof(*a) * (DEFAULT_STRLEN + 2)); + char **const b = tail_alloc(sizeof(*b) * (DEFAULT_STRLEN + 2)); + unsigned int i; + for (i = 0; i <= DEFAULT_STRLEN; ++i) { + a[i] = &str_a[i]; + b[i] = &str_b[i]; + } + a[i] = b[i] = NULL; + + execve(FILENAME, a, b); + printf("execve(\"%s\", [\"%.*s\"...", Q_FILENAME, DEFAULT_STRLEN, a[0]); + for (i = 1; i < DEFAULT_STRLEN; ++i) + printf(", \"%s\"", a[i]); +#ifdef VERBOSE_EXECVE + printf(", \"%s\"", a[i]); +#else + printf(", ..."); +#endif +#ifdef VERBOSE_EXECVE + printf("], [\"%.*s\"...", DEFAULT_STRLEN, b[0]); + for (i = 1; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", b[i]); +#else + printf("], [/* %u vars */", DEFAULT_STRLEN + 1); +#endif + printf("]) = -1 %s (%m)\n", errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + execve(FILENAME, a + 1, b + 1); + printf("execve(\"%s\", [\"%s\"", Q_FILENAME, a[1]); + for (i = 2; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", a[i]); +#ifdef VERBOSE_EXECVE + printf("], [\"%s\"", b[1]); + for (i = 2; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", b[i]); +#else + printf("], [/* %d vars */", DEFAULT_STRLEN); +#endif + printf("]) = -1 %s (%m)\n", errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + const void * const efault = tail_alloc(0); + + execve(FILENAME, (char **) tail_argv[ARRAY_SIZE(q_argv)], efault); + printf("execve(\"%s\", NULL, %p" + ") = -1 %s (%m)\n", + Q_FILENAME, efault, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + execve(FILENAME, efault, NULL); + printf("execve(\"%s\", %p, NULL" + ") = -1 %s (%m)\n", + Q_FILENAME, efault, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + return 0; } diff --git a/tests/execve.expected b/tests/execve.expected deleted file mode 100644 index e184d235..00000000 --- a/tests/execve.expected +++ /dev/null @@ -1 +0,0 @@ -execve\("execve\\nfilename", \["execve\\nfilename", "first", "second"\], \[/\* 2 vars \*/\]\) += -1 ENOENT .* diff --git a/tests/execve.test b/tests/execve.test index a1737cc9..14cae625 100755 --- a/tests/execve.test +++ b/tests/execve.test @@ -4,10 +4,15 @@ . "${srcdir=.}/init.sh" -run_prog -run_strace $args -match_grep -run_strace -v $args -match_grep "$LOG" "$srcdir/${ME_%.test}-v.expected" +check_prog grep +run_prog > /dev/null -exit 0 +OUT="$LOG.out" +EXP="$LOG.exp" +run_strace -eexecve $args > "$EXP" + +# Filter out execve() call made by strace. +grep -F test.execve < "$LOG" > "$OUT" +match_diff "$OUT" "$EXP" + +rm -f "$EXP" "$OUT" diff --git a/tests/execveat-v.c b/tests/execveat-v.c new file mode 100644 index 00000000..530ddfc9 --- /dev/null +++ b/tests/execveat-v.c @@ -0,0 +1,3 @@ +/* This file is part of execveat-v strace test. */ +#define VERBOSE_EXECVEAT +#include "execveat.c" diff --git a/tests/execveat-v.expected b/tests/execveat-v.expected deleted file mode 100644 index ebac879e..00000000 --- a/tests/execveat-v.expected +++ /dev/null @@ -1 +0,0 @@ -execveat\(AT_FDCWD, "execveat\\nfilename", \["execveat\\nfilename", "first", "second"\], \["foobar=1", "foo\\nbar=2"\], AT_SYMLINK_NOFOLLOW\|AT_EMPTY_PATH\) += -1 .* diff --git a/tests/execveat-v.test b/tests/execveat-v.test new file mode 100755 index 00000000..776d2904 --- /dev/null +++ b/tests/execveat-v.test @@ -0,0 +1,11 @@ +#!/bin/sh + +# Check verbose decoding of execveat syscall. + +. "${srcdir=.}/init.sh" + +run_prog > /dev/null +OUT="$LOG.out" +run_strace -veexecveat $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT" diff --git a/tests/execveat.c b/tests/execveat.c index af3d08e7..8ac2cd18 100644 --- a/tests/execveat.c +++ b/tests/execveat.c @@ -1,4 +1,6 @@ /* + * This file is part of execveat strace test. + * * Copyright (c) 2015-2016 Dmitry V. Levin * All rights reserved. * @@ -26,21 +28,156 @@ */ #include "tests.h" +#include +#include #include #include #ifdef __NR_execveat -#define FILENAME "execveat\nfilename" -static const char * const argv[] = - { FILENAME, "first", "second", NULL, NULL, NULL }; -static const char * const envp[] = - { "foobar=1", "foo\nbar=2", NULL , "", NULL , "", NULL, NULL}; +# define FILENAME "test.execveat\nfilename" +# define Q_FILENAME "test.execveat\\nfilename" + +static const char * const argv[] = { + FILENAME, "first", "second", (const char *) -1L, + (const char *) -2L, (const char *) -3L +}; +static const char * const q_argv[] = { + Q_FILENAME, "first", "second" +}; + +static const char * const envp[] = { + "foobar=1", "foo\nbar=2", (const char *) -1L, + (const char *) -2L, (const char *) -3L +}; +static const char * const q_envp[] = { + "foobar=1", "foo\\nbar=2" +}; int main(void) { - syscall(__NR_execveat, -100, FILENAME, argv, envp, 0x1100); + const char ** const tail_argv = tail_memdup(argv, sizeof(argv)); + const char ** const tail_envp = tail_memdup(envp, sizeof(envp)); + + syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100); + printf("execveat(AT_FDCWD, \"%s\"" + ", [\"%s\", \"%s\", \"%s\", %p, %p, %p, ???]" +#ifdef VERBOSE_EXECVEAT + ", [\"%s\", \"%s\", %p, %p, %p, ???]" +#else + ", [/* 5 vars, unterminated */]" +#endif + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, q_argv[0], q_argv[1], q_argv[2], + argv[3], argv[4], argv[5], +#ifdef VERBOSE_EXECVEAT + q_envp[0], q_envp[1], envp[2], envp[3], envp[4], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + tail_argv[ARRAY_SIZE(q_argv)] = NULL; + tail_envp[ARRAY_SIZE(q_envp)] = NULL; + + syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", [\"%s\", \"%s\", \"%s\"]" +#ifdef VERBOSE_EXECVEAT + ", [\"%s\", \"%s\"]" +#else + ", [/* 2 vars */]" +#endif + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, q_argv[0], q_argv[1], q_argv[2], +#ifdef VERBOSE_EXECVEAT + q_envp[0], q_envp[1], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + syscall(__NR_execveat, -100, FILENAME, tail_argv + 2, tail_envp + 1, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", [\"%s\"]" +#ifdef VERBOSE_EXECVEAT + ", [\"%s\"]" +#else + ", [/* 1 var */]" +#endif + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, q_argv[2], +#ifdef VERBOSE_EXECVEAT + q_envp[1], +#endif + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + const char **const empty = tail_alloc(sizeof(*empty)); + *empty = NULL; + + syscall(__NR_execveat, -100, FILENAME, empty, empty, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", []" +#ifdef VERBOSE_EXECVEAT + ", []" +#else + ", [/* 0 vars */]" +#endif + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + char str_a[] = "012345678901234567890123456789012"; + char str_b[] = "_abcdefghijklmnopqrstuvwxyz()[]{}"; +#define DEFAULT_STRLEN ((unsigned int) sizeof(str_a) - 2) + char **const a = tail_alloc(sizeof(*a) * (DEFAULT_STRLEN + 2)); + char **const b = tail_alloc(sizeof(*b) * (DEFAULT_STRLEN + 2)); + unsigned int i; + for (i = 0; i <= DEFAULT_STRLEN; ++i) { + a[i] = &str_a[i]; + b[i] = &str_b[i]; + } + a[i] = b[i] = NULL; + + syscall(__NR_execveat, -100, FILENAME, a, b, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", [\"%.*s\"...", Q_FILENAME, DEFAULT_STRLEN, a[0]); + for (i = 1; i < DEFAULT_STRLEN; ++i) + printf(", \"%s\"", a[i]); +#ifdef VERBOSE_EXECVEAT + printf(", \"%s\"", a[i]); +#else + printf(", ..."); +#endif +#ifdef VERBOSE_EXECVEAT + printf("], [\"%.*s\"...", DEFAULT_STRLEN, b[0]); + for (i = 1; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", b[i]); +#else + printf("], [/* %u vars */", DEFAULT_STRLEN + 1); +#endif + printf("], AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + syscall(__NR_execveat, -100, FILENAME, a + 1, b + 1, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", [\"%s\"", Q_FILENAME, a[1]); + for (i = 2; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", a[i]); +#ifdef VERBOSE_EXECVEAT + printf("], [\"%s\"", b[1]); + for (i = 2; i <= DEFAULT_STRLEN; ++i) + printf(", \"%s\"", b[i]); +#else + printf("], [/* %d vars */", DEFAULT_STRLEN); +#endif + printf("], AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + const void * const efault = tail_alloc(0); + + syscall(__NR_execveat, -100, FILENAME, NULL, efault, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", NULL, %p" + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, efault, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + syscall(__NR_execveat, -100, FILENAME, efault, NULL, 0x1100); + printf("execveat(AT_FDCWD, \"%s\", %p, NULL" + ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n", + Q_FILENAME, efault, errno == ENOSYS ? "ENOSYS" : "ENOENT"); + + puts("+++ exited with 0 +++"); return 0; } diff --git a/tests/execveat.expected b/tests/execveat.expected deleted file mode 100644 index 7383ed23..00000000 --- a/tests/execveat.expected +++ /dev/null @@ -1 +0,0 @@ -execveat\(AT_FDCWD, "execveat\\nfilename", \["execveat\\nfilename", "first", "second"\], \[/\* 2 vars \*/\], AT_SYMLINK_NOFOLLOW\|AT_EMPTY_PATH\) += -1 .* diff --git a/tests/execveat.test b/tests/execveat.test index b371b079..eb4a47aa 100755 --- a/tests/execveat.test +++ b/tests/execveat.test @@ -4,10 +4,8 @@ . "${srcdir=.}/init.sh" -run_prog -run_strace $args -match_grep -run_strace -v $args -match_grep "$LOG" "$srcdir/${ME_%.test}-v.expected" - -exit 0 +run_prog > /dev/null +OUT="$LOG.out" +run_strace -eexecveat $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT"