* [LTP] [PATCH v2 0/6] Added memfd_create() testsuite
@ 2017-03-06 17:45 Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 1/6] Added syscall numbers for memfd_create Jakub Racek
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
memfd_create() is a syscall that creates an anonymous file. This syscall was
originally introduced in "File Sealing & memfd_create()" patchset by
David Herrmann <dh.herrmann@gmail.com>.
My patchset is a partial port of memfd_create() testsuite to LTP, with lapi
extended as necessary.
This is a V2 patchset. V1 was originally posted on 28/02/2017, but it had
LTP style problems and didn't include syscall numbers.
Code that runs _dup, _mmap and _open tests in multi-threaded environment was
not ported yet.
Jakub Racek (6):
Added syscall numbers for memfd_create
Added memfd_create() lapi flags
Added fcntl() lapi flags
Added fallocate() flags and wrapper to lapi
syscalls: added memfd_create dir and memfd_create/memfd_create01.c
syscalls/memfd_create02.c: added new test
include/lapi/fallocate.h | 66 +++
include/lapi/fcntl.h | 25 +
include/lapi/memfd.h | 27 ++
runtest/syscalls | 3 +
testcases/kernel/include/aarch64.in | 1 +
testcases/kernel/include/arm.in | 1 +
testcases/kernel/include/hppa.in | 1 +
testcases/kernel/include/i386.in | 1 +
testcases/kernel/include/ia64.in | 1 +
testcases/kernel/include/powerpc.in | 1 +
testcases/kernel/include/powerpc64.in | 1 +
testcases/kernel/include/s390.in | 1 +
testcases/kernel/include/s390x.in | 1 +
testcases/kernel/include/sh.in | 1 +
testcases/kernel/include/sparc.in | 1 +
testcases/kernel/include/sparc64.in | 1 +
testcases/kernel/include/x86_64.in | 1 +
testcases/kernel/syscalls/.gitignore | 2 +
testcases/kernel/syscalls/memfd_create/Makefile | 19 +
.../kernel/syscalls/memfd_create/memfd_create01.c | 303 ++++++++++++
.../kernel/syscalls/memfd_create/memfd_create02.c | 92 ++++
.../syscalls/memfd_create/memfd_create_common.h | 525 +++++++++++++++++++++
22 files changed, 1075 insertions(+)
create mode 100644 include/lapi/fallocate.h
create mode 100644 include/lapi/memfd.h
create mode 100644 testcases/kernel/syscalls/memfd_create/Makefile
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create01.c
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create02.c
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create_common.h
--
1.8.3.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 1/6] Added syscall numbers for memfd_create
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 2/6] Added memfd_create() lapi flags Jakub Racek
` (4 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
testcases/kernel/include/aarch64.in | 1 +
testcases/kernel/include/arm.in | 1 +
testcases/kernel/include/hppa.in | 1 +
testcases/kernel/include/i386.in | 1 +
testcases/kernel/include/ia64.in | 1 +
testcases/kernel/include/powerpc.in | 1 +
testcases/kernel/include/powerpc64.in | 1 +
testcases/kernel/include/s390.in | 1 +
testcases/kernel/include/s390x.in | 1 +
testcases/kernel/include/sh.in | 1 +
testcases/kernel/include/sparc.in | 1 +
testcases/kernel/include/sparc64.in | 1 +
testcases/kernel/include/x86_64.in | 1 +
13 files changed, 13 insertions(+)
diff --git a/testcases/kernel/include/aarch64.in b/testcases/kernel/include/aarch64.in
index cb3fe06..b81c068 100644
--- a/testcases/kernel/include/aarch64.in
+++ b/testcases/kernel/include/aarch64.in
@@ -255,3 +255,4 @@ setns 268
sendmmsg 269
kcmp 272
getrandom 278
+memfd_create 279
diff --git a/testcases/kernel/include/arm.in b/testcases/kernel/include/arm.in
index cee9718..0a5dde1 100644
--- a/testcases/kernel/include/arm.in
+++ b/testcases/kernel/include/arm.in
@@ -338,3 +338,4 @@ sched_setattr (__NR_SYSCALL_BASE+380)
sched_getattr (__NR_SYSCALL_BASE+381)
renameat2 (__NR_SYSCALL_BASE+382)
getrandom (__NR_SYSCALL_BASE+384)
+memfd_create (__NR_SYSCALL_BASE+385)
diff --git a/testcases/kernel/include/hppa.in b/testcases/kernel/include/hppa.in
index b784a2b..3946155 100644
--- a/testcases/kernel/include/hppa.in
+++ b/testcases/kernel/include/hppa.in
@@ -15,3 +15,4 @@ faccessat (__NR_openat + 12)
splice 291
tee 293
vmsplice 294
+memfd_create 340
diff --git a/testcases/kernel/include/i386.in b/testcases/kernel/include/i386.in
index 1f1cade..42c5e3f 100644
--- a/testcases/kernel/include/i386.in
+++ b/testcases/kernel/include/i386.in
@@ -338,3 +338,4 @@ sched_setattr 351
sched_getattr 352
renameat2 354
getrandom 355
+memfd_create 356
diff --git a/testcases/kernel/include/ia64.in b/testcases/kernel/include/ia64.in
index 846141f..dad25f4 100644
--- a/testcases/kernel/include/ia64.in
+++ b/testcases/kernel/include/ia64.in
@@ -294,3 +294,4 @@ fanotify_mark 1324
prlimit64 1325
renameat2 1338
getrandom 1339
+memfd_create 1340
diff --git a/testcases/kernel/include/powerpc.in b/testcases/kernel/include/powerpc.in
index 5ca42a6..10a6e5d 100644
--- a/testcases/kernel/include/powerpc.in
+++ b/testcases/kernel/include/powerpc.in
@@ -345,3 +345,4 @@ sched_setattr 355
sched_getattr 356
renameat2 357
getrandom 359
+memfd_create 360
diff --git a/testcases/kernel/include/powerpc64.in b/testcases/kernel/include/powerpc64.in
index 5ca42a6..10a6e5d 100644
--- a/testcases/kernel/include/powerpc64.in
+++ b/testcases/kernel/include/powerpc64.in
@@ -345,3 +345,4 @@ sched_setattr 355
sched_getattr 356
renameat2 357
getrandom 359
+memfd_create 360
diff --git a/testcases/kernel/include/s390.in b/testcases/kernel/include/s390.in
index afe94f5..770db7f 100644
--- a/testcases/kernel/include/s390.in
+++ b/testcases/kernel/include/s390.in
@@ -329,3 +329,4 @@ sched_setattr 345
sched_getattr 346
renameat2 347
getrandom 349
+memfd_create 350
diff --git a/testcases/kernel/include/s390x.in b/testcases/kernel/include/s390x.in
index afe94f5..770db7f 100644
--- a/testcases/kernel/include/s390x.in
+++ b/testcases/kernel/include/s390x.in
@@ -329,3 +329,4 @@ sched_setattr 345
sched_getattr 346
renameat2 347
getrandom 349
+memfd_create 350
diff --git a/testcases/kernel/include/sh.in b/testcases/kernel/include/sh.in
index 3cb7e21..0345f8d 100644
--- a/testcases/kernel/include/sh.in
+++ b/testcases/kernel/include/sh.in
@@ -362,3 +362,4 @@ fanotify_init 367
fanotify_mark 368
prlimit64 369
kcmp 378
+memfd_create 385
diff --git a/testcases/kernel/include/sparc.in b/testcases/kernel/include/sparc.in
index f266777..b84c844 100644
--- a/testcases/kernel/include/sparc.in
+++ b/testcases/kernel/include/sparc.in
@@ -334,3 +334,4 @@ prlimit64 331
kcmp 341
renameat2 345
getrandom 347
+memfd_create 348
diff --git a/testcases/kernel/include/sparc64.in b/testcases/kernel/include/sparc64.in
index cb91828..7e0be30 100644
--- a/testcases/kernel/include/sparc64.in
+++ b/testcases/kernel/include/sparc64.in
@@ -310,3 +310,4 @@ prlimit64 331
kcmp 341
renameat2 345
getrandom 347
+memfd_create 348
diff --git a/testcases/kernel/include/x86_64.in b/testcases/kernel/include/x86_64.in
index f54abf4..dec7742 100644
--- a/testcases/kernel/include/x86_64.in
+++ b/testcases/kernel/include/x86_64.in
@@ -305,3 +305,4 @@ sched_setattr 314
sched_getattr 315
renameat2 316
getrandom 318
+memfd_create 319
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 2/6] Added memfd_create() lapi flags
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 1/6] Added syscall numbers for memfd_create Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 3/6] Added fcntl() " Jakub Racek
` (3 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
include/lapi/memfd.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 include/lapi/memfd.h
diff --git a/include/lapi/memfd.h b/include/lapi/memfd.h
new file mode 100644
index 0000000..18ed40f
--- /dev/null
+++ b/include/lapi/memfd.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef LAPI_MEMFD_H
+#define LAPI_MEMFD_H
+
+/* flags for memfd_create(2) (unsigned int) */
+#ifndef MFD_CLOEXEC
+# define MFD_CLOEXEC 0x0001U
+#endif
+#ifndef MFD_ALLOW_SEALING
+# define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 3/6] Added fcntl() lapi flags
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 1/6] Added syscall numbers for memfd_create Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 2/6] Added memfd_create() lapi flags Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi Jakub Racek
` (2 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
include/lapi/fcntl.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/include/lapi/fcntl.h b/include/lapi/fcntl.h
index 38e41ec..849439d 100644
--- a/include/lapi/fcntl.h
+++ b/include/lapi/fcntl.h
@@ -50,6 +50,31 @@
# define F_GETPIPE_SZ 1032
#endif
+/*
+ * Set/Get seals
+ */
+#ifndef F_ADD_SEALS
+# define F_ADD_SEALS (1033)
+#endif
+
+#ifndef F_GET_SEALS
+# define F_GET_SEALS (1034)
+#endif
+
+#ifndef F_SEAL_SEAL
+# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+#endif
+
+#ifndef F_SEAL_SHRINK
+# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+#endif
+#ifndef F_SEAL_GROW
+# define F_SEAL_GROW 0x0004 /* prevent file from growing */
+#endif
+#ifndef F_SEAL_WRITE
+# define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
#ifndef F_OWNER_PGRP
# define F_OWNER_PGRP 2
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
` (2 preceding siblings ...)
2017-03-06 17:45 ` [LTP] [PATCH v2 3/6] Added fcntl() " Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-07 11:44 ` Cyril Hrubis
2017-03-06 17:45 ` [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test Jakub Racek
5 siblings, 1 reply; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
include/lapi/fallocate.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 include/lapi/fallocate.h
diff --git a/include/lapi/fallocate.h b/include/lapi/fallocate.h
new file mode 100644
index 0000000..79d0b7b
--- /dev/null
+++ b/include/lapi/fallocate.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ */
+
+#ifndef FALLOCATE_H
+#define FALLOCATE_H
+
+#include <sys/types.h>
+#include <endian.h>
+#include "config.h"
+#include "lapi/abisize.h"
+#include "linux_syscall_numbers.h"
+
+#ifndef SEEK_HOLE
+# define SEEK_HOLE 4
+#endif
+
+#ifndef FALLOC_FL_KEEP_SIZE
+# define FALLOC_FL_KEEP_SIZE 0x01
+#endif
+
+#ifndef FALLOC_FL_PUNCH_HOLE
+# define FALLOC_FL_PUNCH_HOLE 0x02
+#endif
+
+#ifndef FALLOC_FL_COLLAPSE_RANGE
+# define FALLOC_FL_COLLAPSE_RANGE 0x08
+#endif
+
+#ifndef FALLOC_FL_ZERO_RANGE
+# define FALLOC_FL_ZERO_RANGE 0x10
+#endif
+
+#ifndef FALLOC_FL_INSERT_RANGE
+# define FALLOC_FL_INSERT_RANGE 0x20
+#endif
+
+#if !defined(HAVE_FALLOCATE)
+static inline long fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+ /* Deal with 32bit ABIs that have 64bit syscalls. */
+# if LTP_USE_64_ABI
+ return ltp_syscall(__NR_fallocate, fd, mode, offset, len);
+# else
+ return (long)ltp_syscall(__NR_fallocate, fd, mode,
+ __LONG_LONG_PAIR((off_t) (offset >> 32),
+ (off_t) offset),
+ __LONG_LONG_PAIR((off_t) (len >> 32),
+ (off_t) len));
+# endif
+}
+#endif
+
+#endif /* FALLOCATE_H */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
` (3 preceding siblings ...)
2017-03-06 17:45 ` [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-07 12:17 ` Cyril Hrubis
2017-03-06 17:45 ` [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test Jakub Racek
5 siblings, 1 reply; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
runtest/syscalls | 2 +
testcases/kernel/syscalls/.gitignore | 1 +
testcases/kernel/syscalls/memfd_create/Makefile | 19 +
.../kernel/syscalls/memfd_create/memfd_create01.c | 303 ++++++++++++
.../syscalls/memfd_create/memfd_create_common.h | 525 +++++++++++++++++++++
5 files changed, 850 insertions(+)
create mode 100644 testcases/kernel/syscalls/memfd_create/Makefile
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create01.c
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create_common.h
diff --git a/runtest/syscalls b/runtest/syscalls
index 931a354..fd305ce 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1448,3 +1448,5 @@ futex_wake03 futex_wake03
futex_wake04 futex_wake04
futex_wait_bitset01 futex_wait_bitset01
futex_wait_bitset02 futex_wait_bitset02
+
+memfd_create01 memfd_create01
diff --git a/testcases/kernel/syscalls/.gitignore b/testcases/kernel/syscalls/.gitignore
index 9a4727c..915b1b9 100644
--- a/testcases/kernel/syscalls/.gitignore
+++ b/testcases/kernel/syscalls/.gitignore
@@ -1116,3 +1116,4 @@
/fanotify/fanotify06
/perf_event_open/perf_event_open01
/perf_event_open/perf_event_open02
+/memfd_create/memfd_create01
diff --git a/testcases/kernel/syscalls/memfd_create/Makefile b/testcases/kernel/syscalls/memfd_create/Makefile
new file mode 100644
index 0000000..9dbc4b9
--- /dev/null
+++ b/testcases/kernel/syscalls/memfd_create/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+top_srcdir ?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create01.c b/testcases/kernel/syscalls/memfd_create/memfd_create01.c
new file mode 100644
index 0000000..a950ce5
--- /dev/null
+++ b/testcases/kernel/syscalls/memfd_create/memfd_create01.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+ /*
+ * Based on Linux/tools/testing/selftests/memfd/memfd_test.c
+ * by David Herrmann <dh.herrmann@gmail.com>
+ *
+ * 24/02/2017 Port to LTP <jracek@redhat.com>
+ */
+
+#define _GNU_SOURCE
+
+#include "tst_test.h"
+#include "memfd_create_common.h"
+
+/*
+ * Do few basic sealing tests to see whether setting/retrieving seals works.
+ */
+static void test_basic(int fd)
+{
+ /* add basic seals */
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE));
+
+ /* add them again */
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE));
+
+ /* add more seals and seal against sealing */
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE |
+ F_SEAL_SEAL));
+
+ /* verify that sealing no longer works */
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
+ CHECK_RESULT(mfd_fail_add_seals(fd, 0));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Verify that no sealing is possible when memfd is created without
+ * MFD_ALLOW_SEALING flag.
+ */
+static void test_no_sealing_without_flag(int fd)
+{
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test SEAL_WRITE
+ * Test whether SEAL_WRITE actually prevents modifications.
+ */
+static void test_seal_write(int fd)
+{
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
+
+ CHECK_RESULT(mfd_assert_read(fd));
+ CHECK_RESULT(mfd_fail_write(fd));
+ CHECK_RESULT(mfd_assert_shrink(fd));
+ CHECK_RESULT(mfd_assert_grow(fd));
+ CHECK_RESULT(mfd_fail_grow_write(fd));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test SEAL_SHRINK
+ * Test whether SEAL_SHRINK actually prevents shrinking
+ */
+static void test_seal_shrink(int fd)
+{
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
+
+ CHECK_RESULT(mfd_assert_read(fd));
+ CHECK_RESULT(mfd_assert_write(fd));
+ CHECK_RESULT(mfd_fail_shrink(fd));
+ CHECK_RESULT(mfd_assert_grow(fd));
+ CHECK_RESULT(mfd_assert_grow_write(fd));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test SEAL_GROW
+ * Test whether SEAL_GROW actually prevents growing
+ */
+static void test_seal_grow(int fd)
+{
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_GROW));
+
+ CHECK_RESULT(mfd_assert_read(fd));
+ CHECK_RESULT(mfd_assert_write(fd));
+ CHECK_RESULT(mfd_assert_shrink(fd));
+ CHECK_RESULT(mfd_fail_grow(fd));
+ CHECK_RESULT(mfd_fail_grow_write(fd));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test SEAL_SHRINK | SEAL_GROW
+ * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
+ */
+static void test_seal_resize(int fd)
+{
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
+
+ CHECK_RESULT(mfd_assert_read(fd));
+ CHECK_RESULT(mfd_assert_write(fd));
+ CHECK_RESULT(mfd_fail_shrink(fd));
+ CHECK_RESULT(mfd_fail_grow(fd));
+ CHECK_RESULT(mfd_fail_grow_write(fd));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test sharing via dup()
+ * Test that seals are shared between dupped FDs and they're all equal.
+ */
+static void test_share_dup(int fd)
+{
+ int fd2;
+
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+
+ fd2 = SAFE_DUP(fd);
+ CHECK_RESULT(mfd_assert_has_seals(fd2, 0));
+
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
+
+ CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
+
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SEAL));
+ CHECK_RESULT(mfd_assert_has_seals(fd,
+ F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
+ CHECK_RESULT(mfd_assert_has_seals(fd2,
+ F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
+
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
+ CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_GROW));
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
+ CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_SEAL));
+
+ SAFE_CLOSE(fd2);
+
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test sealing with active mmap()s
+ * Modifying seals is only allowed if no other mmap() refs exist.
+ */
+static void test_share_mmap(int fd)
+{
+ void *p;
+
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+
+ /* shared/writable ref prevents sealing WRITE, but allows others */
+ p = SAFE_MMAP(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
+ SAFE_MUNMAP(p, MFD_DEF_SIZE);
+
+ /* readable ref allows sealing */
+ p = SAFE_MMAP(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
+ SAFE_MUNMAP(p, MFD_DEF_SIZE);
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+/*
+ * Test sealing with open(/proc/self/fd/%d)
+ * Via /proc we can get access to a separate file-context for the same memfd.
+ * This is *not* like dup(), but like a real separate open(). Make sure the
+ * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
+ */
+static void test_share_open(int fd)
+{
+ int fd2;
+
+ CHECK_RESULT(mfd_assert_has_seals(fd, 0));
+
+ fd2 = CHECK_RESULT(mfd_assert_open(fd, O_RDWR, 0));
+ CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
+ CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
+
+ CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
+
+ SAFE_CLOSE(fd);
+ fd = CHECK_RESULT(mfd_assert_open(fd2, O_RDONLY, 0));
+
+ CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
+ CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
+ CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
+
+ SAFE_CLOSE(fd2);
+
+ tst_res(TPASS, "%s", __func__);
+}
+
+static const struct tcase {
+ int flags;
+ void (*func)(int fd);
+} tcases[] = {
+ {MFD_ALLOW_SEALING, &test_basic},
+ {0, &test_no_sealing_without_flag},
+
+ {MFD_ALLOW_SEALING, &test_seal_write},
+ {MFD_ALLOW_SEALING, &test_seal_shrink},
+ {MFD_ALLOW_SEALING, &test_seal_grow},
+ {MFD_ALLOW_SEALING, &test_seal_resize},
+
+ {MFD_ALLOW_SEALING, &test_share_dup},
+ {MFD_ALLOW_SEALING, &test_share_mmap},
+ {MFD_ALLOW_SEALING, &test_share_open},
+};
+
+static void verify_memfd_create(unsigned int n)
+{
+ const struct tcase *tc;
+
+ tc = &tcases[n];
+
+ TEST(mfd_assert_new(TCID, MFD_DEF_SIZE, tc->flags));
+ if (TEST_RETURN < 0)
+ tst_brk(TBROK | TERRNO, "memfd_create() failed unexpectedly");
+
+ tc->func(TEST_RETURN);
+
+ if (TEST_RETURN > 0)
+ SAFE_CLOSE(TEST_RETURN);
+}
+
+static void setup(void)
+{
+ ASSERT_HAVE_MEMFD_CREATE();
+}
+
+static struct tst_test test = {
+ .tid = "memfd_create01",
+ .test = verify_memfd_create,
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+};
diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create_common.h b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
new file mode 100644
index 0000000..f07cc8c
--- /dev/null
+++ b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MEMFD_TEST_COMMON
+#define MEMFD_TEST_COMMON
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <lapi/fallocate.h>
+#include <lapi/fcntl.h>
+#include <lapi/memfd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include <tst_test.h>
+
+#include "linux_syscall_numbers.h"
+
+#define MFD_DEF_SIZE 8192
+#define STACK_SIZE 65536
+
+enum assert_retval {
+ ALL_OK,
+ MEMFD_FAIL,
+ MEMFD_MISMATCH,
+ FTRUNCATE_FAIL,
+ FCNTL_FAIL,
+ GET_SEALS_MISMATCH,
+ ADD_SEALS_FAIL,
+ ADD_SEALS_MISMATCH,
+ FSTAT_FAIL,
+ FILE_SIZE_MISMATCH,
+ OPEN_MISMATCH,
+ OPEN_FAIL,
+ MPROTECT_FAIL,
+ FALLOCATE_PUNCH_FAIL,
+ WRITE_FAIL,
+ WRITE_MISMATCH,
+ MUNMAP_FAIL,
+ MMAP_FAIL,
+ MMAP_MISMATCH,
+ MMAP_MPROT_MISMATCH,
+ FALLOCATE_PUNCH_MISMATCH,
+ FTRUNCATE_SHRINK_MISMATCH,
+ FALLOCATE_ALLOC_FAIL,
+ FTRUNCATE_GROW_MISMATCH,
+ FALLOCATE_ALLOC_MISMATCH,
+ PWRITE_FAIL,
+ PWRITE_MISMATCH,
+ READ_FAIL,
+ READ_MISMATCH,
+ CLOSE_FAIL,
+};
+
+const char *err_msg[] = {
+ "all OK",
+ "memfd_create() failed",
+ "memfd_create() succeeded, but failure expected",
+ "ftruncate() failed",
+ "fcntl() failed",
+ "GET_SEALS() returned unexpected value",
+ "ADD_SEALS() failed",
+ "ADD_SEALS() didn't fail as expected",
+ "fstat() failed",
+ "wrong file size",
+ "open() didn't fail as expected",
+ "open() failed",
+ "mprotect() failed",
+ "fallocate(PUNCH_HOLE) failed",
+ "write() failed",
+ "write() didn't fail as expected",
+ "munmap() failed",
+ "mmap() failed",
+ "mmap() didn't fail as expected",
+ "mmap()+mprotect() didn't fail as expected",
+ "fallocate(PUNCH_HOLE) didn't fail as expected",
+ "ftruncate(SHRINK) didn't fail as expected",
+ "fallocate(ALLOC) failed",
+ "ftruncate(GROW) didn't fail as expected",
+ "fallocate(ALLOC) didn't fail as expected",
+ "pwrite() failed",
+ "pwrite() didn't fail as expected",
+ "read() failed",
+ "read() didn't fail as expected",
+ "close() failed",
+};
+
+#define STRINGIFY(A) #A
+
+#define CHECK_RESULT(func2call) ({ \
+ int result; \
+ result = func2call; \
+ if (result < ALL_OK) \
+ tst_brk(TFAIL, "%s: %s", STRINGIFY(func2call), \
+ err_msg[-result]); \
+ else \
+ tst_res(TPASS, "%s", STRINGIFY(func2call)); \
+ result; \
+})
+
+#define ASSERT_HAVE_MEMFD_CREATE() do { \
+ int r; \
+ r = mfd_assert_new("dummy_call", 0, 0); \
+ if (r < 0) \
+ tst_brk(TCONF, "memfd_create does not exist on your system."); \
+ SAFE_CLOSE(r); \
+ } while (0)
+
+static int sys_memfd_create(const char *name,
+ unsigned int flags)
+{
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
+{
+ int fd, r;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd < 0)
+ return -MEMFD_FAIL;
+
+ r = ftruncate(fd, sz);
+ if (r < 0)
+ return -FTRUNCATE_FAIL;
+
+ return fd;
+}
+
+static int mfd_fail_new(const char *name, unsigned int flags)
+{
+ int fd;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd >= 0) {
+ close(fd);
+ return -MEMFD_MISMATCH;
+ }
+
+ return fd;
+}
+
+static int mfd_assert_get_seals(int fd)
+{
+ int r;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ return -FCNTL_FAIL;
+
+ return r;
+}
+
+static int mfd_assert_has_seals(int fd, int seals)
+{
+ int s;
+
+ s = mfd_assert_get_seals(fd);
+ if (s < 0)
+ return s;
+
+ if (s != seals)
+ return -GET_SEALS_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_add_seals(int fd, int seals)
+{
+ int r;
+
+ r = mfd_assert_get_seals(fd);
+ if (r < 0)
+ return r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0)
+ return -ADD_SEALS_FAIL;
+
+ return ALL_OK;
+}
+
+static int mfd_fail_add_seals(int fd, int seals)
+{
+ int r;
+ int s;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ s = 0;
+ else
+ s = r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r >= 0)
+ return -ADD_SEALS_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_size(int fd, size_t size)
+{
+ struct stat st;
+ int r;
+
+ r = fstat(fd, &st);
+ if (r < 0)
+ return -FSTAT_FAIL;
+ else if (st.st_size != (long)size)
+ return -FILE_SIZE_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+
+ r = open(buf, flags, mode);
+ if (r < 0)
+ return -OPEN_FAIL;
+
+ return r;
+}
+
+static int mfd_fail_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+
+ r = open(buf, flags, mode);
+ if (r >= 0)
+ return -OPEN_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_read(int fd)
+{
+ char buf[16];
+ void *p;
+ ssize_t l;
+
+ l = read(fd, buf, sizeof(buf));
+ if (l != sizeof(buf))
+ return -READ_FAIL;
+
+ /* verify PROT_READ *is* allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED)
+ return -MMAP_FAIL;
+
+ if (munmap(p, MFD_DEF_SIZE) < 0)
+ return -MUNMAP_FAIL;
+
+ /* verify MAP_PRIVATE is *always* allowed (even writable) */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED)
+ return -MMAP_FAIL;
+
+ if (munmap(p, MFD_DEF_SIZE) < 0)
+ return -MUNMAP_FAIL;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_write(int fd)
+{
+ void *p;
+ int r;
+
+ /* verify write() succeeds */
+ if (write(fd, "\0\0\0\0", 4) != 4)
+ return -WRITE_FAIL;
+
+ /* verify PROT_READ | PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED)
+ return -MMAP_FAIL;
+
+ *(char *)p = 0;
+ if (munmap(p, MFD_DEF_SIZE) < 0)
+ return -MUNMAP_FAIL;
+
+ /* verify PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED)
+ return -MMAP_FAIL;
+
+ *(char *)p = 0;
+ if (munmap(p, MFD_DEF_SIZE) < 0)
+ return -MUNMAP_FAIL;
+
+ /* verify PROT_READ with MAP_SHARED is allowed and a following
+ * mprotect(PROT_WRITE) allows writing
+ */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED)
+ return -MMAP_FAIL;
+
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r < 0)
+ return -MPROTECT_FAIL;
+
+ *(char *)p = 0;
+ if (munmap(p, MFD_DEF_SIZE) < 0)
+ return -MUNMAP_FAIL;
+
+ /* verify PUNCH_HOLE works */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r < 0)
+ return -FALLOCATE_PUNCH_FAIL;
+
+ return ALL_OK;
+}
+
+static int mfd_fail_write(int fd)
+{
+ ssize_t l;
+ void *p;
+ int r;
+
+ /* verify write() fails */
+ l = write(fd, "data", 4);
+ if (l != -EPERM)
+ return -WRITE_MISMATCH;
+
+ /* verify PROT_READ | PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED)
+ return -MMAP_MISMATCH;
+
+ /* verify PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED)
+ return -MMAP_MISMATCH;
+
+ /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
+ * allowed. Note that for r/w the kernel already prevents the mmap.
+ */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r >= 0)
+ return -MMAP_MPROT_MISMATCH;
+ }
+
+ /* verify PUNCH_HOLE fails */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r >= 0)
+ return -FALLOCATE_PUNCH_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_shrink(int fd)
+{
+ int fd2, r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r < 0)
+ return -FTRUNCATE_FAIL;
+
+ r = mfd_assert_size(fd, MFD_DEF_SIZE / 2);
+ if (r < 0)
+ return r;
+
+ fd2 = mfd_assert_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ 0600);
+ if (fd2 < 0)
+ return fd2;
+
+ if (close(fd2) < 0)
+ return -CLOSE_FAIL;
+
+ return mfd_assert_size(fd, 0);
+}
+
+static int mfd_fail_shrink(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r >= 0)
+ return -FTRUNCATE_SHRINK_MISMATCH;
+
+ return mfd_fail_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ 0600);
+}
+
+static int mfd_assert_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r < 0)
+ return -FTRUNCATE_FAIL;
+
+ r = mfd_assert_size(fd, MFD_DEF_SIZE * 2);
+ if (r < 0)
+ return r;
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r < 0)
+ return -FALLOCATE_ALLOC_FAIL;
+
+ return mfd_assert_size(fd, MFD_DEF_SIZE * 4);
+}
+
+static int mfd_fail_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r >= 0)
+ return -FTRUNCATE_GROW_MISMATCH;
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r >= 0)
+ return -FALLOCATE_ALLOC_MISMATCH;
+
+ return ALL_OK;
+}
+
+static int mfd_assert_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l != sizeof(buf))
+ return -PWRITE_FAIL;
+
+ return mfd_assert_size(fd, MFD_DEF_SIZE * 8);
+}
+
+static int mfd_fail_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l == sizeof(buf))
+ return -PWRITE_MISMATCH;
+
+ return ALL_OK;
+}
+
+#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
` (4 preceding siblings ...)
2017-03-06 17:45 ` [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c Jakub Racek
@ 2017-03-06 17:45 ` Jakub Racek
2017-03-07 12:21 ` Cyril Hrubis
5 siblings, 1 reply; 12+ messages in thread
From: Jakub Racek @ 2017-03-06 17:45 UTC (permalink / raw)
To: ltp
Signed-off-by: Jakub Racek <jracek@redhat.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/.gitignore | 1 +
.../kernel/syscalls/memfd_create/memfd_create02.c | 92 ++++++++++++++++++++++
3 files changed, 94 insertions(+)
create mode 100644 testcases/kernel/syscalls/memfd_create/memfd_create02.c
diff --git a/runtest/syscalls b/runtest/syscalls
index fd305ce..3d59686 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1450,3 +1450,4 @@ futex_wait_bitset01 futex_wait_bitset01
futex_wait_bitset02 futex_wait_bitset02
memfd_create01 memfd_create01
+memfd_create02 memfd_create02
diff --git a/testcases/kernel/syscalls/.gitignore b/testcases/kernel/syscalls/.gitignore
index 915b1b9..75227f9 100644
--- a/testcases/kernel/syscalls/.gitignore
+++ b/testcases/kernel/syscalls/.gitignore
@@ -1117,3 +1117,4 @@
/perf_event_open/perf_event_open01
/perf_event_open/perf_event_open02
/memfd_create/memfd_create01
+/memfd_create/memfd_create02
diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create02.c b/testcases/kernel/syscalls/memfd_create/memfd_create02.c
new file mode 100644
index 0000000..b7c2815
--- /dev/null
+++ b/testcases/kernel/syscalls/memfd_create/memfd_create02.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+ /*
+ * Based on Linux/tools/testing/selftests/memfd/memfd_test.c
+ * by David Herrmann <dh.herrmann@gmail.com>
+ *
+ * 24/02/2017 Port to LTP <jracek@redhat.com>
+ */
+
+#define _GNU_SOURCE
+
+#include <tst_test.h>
+
+#include "memfd_create_common.h"
+
+static char buf[2048];
+static char term_buf[2048];
+
+static const struct tcase {
+ char *descr;
+ char *memfd_name;
+ int flags;
+ int memfd_create_exp_err;
+} tcases[] = {
+ /*
+ * Test memfd_create() syscall
+ * Verify syscall-argument validation, including name checks,
+ * flag validation and more.
+ */
+ {"invalid name fail 1", NULL, 0, EFAULT },
+ {"invalid name fail 2", buf, 0, EINVAL },
+ {"invalid name fail 3", term_buf, 0, EINVAL },
+
+ {"invalid flags fail 1", "test", -500, EINVAL },
+ {"invalid flags fail 2", "test", 0x0100, EINVAL },
+ {"invalid flags fail 3", "test", ~MFD_CLOEXEC, EINVAL },
+ {"invalid flags fail 4", "test", ~MFD_ALLOW_SEALING, EINVAL },
+ {"invalid flags fail 5", "test", ~0, EINVAL },
+ {"invalid flags fail 6", "test", 0x80000000U, EINVAL },
+
+ {"valid flags 1 pass", "test", MFD_CLOEXEC, 0 },
+ {"valid flags 2 pass", "test", MFD_ALLOW_SEALING, 0 },
+ {"valid flags 3 pass", "test", MFD_CLOEXEC | MFD_ALLOW_SEALING, 0 },
+ {"valid flags 4 pass", "test", 0, 0 },
+ {"valid flags 5 pass", "", 0, 0 },
+};
+
+static void setup(void)
+{
+ ASSERT_HAVE_MEMFD_CREATE();
+
+ memset(buf, 0xff, sizeof(buf));
+
+ memset(term_buf, 0xff, sizeof(term_buf));
+ term_buf[sizeof(term_buf) - 1] = 0;
+}
+
+static void verify_memfd_create_errno(unsigned int n)
+{
+ const struct tcase *tc;
+
+ tc = &tcases[n];
+
+ TEST(mfd_fail_new(tc->memfd_name, tc->flags));
+ if (TEST_ERRNO != tc->memfd_create_exp_err)
+ tst_brk(TFAIL, "test '%s'", tc->descr);
+ else
+ tst_res(TPASS, "test '%s'", tc->descr);
+
+ if (TEST_RETURN > 0)
+ SAFE_CLOSE(TEST_RETURN);
+}
+
+static struct tst_test test = {
+ .tid = "memfd_create02",
+ .test = verify_memfd_create_errno,
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi
2017-03-06 17:45 ` [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi Jakub Racek
@ 2017-03-07 11:44 ` Cyril Hrubis
0 siblings, 0 replies; 12+ messages in thread
From: Cyril Hrubis @ 2017-03-07 11:44 UTC (permalink / raw)
To: ltp
Hi!
This patch should also remove the original file
(testcases/kernel/syscalls/fallocate/fallocate.h) and fix the fallocate
testcases to include the header in lapi/.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c
2017-03-06 17:45 ` [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c Jakub Racek
@ 2017-03-07 12:17 ` Cyril Hrubis
2017-03-07 13:08 ` Jakub =?unknown-8bit?q?Ra=C4=8Dek?=
0 siblings, 1 reply; 12+ messages in thread
From: Cyril Hrubis @ 2017-03-07 12:17 UTC (permalink / raw)
To: ltp
Hi!
> +/*
> + * Do few basic sealing tests to see whether setting/retrieving seals works.
> + */
> +static void test_basic(int fd)
> +{
> + /* add basic seals */
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_WRITE));
> +
> + /* add them again */
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_WRITE));
> +
> + /* add more seals and seal against sealing */
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_GROW |
> + F_SEAL_WRITE |
> + F_SEAL_SEAL));
> +
> + /* verify that sealing no longer works */
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
> + CHECK_RESULT(mfd_fail_add_seals(fd, 0));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Verify that no sealing is possible when memfd is created without
> + * MFD_ALLOW_SEALING flag.
> + */
> +static void test_no_sealing_without_flag(int fd)
> +{
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SHRINK |
> + F_SEAL_GROW |
> + F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test SEAL_WRITE
> + * Test whether SEAL_WRITE actually prevents modifications.
> + */
> +static void test_seal_write(int fd)
> +{
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
> +
> + CHECK_RESULT(mfd_assert_read(fd));
> + CHECK_RESULT(mfd_fail_write(fd));
> + CHECK_RESULT(mfd_assert_shrink(fd));
> + CHECK_RESULT(mfd_assert_grow(fd));
> + CHECK_RESULT(mfd_fail_grow_write(fd));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test SEAL_SHRINK
> + * Test whether SEAL_SHRINK actually prevents shrinking
> + */
> +static void test_seal_shrink(int fd)
> +{
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
> +
> + CHECK_RESULT(mfd_assert_read(fd));
> + CHECK_RESULT(mfd_assert_write(fd));
> + CHECK_RESULT(mfd_fail_shrink(fd));
> + CHECK_RESULT(mfd_assert_grow(fd));
> + CHECK_RESULT(mfd_assert_grow_write(fd));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test SEAL_GROW
> + * Test whether SEAL_GROW actually prevents growing
> + */
> +static void test_seal_grow(int fd)
> +{
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_GROW));
> +
> + CHECK_RESULT(mfd_assert_read(fd));
> + CHECK_RESULT(mfd_assert_write(fd));
> + CHECK_RESULT(mfd_assert_shrink(fd));
> + CHECK_RESULT(mfd_fail_grow(fd));
> + CHECK_RESULT(mfd_fail_grow_write(fd));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test SEAL_SHRINK | SEAL_GROW
> + * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
> + */
> +static void test_seal_resize(int fd)
> +{
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
> +
> + CHECK_RESULT(mfd_assert_read(fd));
> + CHECK_RESULT(mfd_assert_write(fd));
> + CHECK_RESULT(mfd_fail_shrink(fd));
> + CHECK_RESULT(mfd_fail_grow(fd));
> + CHECK_RESULT(mfd_fail_grow_write(fd));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test sharing via dup()
> + * Test that seals are shared between dupped FDs and they're all equal.
> + */
> +static void test_share_dup(int fd)
> +{
> + int fd2;
> +
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> +
> + fd2 = SAFE_DUP(fd);
> + CHECK_RESULT(mfd_assert_has_seals(fd2, 0));
> +
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
> +
> + CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
> +
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SEAL));
> + CHECK_RESULT(mfd_assert_has_seals(fd,
> + F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
> + CHECK_RESULT(mfd_assert_has_seals(fd2,
> + F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
> +
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
> + CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_GROW));
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
> + CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_SEAL));
> +
> + SAFE_CLOSE(fd2);
> +
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test sealing with active mmap()s
> + * Modifying seals is only allowed if no other mmap() refs exist.
> + */
> +static void test_share_mmap(int fd)
> +{
> + void *p;
> +
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> +
> + /* shared/writable ref prevents sealing WRITE, but allows others */
> + p = SAFE_MMAP(NULL,
> + MFD_DEF_SIZE,
> + PROT_READ | PROT_WRITE,
> + MAP_SHARED,
> + fd,
> + 0);
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
> + SAFE_MUNMAP(p, MFD_DEF_SIZE);
> +
> + /* readable ref allows sealing */
> + p = SAFE_MMAP(NULL,
> + MFD_DEF_SIZE,
> + PROT_READ,
> + MAP_PRIVATE,
> + fd,
> + 0);
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
> + SAFE_MUNMAP(p, MFD_DEF_SIZE);
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +/*
> + * Test sealing with open(/proc/self/fd/%d)
> + * Via /proc we can get access to a separate file-context for the same memfd.
> + * This is *not* like dup(), but like a real separate open(). Make sure the
> + * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
> + */
> +static void test_share_open(int fd)
> +{
> + int fd2;
> +
> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
> +
> + fd2 = CHECK_RESULT(mfd_assert_open(fd, O_RDWR, 0));
> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
> +
> + CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
> +
> + SAFE_CLOSE(fd);
> + fd = CHECK_RESULT(mfd_assert_open(fd2, O_RDONLY, 0));
> +
> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
> +
> + SAFE_CLOSE(fd2);
> +
> + tst_res(TPASS, "%s", __func__);
> +}
> +
> +static const struct tcase {
> + int flags;
> + void (*func)(int fd);
> +} tcases[] = {
> + {MFD_ALLOW_SEALING, &test_basic},
> + {0, &test_no_sealing_without_flag},
> +
> + {MFD_ALLOW_SEALING, &test_seal_write},
> + {MFD_ALLOW_SEALING, &test_seal_shrink},
> + {MFD_ALLOW_SEALING, &test_seal_grow},
> + {MFD_ALLOW_SEALING, &test_seal_resize},
> +
> + {MFD_ALLOW_SEALING, &test_share_dup},
> + {MFD_ALLOW_SEALING, &test_share_mmap},
> + {MFD_ALLOW_SEALING, &test_share_open},
> +};
> +
> +static void verify_memfd_create(unsigned int n)
> +{
> + const struct tcase *tc;
> +
> + tc = &tcases[n];
> +
> + TEST(mfd_assert_new(TCID, MFD_DEF_SIZE, tc->flags));
> + if (TEST_RETURN < 0)
> + tst_brk(TBROK | TERRNO, "memfd_create() failed unexpectedly");
> +
> + tc->func(TEST_RETURN);
> +
> + if (TEST_RETURN > 0)
> + SAFE_CLOSE(TEST_RETURN);
> +}
> +
> +static void setup(void)
> +{
> + ASSERT_HAVE_MEMFD_CREATE();
> +}
> +
> +static struct tst_test test = {
> + .tid = "memfd_create01",
> + .test = verify_memfd_create,
> + .tcnt = ARRAY_SIZE(tcases),
> + .setup = setup,
> +};
> diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create_common.h b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
> new file mode 100644
> index 0000000..f07cc8c
> --- /dev/null
> +++ b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
> @@ -0,0 +1,525 @@
> +/*
> + * Copyright (C) 2017 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef MEMFD_TEST_COMMON
> +#define MEMFD_TEST_COMMON
> +
> +#include <sys/types.h>
> +#include <sys/syscall.h>
> +#include <sys/uio.h>
> +#include <lapi/fallocate.h>
> +#include <lapi/fcntl.h>
> +#include <lapi/memfd.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include <tst_test.h>
> +
> +#include "linux_syscall_numbers.h"
> +
> +#define MFD_DEF_SIZE 8192
> +#define STACK_SIZE 65536
> +
> +enum assert_retval {
> + ALL_OK,
> + MEMFD_FAIL,
> + MEMFD_MISMATCH,
> + FTRUNCATE_FAIL,
> + FCNTL_FAIL,
> + GET_SEALS_MISMATCH,
> + ADD_SEALS_FAIL,
> + ADD_SEALS_MISMATCH,
> + FSTAT_FAIL,
> + FILE_SIZE_MISMATCH,
> + OPEN_MISMATCH,
> + OPEN_FAIL,
> + MPROTECT_FAIL,
> + FALLOCATE_PUNCH_FAIL,
> + WRITE_FAIL,
> + WRITE_MISMATCH,
> + MUNMAP_FAIL,
> + MMAP_FAIL,
> + MMAP_MISMATCH,
> + MMAP_MPROT_MISMATCH,
> + FALLOCATE_PUNCH_MISMATCH,
> + FTRUNCATE_SHRINK_MISMATCH,
> + FALLOCATE_ALLOC_FAIL,
> + FTRUNCATE_GROW_MISMATCH,
> + FALLOCATE_ALLOC_MISMATCH,
> + PWRITE_FAIL,
> + PWRITE_MISMATCH,
> + READ_FAIL,
> + READ_MISMATCH,
> + CLOSE_FAIL,
> +};
> +
> +const char *err_msg[] = {
> + "all OK",
> + "memfd_create() failed",
> + "memfd_create() succeeded, but failure expected",
> + "ftruncate() failed",
> + "fcntl() failed",
> + "GET_SEALS() returned unexpected value",
> + "ADD_SEALS() failed",
> + "ADD_SEALS() didn't fail as expected",
> + "fstat() failed",
> + "wrong file size",
> + "open() didn't fail as expected",
> + "open() failed",
> + "mprotect() failed",
> + "fallocate(PUNCH_HOLE) failed",
> + "write() failed",
> + "write() didn't fail as expected",
> + "munmap() failed",
> + "mmap() failed",
> + "mmap() didn't fail as expected",
> + "mmap()+mprotect() didn't fail as expected",
> + "fallocate(PUNCH_HOLE) didn't fail as expected",
> + "ftruncate(SHRINK) didn't fail as expected",
> + "fallocate(ALLOC) failed",
> + "ftruncate(GROW) didn't fail as expected",
> + "fallocate(ALLOC) didn't fail as expected",
> + "pwrite() failed",
> + "pwrite() didn't fail as expected",
> + "read() failed",
> + "read() didn't fail as expected",
> + "close() failed",
> +};
> +
> +#define STRINGIFY(A) #A
> +
> +#define CHECK_RESULT(func2call) ({ \
> + int result; \
> + result = func2call; \
> + if (result < ALL_OK) \
> + tst_brk(TFAIL, "%s: %s", STRINGIFY(func2call), \
> + err_msg[-result]); \
> + else \
> + tst_res(TPASS, "%s", STRINGIFY(func2call)); \
> + result; \
> +})
> +
> +#define ASSERT_HAVE_MEMFD_CREATE() do { \
> + int r; \
> + r = mfd_assert_new("dummy_call", 0, 0); \
> + if (r < 0) \
> + tst_brk(TCONF, "memfd_create does not exist on your system."); \
> + SAFE_CLOSE(r); \
^
The indentation here is confusing.
> + } while (0)
> +
> +static int sys_memfd_create(const char *name,
> + unsigned int flags)
> +{
> + return syscall(__NR_memfd_create, name, flags);
> +}
> +
> +static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
> +{
> + int fd, r;
> +
> + fd = sys_memfd_create(name, flags);
> + if (fd < 0)
> + return -MEMFD_FAIL;
> +
> + r = ftruncate(fd, sz);
> + if (r < 0)
> + return -FTRUNCATE_FAIL;
> +
> + return fd;
> +}
This indirection (returning error number and matching it agains table is
confusing as well).
I wonder if we should do this similarily to safe macros, i.e. doing
something as:
#define SAFE_MFD_NEW(name, sz, flags) \
safe_mfd_new(__FILE__, __LINE__, name, flags);
static int safe_mfd_new(const char *filename, const char lineno,
const char *name, unsigned int flags)
{
int fd;
if (sys_memfd_create(name, flags)) {
tst_brk(TBROK | TERRNO,
"%s:%i: memfd_create(%s,%u) failed",
file, lineno, name, flags);
}
return fd;
}
Then we could do something as:
int fd;
fd = SAFE_MFD_NEW("foo", 0);
SAFE_FTRUNCATE(fd, sz);
In the main test function, which seems to be much clearer code to me.
> +static int mfd_fail_new(const char *name, unsigned int flags)
> +{
> + int fd;
> +
> + fd = sys_memfd_create(name, flags);
> + if (fd >= 0) {
> + close(fd);
> + return -MEMFD_MISMATCH;
> + }
> +
> + return fd;
> +}
> +
> +static int mfd_assert_get_seals(int fd)
> +{
> + int r;
> +
> + r = fcntl(fd, F_GET_SEALS);
> + if (r < 0)
> + return -FCNTL_FAIL;
> +
> + return r;
> +}
This could be just replaced with SAFE_FCNTL() in the test code.
> +static int mfd_assert_has_seals(int fd, int seals)
> +{
> + int s;
> +
> + s = mfd_assert_get_seals(fd);
> + if (s < 0)
> + return s;
> +
> + if (s != seals)
> + return -GET_SEALS_MISMATCH;
> +
> + return ALL_OK;
> +}
This as well, you can even just do:
int s;
s = SAFE_FCNTL(fd, F_GET_SEALS);
if (seals != s) {
tst_res(TFAIL, "Unexpected seals %i, expected %i",
seals, s);
}
> +static int mfd_assert_add_seals(int fd, int seals)
> +{
> + int r;
> +
> + r = mfd_assert_get_seals(fd);
> + if (r < 0)
> + return r;
> +
> + r = fcntl(fd, F_ADD_SEALS, seals);
> + if (r < 0)
> + return -ADD_SEALS_FAIL;
> +
> + return ALL_OK;
> +}
Again this is just one SAFE_FCNTL();
> +static int mfd_fail_add_seals(int fd, int seals)
> +{
> + int r;
> + int s;
> +
> + r = fcntl(fd, F_GET_SEALS);
> + if (r < 0)
> + s = 0;
> + else
> + s = r;
This does not make any sense, is the s variable used for anything at
all?
> + r = fcntl(fd, F_ADD_SEALS, seals);
> + if (r >= 0)
> + return -ADD_SEALS_MISMATCH;
> +
> + return ALL_OK;
> +}
And we can so something as:
#define FAIL_ADD_SEALS(fd, seals) \
fail_add_seals(__FILE__, __LINE__, fd, seals)
static void fail_add_seals(const char *file, const int lineno,
int fd, int seals)
{
if (fcntl(fd, F_ADD_SEALS, seals) >= 0) {
tst_res(TFAIL,
"%s:%i: fcntl(%i, F_ADD_SEALS, %i) passed unexpectedly",
file, lineno, fd, seals);
} else {
tst_res(TPASS, "%s:%i: fcntl(%i, F_ADD_SEALS, %i) failed",
file, lineno, fd, seals);
}
}
For the negative testcases.
> +static int mfd_assert_size(int fd, size_t size)
> +{
> + struct stat st;
> + int r;
> +
> + r = fstat(fd, &st);
> + if (r < 0)
> + return -FSTAT_FAIL;
> + else if (st.st_size != (long)size)
> + return -FILE_SIZE_MISMATCH;
> +
> + return ALL_OK;
> +}
We have SAFE_FSTAT() as well. etc.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test
2017-03-06 17:45 ` [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test Jakub Racek
@ 2017-03-07 12:21 ` Cyril Hrubis
0 siblings, 0 replies; 12+ messages in thread
From: Cyril Hrubis @ 2017-03-07 12:21 UTC (permalink / raw)
To: ltp
Hi!
This one looks good, as well as the rest of the patches I didn't comment
on.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c
2017-03-07 12:17 ` Cyril Hrubis
@ 2017-03-07 13:08 ` Jakub =?unknown-8bit?q?Ra=C4=8Dek?=
2017-03-07 13:21 ` Cyril Hrubis
0 siblings, 1 reply; 12+ messages in thread
From: Jakub =?unknown-8bit?q?Ra=C4=8Dek?= @ 2017-03-07 13:08 UTC (permalink / raw)
To: ltp
Hi,
SAFE_MFD_NEW and others should go to "include/tst_safe_macros.h", right?
If I undestand this correctly, negative testcases will have to stay in
memfd_create_common.h. That means I can't use
SAFE_ macros in those functions/macros, as that would obscure line
numbers. And putting those elsewhere would duplicate a lot of code.
Jakub Racek
On 03/07/2017 01:17 PM, Cyril Hrubis wrote:
> Hi!
>> +/*
>> + * Do few basic sealing tests to see whether setting/retrieving seals works.
>> + */
>> +static void test_basic(int fd)
>> +{
>> + /* add basic seals */
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_WRITE));
>> +
>> + /* add them again */
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_WRITE));
>> +
>> + /* add more seals and seal against sealing */
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_GROW |
>> + F_SEAL_WRITE |
>> + F_SEAL_SEAL));
>> +
>> + /* verify that sealing no longer works */
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
>> + CHECK_RESULT(mfd_fail_add_seals(fd, 0));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Verify that no sealing is possible when memfd is created without
>> + * MFD_ALLOW_SEALING flag.
>> + */
>> +static void test_no_sealing_without_flag(int fd)
>> +{
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SHRINK |
>> + F_SEAL_GROW |
>> + F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SEAL));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test SEAL_WRITE
>> + * Test whether SEAL_WRITE actually prevents modifications.
>> + */
>> +static void test_seal_write(int fd)
>> +{
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
>> +
>> + CHECK_RESULT(mfd_assert_read(fd));
>> + CHECK_RESULT(mfd_fail_write(fd));
>> + CHECK_RESULT(mfd_assert_shrink(fd));
>> + CHECK_RESULT(mfd_assert_grow(fd));
>> + CHECK_RESULT(mfd_fail_grow_write(fd));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test SEAL_SHRINK
>> + * Test whether SEAL_SHRINK actually prevents shrinking
>> + */
>> +static void test_seal_shrink(int fd)
>> +{
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
>> +
>> + CHECK_RESULT(mfd_assert_read(fd));
>> + CHECK_RESULT(mfd_assert_write(fd));
>> + CHECK_RESULT(mfd_fail_shrink(fd));
>> + CHECK_RESULT(mfd_assert_grow(fd));
>> + CHECK_RESULT(mfd_assert_grow_write(fd));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test SEAL_GROW
>> + * Test whether SEAL_GROW actually prevents growing
>> + */
>> +static void test_seal_grow(int fd)
>> +{
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_GROW));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_GROW));
>> +
>> + CHECK_RESULT(mfd_assert_read(fd));
>> + CHECK_RESULT(mfd_assert_write(fd));
>> + CHECK_RESULT(mfd_assert_shrink(fd));
>> + CHECK_RESULT(mfd_fail_grow(fd));
>> + CHECK_RESULT(mfd_fail_grow_write(fd));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test SEAL_SHRINK | SEAL_GROW
>> + * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
>> + */
>> +static void test_seal_resize(int fd)
>> +{
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW));
>> +
>> + CHECK_RESULT(mfd_assert_read(fd));
>> + CHECK_RESULT(mfd_assert_write(fd));
>> + CHECK_RESULT(mfd_fail_shrink(fd));
>> + CHECK_RESULT(mfd_fail_grow(fd));
>> + CHECK_RESULT(mfd_fail_grow_write(fd));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test sharing via dup()
>> + * Test that seals are shared between dupped FDs and they're all equal.
>> + */
>> +static void test_share_dup(int fd)
>> +{
>> + int fd2;
>> +
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> +
>> + fd2 = SAFE_DUP(fd);
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, 0));
>> +
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
>> +
>> + CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
>> +
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_assert_has_seals(fd,
>> + F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2,
>> + F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL));
>> +
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
>> + CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_GROW));
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_fail_add_seals(fd2, F_SEAL_SEAL));
>> +
>> + SAFE_CLOSE(fd2);
>> +
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_GROW));
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test sealing with active mmap()s
>> + * Modifying seals is only allowed if no other mmap() refs exist.
>> + */
>> +static void test_share_mmap(int fd)
>> +{
>> + void *p;
>> +
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> +
>> + /* shared/writable ref prevents sealing WRITE, but allows others */
>> + p = SAFE_MMAP(NULL,
>> + MFD_DEF_SIZE,
>> + PROT_READ | PROT_WRITE,
>> + MAP_SHARED,
>> + fd,
>> + 0);
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_SHRINK));
>> + SAFE_MUNMAP(p, MFD_DEF_SIZE);
>> +
>> + /* readable ref allows sealing */
>> + p = SAFE_MMAP(NULL,
>> + MFD_DEF_SIZE,
>> + PROT_READ,
>> + MAP_PRIVATE,
>> + fd,
>> + 0);
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
>> + SAFE_MUNMAP(p, MFD_DEF_SIZE);
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +/*
>> + * Test sealing with open(/proc/self/fd/%d)
>> + * Via /proc we can get access to a separate file-context for the same memfd.
>> + * This is *not* like dup(), but like a real separate open(). Make sure the
>> + * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
>> + */
>> +static void test_share_open(int fd)
>> +{
>> + int fd2;
>> +
>> + CHECK_RESULT(mfd_assert_has_seals(fd, 0));
>> +
>> + fd2 = CHECK_RESULT(mfd_assert_open(fd, O_RDWR, 0));
>> + CHECK_RESULT(mfd_assert_add_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE));
>> +
>> + CHECK_RESULT(mfd_assert_add_seals(fd2, F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
>> +
>> + SAFE_CLOSE(fd);
>> + fd = CHECK_RESULT(mfd_assert_open(fd2, O_RDONLY, 0));
>> +
>> + CHECK_RESULT(mfd_fail_add_seals(fd, F_SEAL_SEAL));
>> + CHECK_RESULT(mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK));
>> + CHECK_RESULT(mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK));
>> +
>> + SAFE_CLOSE(fd2);
>> +
>> + tst_res(TPASS, "%s", __func__);
>> +}
>> +
>> +static const struct tcase {
>> + int flags;
>> + void (*func)(int fd);
>> +} tcases[] = {
>> + {MFD_ALLOW_SEALING, &test_basic},
>> + {0, &test_no_sealing_without_flag},
>> +
>> + {MFD_ALLOW_SEALING, &test_seal_write},
>> + {MFD_ALLOW_SEALING, &test_seal_shrink},
>> + {MFD_ALLOW_SEALING, &test_seal_grow},
>> + {MFD_ALLOW_SEALING, &test_seal_resize},
>> +
>> + {MFD_ALLOW_SEALING, &test_share_dup},
>> + {MFD_ALLOW_SEALING, &test_share_mmap},
>> + {MFD_ALLOW_SEALING, &test_share_open},
>> +};
>> +
>> +static void verify_memfd_create(unsigned int n)
>> +{
>> + const struct tcase *tc;
>> +
>> + tc = &tcases[n];
>> +
>> + TEST(mfd_assert_new(TCID, MFD_DEF_SIZE, tc->flags));
>> + if (TEST_RETURN < 0)
>> + tst_brk(TBROK | TERRNO, "memfd_create() failed unexpectedly");
>> +
>> + tc->func(TEST_RETURN);
>> +
>> + if (TEST_RETURN > 0)
>> + SAFE_CLOSE(TEST_RETURN);
>> +}
>> +
>> +static void setup(void)
>> +{
>> + ASSERT_HAVE_MEMFD_CREATE();
>> +}
>> +
>> +static struct tst_test test = {
>> + .tid = "memfd_create01",
>> + .test = verify_memfd_create,
>> + .tcnt = ARRAY_SIZE(tcases),
>> + .setup = setup,
>> +};
>> diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create_common.h b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
>> new file mode 100644
>> index 0000000..f07cc8c
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/memfd_create/memfd_create_common.h
>> @@ -0,0 +1,525 @@
>> +/*
>> + * Copyright (C) 2017 Red Hat, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#ifndef MEMFD_TEST_COMMON
>> +#define MEMFD_TEST_COMMON
>> +
>> +#include <sys/types.h>
>> +#include <sys/syscall.h>
>> +#include <sys/uio.h>
>> +#include <lapi/fallocate.h>
>> +#include <lapi/fcntl.h>
>> +#include <lapi/memfd.h>
>> +#include <errno.h>
>> +#include <string.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +
>> +#define TST_NO_DEFAULT_MAIN
>> +#include <tst_test.h>
>> +
>> +#include "linux_syscall_numbers.h"
>> +
>> +#define MFD_DEF_SIZE 8192
>> +#define STACK_SIZE 65536
>> +
>> +enum assert_retval {
>> + ALL_OK,
>> + MEMFD_FAIL,
>> + MEMFD_MISMATCH,
>> + FTRUNCATE_FAIL,
>> + FCNTL_FAIL,
>> + GET_SEALS_MISMATCH,
>> + ADD_SEALS_FAIL,
>> + ADD_SEALS_MISMATCH,
>> + FSTAT_FAIL,
>> + FILE_SIZE_MISMATCH,
>> + OPEN_MISMATCH,
>> + OPEN_FAIL,
>> + MPROTECT_FAIL,
>> + FALLOCATE_PUNCH_FAIL,
>> + WRITE_FAIL,
>> + WRITE_MISMATCH,
>> + MUNMAP_FAIL,
>> + MMAP_FAIL,
>> + MMAP_MISMATCH,
>> + MMAP_MPROT_MISMATCH,
>> + FALLOCATE_PUNCH_MISMATCH,
>> + FTRUNCATE_SHRINK_MISMATCH,
>> + FALLOCATE_ALLOC_FAIL,
>> + FTRUNCATE_GROW_MISMATCH,
>> + FALLOCATE_ALLOC_MISMATCH,
>> + PWRITE_FAIL,
>> + PWRITE_MISMATCH,
>> + READ_FAIL,
>> + READ_MISMATCH,
>> + CLOSE_FAIL,
>> +};
>> +
>> +const char *err_msg[] = {
>> + "all OK",
>> + "memfd_create() failed",
>> + "memfd_create() succeeded, but failure expected",
>> + "ftruncate() failed",
>> + "fcntl() failed",
>> + "GET_SEALS() returned unexpected value",
>> + "ADD_SEALS() failed",
>> + "ADD_SEALS() didn't fail as expected",
>> + "fstat() failed",
>> + "wrong file size",
>> + "open() didn't fail as expected",
>> + "open() failed",
>> + "mprotect() failed",
>> + "fallocate(PUNCH_HOLE) failed",
>> + "write() failed",
>> + "write() didn't fail as expected",
>> + "munmap() failed",
>> + "mmap() failed",
>> + "mmap() didn't fail as expected",
>> + "mmap()+mprotect() didn't fail as expected",
>> + "fallocate(PUNCH_HOLE) didn't fail as expected",
>> + "ftruncate(SHRINK) didn't fail as expected",
>> + "fallocate(ALLOC) failed",
>> + "ftruncate(GROW) didn't fail as expected",
>> + "fallocate(ALLOC) didn't fail as expected",
>> + "pwrite() failed",
>> + "pwrite() didn't fail as expected",
>> + "read() failed",
>> + "read() didn't fail as expected",
>> + "close() failed",
>> +};
>> +
>> +#define STRINGIFY(A) #A
>> +
>> +#define CHECK_RESULT(func2call) ({ \
>> + int result; \
>> + result = func2call; \
>> + if (result < ALL_OK) \
>> + tst_brk(TFAIL, "%s: %s", STRINGIFY(func2call), \
>> + err_msg[-result]); \
>> + else \
>> + tst_res(TPASS, "%s", STRINGIFY(func2call)); \
>> + result; \
>> +})
>> +
>> +#define ASSERT_HAVE_MEMFD_CREATE() do { \
>> + int r; \
>> + r = mfd_assert_new("dummy_call", 0, 0); \
>> + if (r < 0) \
>> + tst_brk(TCONF, "memfd_create does not exist on your system."); \
>> + SAFE_CLOSE(r); \
> ^
> The indentation here is confusing.
>
>> + } while (0)
>> +
>> +static int sys_memfd_create(const char *name,
>> + unsigned int flags)
>> +{
>> + return syscall(__NR_memfd_create, name, flags);
>> +}
>> +
>> +static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
>> +{
>> + int fd, r;
>> +
>> + fd = sys_memfd_create(name, flags);
>> + if (fd < 0)
>> + return -MEMFD_FAIL;
>> +
>> + r = ftruncate(fd, sz);
>> + if (r < 0)
>> + return -FTRUNCATE_FAIL;
>> +
>> + return fd;
>> +}
> This indirection (returning error number and matching it agains table is
> confusing as well).
>
> I wonder if we should do this similarily to safe macros, i.e. doing
> something as:
>
> #define SAFE_MFD_NEW(name, sz, flags) \
> safe_mfd_new(__FILE__, __LINE__, name, flags);
>
> static int safe_mfd_new(const char *filename, const char lineno,
> const char *name, unsigned int flags)
> {
> int fd;
>
> if (sys_memfd_create(name, flags)) {
> tst_brk(TBROK | TERRNO,
> "%s:%i: memfd_create(%s,%u) failed",
> file, lineno, name, flags);
> }
>
> return fd;
> }
>
> Then we could do something as:
>
> int fd;
>
> fd = SAFE_MFD_NEW("foo", 0);
> SAFE_FTRUNCATE(fd, sz);
>
> In the main test function, which seems to be much clearer code to me.
>
>> +static int mfd_fail_new(const char *name, unsigned int flags)
>> +{
>> + int fd;
>> +
>> + fd = sys_memfd_create(name, flags);
>> + if (fd >= 0) {
>> + close(fd);
>> + return -MEMFD_MISMATCH;
>> + }
>> +
>> + return fd;
>> +}
>> +
>> +static int mfd_assert_get_seals(int fd)
>> +{
>> + int r;
>> +
>> + r = fcntl(fd, F_GET_SEALS);
>> + if (r < 0)
>> + return -FCNTL_FAIL;
>> +
>> + return r;
>> +}
> This could be just replaced with SAFE_FCNTL() in the test code.
>
>> +static int mfd_assert_has_seals(int fd, int seals)
>> +{
>> + int s;
>> +
>> + s = mfd_assert_get_seals(fd);
>> + if (s < 0)
>> + return s;
>> +
>> + if (s != seals)
>> + return -GET_SEALS_MISMATCH;
>> +
>> + return ALL_OK;
>> +}
> This as well, you can even just do:
>
> int s;
>
> s = SAFE_FCNTL(fd, F_GET_SEALS);
>
> if (seals != s) {
> tst_res(TFAIL, "Unexpected seals %i, expected %i",
> seals, s);
> }
>
>> +static int mfd_assert_add_seals(int fd, int seals)
>> +{
>> + int r;
>> +
>> + r = mfd_assert_get_seals(fd);
>> + if (r < 0)
>> + return r;
>> +
>> + r = fcntl(fd, F_ADD_SEALS, seals);
>> + if (r < 0)
>> + return -ADD_SEALS_FAIL;
>> +
>> + return ALL_OK;
>> +}
> Again this is just one SAFE_FCNTL();
>
>> +static int mfd_fail_add_seals(int fd, int seals)
>> +{
>> + int r;
>> + int s;
>> +
>> + r = fcntl(fd, F_GET_SEALS);
>> + if (r < 0)
>> + s = 0;
>> + else
>> + s = r;
> This does not make any sense, is the s variable used for anything at
> all?
>
>> + r = fcntl(fd, F_ADD_SEALS, seals);
>> + if (r >= 0)
>> + return -ADD_SEALS_MISMATCH;
>> +
>> + return ALL_OK;
>> +}
> And we can so something as:
>
> #define FAIL_ADD_SEALS(fd, seals) \
> fail_add_seals(__FILE__, __LINE__, fd, seals)
>
> static void fail_add_seals(const char *file, const int lineno,
> int fd, int seals)
> {
> if (fcntl(fd, F_ADD_SEALS, seals) >= 0) {
> tst_res(TFAIL,
> "%s:%i: fcntl(%i, F_ADD_SEALS, %i) passed unexpectedly",
> file, lineno, fd, seals);
> } else {
> tst_res(TPASS, "%s:%i: fcntl(%i, F_ADD_SEALS, %i) failed",
> file, lineno, fd, seals);
> }
> }
>
> For the negative testcases.
>
>> +static int mfd_assert_size(int fd, size_t size)
>> +{
>> + struct stat st;
>> + int r;
>> +
>> + r = fstat(fd, &st);
>> + if (r < 0)
>> + return -FSTAT_FAIL;
>> + else if (st.st_size != (long)size)
>> + return -FILE_SIZE_MISMATCH;
>> +
>> + return ALL_OK;
>> +}
> We have SAFE_FSTAT() as well. etc.
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c
2017-03-07 13:08 ` Jakub =?unknown-8bit?q?Ra=C4=8Dek?=
@ 2017-03-07 13:21 ` Cyril Hrubis
0 siblings, 0 replies; 12+ messages in thread
From: Cyril Hrubis @ 2017-03-07 13:21 UTC (permalink / raw)
To: ltp
Hi!
> SAFE_MFD_NEW and others should go to "include/tst_safe_macros.h", right?
That one is too big at this point. And I guess that this call would not
be usefull anywhere else than this testsuite, so having it in local
header should be fine.
> If I undestand this correctly, negative testcases will have to stay in
> memfd_create_common.h. That means I can't use
> SAFE_ macros in those functions/macros, as that would obscure line
> numbers. And putting those elsewhere would duplicate a lot of code.
Hmm, we can always use the functions SAFE_MACROS call and pass filename
and line number explicitly.
#define FAIL_MFD_FOO(foo, bar) \
fail_mfd_foo(__FILE__, __LINE__, foo, bar)
void fail_mfd_foo(const char *file, const int lineno, int foo, int bar)
{
int ret;
ret = safe_foo(file, lineno, foo);
...
}
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2017-03-07 13:21 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-06 17:45 [LTP] [PATCH v2 0/6] Added memfd_create() testsuite Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 1/6] Added syscall numbers for memfd_create Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 2/6] Added memfd_create() lapi flags Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 3/6] Added fcntl() " Jakub Racek
2017-03-06 17:45 ` [LTP] [PATCH v2 4/6] Added fallocate() flags and wrapper to lapi Jakub Racek
2017-03-07 11:44 ` Cyril Hrubis
2017-03-06 17:45 ` [LTP] [PATCH v2 5/6] syscalls: added memfd_create dir and memfd_create/memfd_create01.c Jakub Racek
2017-03-07 12:17 ` Cyril Hrubis
2017-03-07 13:08 ` Jakub =?unknown-8bit?q?Ra=C4=8Dek?=
2017-03-07 13:21 ` Cyril Hrubis
2017-03-06 17:45 ` [LTP] [PATCH v2 6/6] syscalls/memfd_create02.c: added new test Jakub Racek
2017-03-07 12:21 ` Cyril Hrubis
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.