From: Allison Karlitskaya Date: Tue, 13 Oct 2020 11:17:11 +0000 (+0200) Subject: Linux: Add wrapper for fcntl(F_{GET,ADD}_SEALS) X-Git-Tag: VALGRIND_3_17_0~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dec30506534c0c1bb0e77e62275e697b041e3c3a;p=thirdparty%2Fvalgrind.git Linux: Add wrapper for fcntl(F_{GET,ADD}_SEALS) Add also a testcase to memcheck/tests/linux, enabled according to a new check for memfd_create() in configure.ac. https://bugs.kde.org/show_bug.cgi?id=361770 --- diff --git a/.gitignore b/.gitignore index dff20848e6..eec6169891 100644 --- a/.gitignore +++ b/.gitignore @@ -1047,6 +1047,7 @@ /memcheck/tests/linux/lsframe2 /memcheck/tests/linux/Makefile /memcheck/tests/linux/Makefile.in +/memcheck/tests/linux/memfd /memcheck/tests/linux/rfcomm /memcheck/tests/linux/sigqueue /memcheck/tests/linux/stack_changes diff --git a/NEWS b/NEWS index cdd103b01e..55bf58ae8a 100644 --- a/NEWS +++ b/NEWS @@ -78,6 +78,7 @@ where XXXXXX is the bug number as listed below. 140939 --track-fds reports leakage of stdout/in/err and doesn't respect -q 217695 malloc/calloc/realloc/memalign failure doesn't set errno to ENOMEM 345077 linux syscall execveat support (linux 3.19) +361770 Missing F_ADD_SEALS 369029 handle linux syscalls sched_getattr and sched_setattr 384729 __libc_freeres inhibits cross-platform valgrind 391853 Makefile.all.am:L247 and @SOLARIS_UNDEF_LARGESOURCE@ being empty diff --git a/configure.ac b/configure.ac index 41ae942429..4648450fe3 100755 --- a/configure.ac +++ b/configure.ac @@ -4358,6 +4358,7 @@ AC_CHECK_FUNCS([ \ klogctl \ mallinfo \ memchr \ + memfd_create \ memset \ mkdir \ mremap \ @@ -4409,6 +4410,8 @@ AM_CONDITIONAL([HAVE_PREADV_PWRITEV], [test x$ac_cv_func_preadv = xyes && test x$ac_cv_func_pwritev = xyes]) AM_CONDITIONAL([HAVE_PREADV2_PWRITEV2], [test x$ac_cv_func_preadv2 = xyes && test x$ac_cv_func_pwritev2 = xyes]) +AM_CONDITIONAL([HAVE_MEMFD_CREATE], + [test x$ac_cv_func_memfd_create = xyes]) if test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \ diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index fcc534454a..3d6939d147 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -6784,6 +6784,7 @@ PRE(sys_fcntl) case VKI_F_GETSIG: case VKI_F_GETLEASE: case VKI_F_GETPIPE_SZ: + case VKI_F_GET_SEALS: PRINT("sys_fcntl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2); PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd); break; @@ -6798,6 +6799,7 @@ PRE(sys_fcntl) case VKI_F_SETOWN: case VKI_F_SETSIG: case VKI_F_SETPIPE_SZ: + case VKI_F_ADD_SEALS: PRINT("sys_fcntl[ARG3=='arg'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); PRE_REG_READ3(long, "fcntl", @@ -6930,6 +6932,7 @@ PRE(sys_fcntl64) case VKI_F_GETSIG: case VKI_F_SETSIG: case VKI_F_GETLEASE: + case VKI_F_GET_SEALS: PRINT("sys_fcntl64 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2); PRE_REG_READ2(long, "fcntl64", unsigned int, fd, unsigned int, cmd); break; @@ -6941,6 +6944,7 @@ PRE(sys_fcntl64) case VKI_F_SETFL: case VKI_F_SETLEASE: case VKI_F_NOTIFY: + case VKI_F_ADD_SEALS: PRINT("sys_fcntl64[ARG3=='arg'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); PRE_REG_READ3(long, "fcntl64", diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h index 3b9dc37796..426d9db92f 100644 --- a/include/vki/vki-linux.h +++ b/include/vki/vki-linux.h @@ -1504,6 +1504,9 @@ struct vki_dirent64 { #define VKI_F_SETPIPE_SZ (VKI_F_LINUX_SPECIFIC_BASE + 7) #define VKI_F_GETPIPE_SZ (VKI_F_LINUX_SPECIFIC_BASE + 8) +#define VKI_F_ADD_SEALS (VKI_F_LINUX_SPECIFIC_BASE + 9) +#define VKI_F_GET_SEALS (VKI_F_LINUX_SPECIFIC_BASE + 10) + struct vki_flock { short l_type; short l_whence; diff --git a/memcheck/tests/linux/Makefile.am b/memcheck/tests/linux/Makefile.am index 1c53ffbaf8..7e796aa7fa 100644 --- a/memcheck/tests/linux/Makefile.am +++ b/memcheck/tests/linux/Makefile.am @@ -13,6 +13,7 @@ EXTRA_DIST = \ ioctl-tiocsig.vgtest ioctl-tiocsig.stderr.exp \ lsframe1.vgtest lsframe1.stdout.exp lsframe1.stderr.exp \ lsframe2.vgtest lsframe2.stdout.exp lsframe2.stderr.exp \ + memfd.vgtest memfd.stderr.exp \ rfcomm.vgtest rfcomm.stderr.exp \ sigqueue.vgtest sigqueue.stderr.exp \ stack_changes.stderr.exp stack_changes.stdout.exp \ @@ -58,6 +59,10 @@ if HAVE_AT_FDCWD check_PROGRAMS += sys-openat endif +if HAVE_MEMFD_CREATE +check_PROGRAMS += memfd +endif + if HAVE_COPY_FILE_RANGE check_PROGRAMS += sys-copy_file_range endif diff --git a/memcheck/tests/linux/memfd.c b/memcheck/tests/linux/memfd.c new file mode 100644 index 0000000000..f37e4b5c2f --- /dev/null +++ b/memcheck/tests/linux/memfd.c @@ -0,0 +1,75 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "../../memcheck.h" + +static void +assert_expected (int fd, int expected_seals) +{ + int current_seals = fcntl (fd, F_GET_SEALS); + assert (current_seals == expected_seals); +} + +static void +add_seal (int fd, int *expected_seals, int new_seal) +{ + int r = fcntl (fd, F_ADD_SEALS, new_seal); + assert (r == 0); + + *expected_seals |= new_seal; + + // Make sure we get the result we expected. + assert_expected (fd, *expected_seals); +} + +static void +add_seal_expect_fail (int fd, int new_seal, int expected_errno) +{ + int r = fcntl (fd, F_ADD_SEALS, new_seal); + assert (r == -1 && errno == expected_errno); +} + +int +main (void) +{ + int expected_seals = 0; + int fd; + + // Try with an fd that doesn't support sealing. + fd = memfd_create ("xyz", 0); + if (fd < 0) + { + // Not supported, nothing to test... + return 1; + } + + assert_expected (fd, F_SEAL_SEAL); + add_seal_expect_fail (fd, F_SEAL_WRITE, EPERM); + assert_expected (fd, F_SEAL_SEAL); // ...should still be unset after failed attempt + close (fd); + + // Now, try the successful case. + fd = memfd_create ("xyz", MFD_ALLOW_SEALING); + add_seal (fd, &expected_seals, F_SEAL_SHRINK); + add_seal (fd, &expected_seals, F_SEAL_GROW); + + // Now prevent more sealing. + add_seal (fd, &expected_seals, F_SEAL_SEAL); + + // And make sure that it indeed fails. + add_seal_expect_fail (fd, F_SEAL_WRITE, EPERM); + assert_expected (fd, expected_seals); + close (fd); + + // Test the only memory failure possible: passing an undefined argument to F_ADD_SEALS + int undefined_seal = 0; + VALGRIND_MAKE_MEM_UNDEFINED(&undefined_seal, sizeof undefined_seal); + fcntl (-1, F_ADD_SEALS, undefined_seal); + + return 0; +} diff --git a/memcheck/tests/linux/memfd.stderr.exp b/memcheck/tests/linux/memfd.stderr.exp new file mode 100644 index 0000000000..13009d8ae4 --- /dev/null +++ b/memcheck/tests/linux/memfd.stderr.exp @@ -0,0 +1,6 @@ +Syscall param fcntl(arg) contains uninitialised byte(s) + ... + by 0x........: main (memfd.c:72) + Uninitialised value was created by a client request + at 0x........: main (memfd.c:71) + diff --git a/memcheck/tests/linux/memfd.vgtest b/memcheck/tests/linux/memfd.vgtest new file mode 100644 index 0000000000..4096401f73 --- /dev/null +++ b/memcheck/tests/linux/memfd.vgtest @@ -0,0 +1,3 @@ +prereq: test -e memfd +vgopts: -q --track-origins=yes +prog: memfd