From: Dmitry V. Levin Date: Sat, 5 Dec 2015 00:52:01 +0000 (+0000) Subject: fcntl: skip F_GETLK64, F_SETLK64, and F_SETLKW64 in fcntl syscall parser X-Git-Tag: v4.11~58 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2154702865b489cfb14a649f6a3217ded32bf5f9;p=strace fcntl: skip F_GETLK64, F_SETLK64, and F_SETLKW64 in fcntl syscall parser As the kernel recognizes F_GETLK64, F_SETLK64, and F_SETLKW64 commands in fcntl64 syscall only, do not parse their structures in fcntl parser. * xlat/fcntlcmds.in: Move F_GETLK64, F_SETLK64, and F_SETLKW64 ... * xlat/fcntl64cmds.in: ... here. * fcntl.c: Include "xlat/fcntl64cmds.h". (print_fcntl): Move printing of first two syscall arguments and handling of F_GETLK64, F_SETLK64, and F_SETLKW64 commands ... (SYS_FUNC(fcntl), SYS_FUNC(fcntl64)): ... here. * tests/fcntl.c: New file, based on struct_flock.c. * tests/fcntl64.c: Likewise. * tests/struct_flock.c (test_flock_einval, create_sample): New functions. (test_flock): Use test_flock_einval. (test_flock64, main): Remove. * tests/fcntl.test: New test. * tests/fcntl64.test: Likewise. * tests/struct_flock.test: Remove. * tests/Makefile.am (check_PROGRAMS): Add fcntl and fcntl64, remove struct_flock. (TESTS): Add fcntl.test and fcntl64.test, remove struct_flock.test. (EXTRA_DIST) Add struct_flock.c. * tests/.gitignore: Add fcntl and fcntl64, remove struct_flock. --- diff --git a/fcntl.c b/fcntl.c index 8a49fabf..88809fe2 100644 --- a/fcntl.c +++ b/fcntl.c @@ -34,6 +34,7 @@ #include "xlat/f_owner_types.h" #include "xlat/f_seals.h" #include "xlat/fcntlcmds.h" +#include "xlat/fcntl64cmds.h" #include "xlat/fdflags.h" #include "xlat/lockfcmds.h" #include "xlat/notifyflags.h" @@ -86,11 +87,6 @@ print_f_owner_ex(struct tcb *tcp, const long addr) static int print_fcntl(struct tcb *tcp) { - if (entering(tcp)) { - printfd(tcp, tcp->u_arg[0]); - tprints(", "); - printxval(fcntlcmds, tcp->u_arg[1], "F_???"); - } switch (tcp->u_arg[1]) { case F_SETFD: tprints(", "); @@ -113,8 +109,6 @@ print_fcntl(struct tcb *tcp) tprints(", "); printflock(tcp, tcp->u_arg[2], 0); break; - case F_SETLK64: - case F_SETLKW64: case F_OFD_SETLK: case F_OFD_SETLKW: tprints(", "); @@ -159,7 +153,6 @@ print_fcntl(struct tcb *tcp) tprints(", "); printflock(tcp, tcp->u_arg[2], 1); break; - case F_GETLK64: case F_OFD_GETLK: if (entering(tcp)) return 0; @@ -196,10 +189,48 @@ print_fcntl(struct tcb *tcp) SYS_FUNC(fcntl) { + if (entering(tcp)) { + printfd(tcp, tcp->u_arg[0]); + tprints(", "); + const char *str = xlookup(fcntlcmds, tcp->u_arg[1]); + if (str) { + tprints(str); + } else { + /* + * fcntl syscall does not recognize these + * constants, but we would like to show them + * for better debugging experience. + */ + printxval(fcntl64cmds, tcp->u_arg[1], "F_???"); + } + } return print_fcntl(tcp); } SYS_FUNC(fcntl64) { + if (entering(tcp)) { + printfd(tcp, tcp->u_arg[0]); + tprints(", "); + const char *str = xlookup(fcntl64cmds, tcp->u_arg[1]); + if (str) { + tprints(str); + } else { + printxval(fcntlcmds, tcp->u_arg[1], "F_???"); + } + } + switch (tcp->u_arg[1]) { + case F_SETLK64: + case F_SETLKW64: + tprints(", "); + printflock64(tcp, tcp->u_arg[2], 0); + return RVAL_DECODED; + case F_GETLK64: + if (exiting(tcp)) { + tprints(", "); + printflock64(tcp, tcp->u_arg[2], 1); + } + return 0; + } return print_fcntl(tcp); } diff --git a/tests/.gitignore b/tests/.gitignore index 2a2fca86..ca3eb2bc 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -9,6 +9,8 @@ eventfd execve execveat fanotify_mark +fcntl +fcntl64 file_handle filter-unavailable fstat @@ -68,7 +70,6 @@ stack-fcall stat stat64 statfs -struct_flock sysinfo time timer_create diff --git a/tests/Makefile.am b/tests/Makefile.am index 3bb44eb0..56e64ab5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,6 +22,8 @@ check_PROGRAMS = \ execve \ execveat \ fanotify_mark \ + fcntl \ + fcntl64 \ file_handle \ filter-unavailable \ fstat \ @@ -81,7 +83,6 @@ check_PROGRAMS = \ stat \ stat64 \ statfs \ - struct_flock \ sysinfo \ time \ timer_create \ @@ -142,6 +143,8 @@ TESTS = \ execve.test \ execveat.test \ fanotify_mark.test \ + fcntl.test \ + fcntl64.test \ file_handle.test \ filter-unavailable.test \ fstat.test \ @@ -182,7 +185,6 @@ TESTS = \ stat.test \ stat64.test \ statfs.test \ - struct_flock.test \ sysinfo.test \ membarrier.test \ memfd_create.test \ @@ -268,6 +270,7 @@ EXTRA_DIST = init.sh run.sh match.awk \ signalfd.expected \ statfs.expected \ statx.sh \ + struct_flock.c \ sun_path.expected \ uid.awk \ uio.expected \ diff --git a/tests/fcntl.c b/tests/fcntl.c new file mode 100644 index 00000000..d4df77d8 --- /dev/null +++ b/tests/fcntl.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#ifdef __NR_fcntl + +# define TEST_SYSCALL_NAME fcntl +# include "struct_flock.c" + +#define TEST_FLOCK64_EINVAL(cmd) test_flock64_einval(cmd, #cmd) + +static void +test_flock64_einval(const int cmd, const char *name) +{ + struct_kernel_flock64 fl = { + .l_type = F_RDLCK, + .l_start = 0xdefaced1facefeed, + .l_len = 0xdefaced2cafef00d + }; + syscall(TEST_SYSCALL_NR, 0, cmd, &fl); + printf("%s(0, %s, %p) = %s\n", + TEST_SYSCALL_STR, name, &fl, EINVAL_STR); +} + +static void +test_flock64(void) +{ +/* + * F_[GS]ETOWN_EX had conflicting values with F_[GS]ETLK64 + * in kernel revisions v2.6.32-rc1~96..v2.6.32-rc7~23. + */ +#if !defined(F_GETOWN_EX) || F_GETOWN_EX != F_SETLK64 + TEST_FLOCK64_EINVAL(F_SETLK64); +#endif + TEST_FLOCK64_EINVAL(F_SETLKW64); +#if !defined(F_SETOWN_EX) || F_SETOWN_EX != F_GETLK64 + TEST_FLOCK64_EINVAL(F_GETLK64); +#endif +} + +int +main(void) +{ + if (create_sample()) + return 77; + + test_flock(); + test_flock64(); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +int +main(void) +{ + return 77; +} + +#endif diff --git a/tests/fcntl.test b/tests/fcntl.test new file mode 100755 index 00000000..4bb95fb3 --- /dev/null +++ b/tests/fcntl.test @@ -0,0 +1,14 @@ +#!/bin/sh + +# Check fcntl decoding. + +. "${srcdir=.}/init.sh" + +run_prog > /dev/null +OUT="$LOG.out" +syscall=${ME_%.test} +run_strace -a8 -e$syscall $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT" + +exit 0 diff --git a/tests/fcntl64.c b/tests/fcntl64.c new file mode 100644 index 00000000..7ffb07d3 --- /dev/null +++ b/tests/fcntl64.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#ifdef __NR_fcntl64 + +# define TEST_SYSCALL_NAME fcntl64 +# include "struct_flock.c" + +#define TEST_FLOCK64_EINVAL(cmd) test_flock64_einval(cmd, #cmd) + +static void +test_flock64_einval(const int cmd, const char *name) +{ + struct_kernel_flock64 fl = { + .l_type = F_RDLCK, + .l_start = 0xdefaced1facefeed, + .l_len = 0xdefaced2cafef00d + }; + syscall(TEST_SYSCALL_NR, 0, cmd, &fl); + printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET" + ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name, + (intmax_t) fl.l_start, (intmax_t) fl.l_len, EINVAL_STR); +} + +static void +test_flock64(void) +{ + TEST_FLOCK64_EINVAL(F_SETLK64); + TEST_FLOCK64_EINVAL(F_SETLKW64); +#ifdef F_OFD_SETLK + TEST_FLOCK64_EINVAL(F_OFD_SETLK); + TEST_FLOCK64_EINVAL(F_OFD_SETLKW); +#endif + + struct_kernel_flock64 fl = { + .l_type = F_RDLCK, + .l_len = FILE_LEN + }; + int rc = syscall(TEST_SYSCALL_NR, 0, F_SETLK64, &fl); + printf("%s(0, F_SETLK64, {l_type=F_RDLCK, l_whence=SEEK_SET" + ", l_start=0, l_len=%d}) = %s\n", + TEST_SYSCALL_STR, FILE_LEN, rc ? EINVAL_STR : "0"); + + if (rc) + return; + + syscall(TEST_SYSCALL_NR, 0, F_GETLK64, &fl); + printf("%s(0, F_GETLK64, {l_type=F_UNLCK, l_whence=SEEK_SET" + ", l_start=0, l_len=%d, l_pid=0}) = 0\n", + TEST_SYSCALL_STR, FILE_LEN); + + syscall(TEST_SYSCALL_NR, 0, F_SETLK64, &fl); + printf("%s(0, F_SETLK64, {l_type=F_UNLCK, l_whence=SEEK_SET" + ", l_start=0, l_len=%d}) = 0\n", + TEST_SYSCALL_STR, FILE_LEN); +} + +int +main(void) +{ + if (create_sample()) + return 77; + + test_flock(); + test_flock64(); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +int +main(void) +{ + return 77; +} + +#endif diff --git a/tests/fcntl64.test b/tests/fcntl64.test new file mode 100755 index 00000000..00ba671a --- /dev/null +++ b/tests/fcntl64.test @@ -0,0 +1,5 @@ +#!/bin/sh + +# Check fcntl64 syscall decoding. + +. "${srcdir=.}/fcntl.test" diff --git a/tests/struct_flock.c b/tests/struct_flock.c index 644fa945..7ab07ed8 100644 --- a/tests/struct_flock.c +++ b/tests/struct_flock.c @@ -25,115 +25,73 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include #include #include #include #include #include -#include #include "flock.h" #define FILE_LEN 4096 +#define EINVAL_STR "-1 EINVAL (Invalid argument)" + +# define TEST_SYSCALL_STR stringify(TEST_SYSCALL_NAME) +# define stringify(arg) stringify_(arg) +# define stringify_(arg) #arg + +#define TEST_SYSCALL_NR nrify(TEST_SYSCALL_NAME) +#define nrify(arg) nrify_(arg) +#define nrify_(arg) __NR_ ## arg + +#define TEST_FLOCK_EINVAL(cmd) test_flock_einval(cmd, #cmd) static void -test_flock(int nr, const char *name) +test_flock_einval(const int cmd, const char *name) { struct_kernel_flock fl = { .l_type = F_RDLCK, .l_start = (off_t) 0xdefaced1facefeed, .l_len = (off_t) 0xdefaced2cafef00d }; - int rc; - - syscall(nr, -1, F_SETLK, &fl); - printf("%s(-1, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET" - ", l_start=%jd, l_len=%jd}) = -1 %s\n", - name, (intmax_t) fl.l_start, (intmax_t) fl.l_len, - errno == EBADF ? "EBADF (Bad file descriptor)" : - "EINVAL (Invalid argument)"); - - fl.l_start = 0; - fl.l_len = FILE_LEN; - - rc = syscall(nr, 0, F_SETLK, &fl); - printf("%s(0, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET" - ", l_start=0, l_len=%d}) = %s\n", - name, FILE_LEN, rc ? "-1 EINVAL (Invalid argument)" : "0"); - - if (rc) - return; - - syscall(nr, 0, F_GETLK, &fl); - printf("%s(0, F_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET" - ", l_start=0, l_len=%d, l_pid=0}) = 0\n", name, FILE_LEN); - - syscall(nr, 0, F_SETLK, &fl); - printf("%s(0, F_SETLK, {l_type=F_UNLCK, l_whence=SEEK_SET" - ", l_start=0, l_len=%d}) = 0\n", name, FILE_LEN); - + syscall(TEST_SYSCALL_NR, 0, cmd, &fl); + printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET" + ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name, + (intmax_t) fl.l_start, (intmax_t) fl.l_len, EINVAL_STR); } static void -test_flock64(int nr, const char *name) +test_flock(void) { - struct_kernel_flock64 fl = { + TEST_FLOCK_EINVAL(F_SETLK); + TEST_FLOCK_EINVAL(F_SETLKW); + + struct_kernel_flock fl = { .l_type = F_RDLCK, - .l_start = 0xdefaced1facefeed, - .l_len = 0xdefaced2cafef00d + .l_len = FILE_LEN }; - int rc; - - syscall(nr, -1, F_SETLK64, &fl); - printf("%s(-1, F_SETLK64, {l_type=F_RDLCK, l_whence=SEEK_SET" - ", l_start=%jd, l_len=%jd}) = -1 %s\n", - name, (intmax_t) fl.l_start, (intmax_t) fl.l_len, - errno == EBADF ? "EBADF (Bad file descriptor)" : - "EINVAL (Invalid argument)"); - - fl.l_start = 0; - fl.l_len = FILE_LEN; - - rc = syscall(nr, 0, F_SETLK64, &fl); - printf("%s(0, F_SETLK64, {l_type=F_RDLCK, l_whence=SEEK_SET" + int rc = syscall(TEST_SYSCALL_NR, 0, F_SETLK, &fl); + printf("%s(0, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET" ", l_start=0, l_len=%d}) = %s\n", - name, FILE_LEN, rc ? "-1 EINVAL (Invalid argument)" : "0"); - + TEST_SYSCALL_STR, FILE_LEN, rc ? EINVAL_STR : "0"); if (rc) return; - syscall(nr, 0, F_GETLK64, &fl); - printf("%s(0, F_GETLK64, {l_type=F_UNLCK, l_whence=SEEK_SET" - ", l_start=0, l_len=%d, l_pid=0}) = 0\n", name, FILE_LEN); + syscall(TEST_SYSCALL_NR, 0, F_GETLK, &fl); + printf("%s(0, F_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET" + ", l_start=0, l_len=%d, l_pid=0}) = 0\n", + TEST_SYSCALL_STR, FILE_LEN); - syscall(nr, 0, F_SETLK64, &fl); - printf("%s(0, F_SETLK64, {l_type=F_UNLCK, l_whence=SEEK_SET" - ", l_start=0, l_len=%d}) = 0\n", name, FILE_LEN); + syscall(TEST_SYSCALL_NR, 0, F_SETLK, &fl); + printf("%s(0, F_SETLK, {l_type=F_UNLCK, l_whence=SEEK_SET" + ", l_start=0, l_len=%d}) = 0\n", + TEST_SYSCALL_STR, FILE_LEN); } -int -main(void) +static int +create_sample(void) { - char fname[] = "struct_flock_XXXXXX"; + char fname[] = TEST_SYSCALL_STR "_XXXXXX"; (void) close(0); - assert(mkstemp(fname) == 0); - assert(unlink(fname) == 0); - assert(ftruncate(0, FILE_LEN) == 0); - -#ifdef __NR_fcntl - test_flock(__NR_fcntl, "fcntl"); - test_flock64(__NR_fcntl, "fcntl"); -#endif -#ifdef __NR_fcntl64 - test_flock(__NR_fcntl64, "fcntl64"); - test_flock64(__NR_fcntl64, "fcntl64"); -#endif - - puts("+++ exited with 0 +++"); - return 0; + return mkstemp(fname) || unlink(fname) || ftruncate(0, FILE_LEN) ? 77 : 0; } diff --git a/tests/struct_flock.test b/tests/struct_flock.test deleted file mode 100755 index ab77f301..00000000 --- a/tests/struct_flock.test +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# Check struct flock and struct flock64 decoding. - -. "${srcdir=.}/init.sh" - -run_prog > /dev/null -OUT="$LOG.out" -syscalls= -for n in fcntl fcntl64; do - $STRACE -e$n -h > /dev/null && syscalls=$syscalls,$n -done -run_strace -e trace=$syscalls $args > "$OUT" -match_diff "$LOG" "$OUT" -rm -f "$OUT" - -exit 0 diff --git a/xlat/fcntl64cmds.in b/xlat/fcntl64cmds.in new file mode 100644 index 00000000..074efe45 --- /dev/null +++ b/xlat/fcntl64cmds.in @@ -0,0 +1,4 @@ +/* asm-generic/fcntl.h */ +F_GETLK64 12 +F_SETLK64 13 +F_SETLKW64 14 diff --git a/xlat/fcntlcmds.in b/xlat/fcntlcmds.in index 8f111a79..c050836c 100644 --- a/xlat/fcntlcmds.in +++ b/xlat/fcntlcmds.in @@ -11,9 +11,6 @@ F_SETOWN 8 F_GETOWN 9 F_SETSIG 10 F_GETSIG 11 -F_GETLK64 12 -F_SETLK64 13 -F_SETLKW64 14 F_SETOWN_EX 15 F_GETOWN_EX 16 F_GETOWNER_UIDS 17