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
This commit is contained in:
Allison Karlitskaya 2020-10-13 13:17:11 +02:00 committed by Mark Wielaard
parent 7aac53c6d0
commit dec3050653
9 changed files with 101 additions and 0 deletions

1
.gitignore vendored
View File

@ -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

1
NEWS
View File

@ -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

View File

@ -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 \

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,75 @@
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#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;
}

View File

@ -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)

View File

@ -0,0 +1,3 @@
prereq: test -e memfd
vgopts: -q --track-origins=yes
prog: memfd