Re: [PATCH v14 10/10] secretmem: test: add basic selftest for memfd_secret(2)

2020-12-12 Thread Mike Rapoport
Hi John,

On Fri, Dec 11, 2020 at 10:16:23PM -0800, John Hubbard wrote:
> On 12/2/20 10:29 PM, Mike Rapoport wrote:
> > From: Mike Rapoport 
> ...
> > +#include "../kselftest.h"
> > +
> > +#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__)
> > +#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__)
> > +#define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__)
> > +
> > +#ifdef __NR_memfd_secret
> > +
> > +#include 
> 
> Hi Mike,
> 
> Say, when I tried this out from today's linux-next, I had to delete the
> above line. In other words, the following was required in order to build:
> 
> diff --git a/tools/testing/selftests/vm/memfd_secret.c 
> b/tools/testing/selftests/vm/memfd_secret.c
> index 79578dfd13e6..c878c2b841fc 100644
> --- a/tools/testing/selftests/vm/memfd_secret.c
> +++ b/tools/testing/selftests/vm/memfd_secret.c
> @@ -29,8 +29,6 @@
> 
>  #ifdef __NR_memfd_secret
> 
> -#include 
> -
>  #define PATTERN0x55
> 
>  static const int prot = PROT_READ | PROT_WRITE;
> 
> 
> ...and that makes sense to me, because:
> 
> a) secretmem.h is not in the uapi, which this selftests/vm build system
>expects (it runs "make headers_install" for us, which is *not* going
>to pick up items in the kernel include dirs), and
> 
> b) There is nothing in secretmem.h that this test uses, anyway! Just these:
> 
> bool vma_is_secretmem(struct vm_area_struct *vma);
> bool page_is_secretmem(struct page *page);
> bool secretmem_active(void);
> 
> 
> ...or am I just Doing It Wrong? :)

You are perfectly right, I had a stale header in uapi from the prevoius
versions, the include in the test remained from then.

@Andrew, can you please add the hunk above as a fixup?

> thanks,
> -- 
> John Hubbard
> NVIDIA

-- 
Sincerely yours,
Mike.


Re: [PATCH v14 10/10] secretmem: test: add basic selftest for memfd_secret(2)

2020-12-11 Thread John Hubbard

On 12/2/20 10:29 PM, Mike Rapoport wrote:

From: Mike Rapoport 

...

+#include "../kselftest.h"
+
+#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__)
+#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__)
+#define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__)
+
+#ifdef __NR_memfd_secret
+
+#include 


Hi Mike,

Say, when I tried this out from today's linux-next, I had to delete the
above line. In other words, the following was required in order to build:

diff --git a/tools/testing/selftests/vm/memfd_secret.c 
b/tools/testing/selftests/vm/memfd_secret.c
index 79578dfd13e6..c878c2b841fc 100644
--- a/tools/testing/selftests/vm/memfd_secret.c
+++ b/tools/testing/selftests/vm/memfd_secret.c
@@ -29,8 +29,6 @@

 #ifdef __NR_memfd_secret

-#include 
-
 #define PATTERN0x55

 static const int prot = PROT_READ | PROT_WRITE;


...and that makes sense to me, because:

a) secretmem.h is not in the uapi, which this selftests/vm build system
   expects (it runs "make headers_install" for us, which is *not* going
   to pick up items in the kernel include dirs), and

b) There is nothing in secretmem.h that this test uses, anyway! Just these:

bool vma_is_secretmem(struct vm_area_struct *vma);
bool page_is_secretmem(struct page *page);
bool secretmem_active(void);


...or am I just Doing It Wrong? :)

thanks,
--
John Hubbard
NVIDIA


[PATCH v14 10/10] secretmem: test: add basic selftest for memfd_secret(2)

2020-12-02 Thread Mike Rapoport
From: Mike Rapoport 

The test verifies that file descriptor created with memfd_secret does
not allow read/write operations, that secret memory mappings respect
RLIMIT_MEMLOCK and that remote accesses with process_vm_read() and
ptrace() to the secret memory fail.

Signed-off-by: Mike Rapoport 
---
 tools/testing/selftests/vm/.gitignore |   1 +
 tools/testing/selftests/vm/Makefile   |   3 +-
 tools/testing/selftests/vm/memfd_secret.c | 298 ++
 tools/testing/selftests/vm/run_vmtests|  17 ++
 4 files changed, 318 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/vm/memfd_secret.c

diff --git a/tools/testing/selftests/vm/.gitignore 
b/tools/testing/selftests/vm/.gitignore
index 9a35c3f6a557..c8deddc81e7a 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -21,4 +21,5 @@ va_128TBswitch
 map_fixed_noreplace
 write_to_hugetlbfs
 hmm-tests
+memfd_secret
 local_config.*
diff --git a/tools/testing/selftests/vm/Makefile 
b/tools/testing/selftests/vm/Makefile
index 62fb15f286ee..9ab98946fbf2 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -34,6 +34,7 @@ TEST_GEN_FILES += khugepaged
 TEST_GEN_FILES += map_fixed_noreplace
 TEST_GEN_FILES += map_hugetlb
 TEST_GEN_FILES += map_populate
+TEST_GEN_FILES += memfd_secret
 TEST_GEN_FILES += mlock-random-test
 TEST_GEN_FILES += mlock2-tests
 TEST_GEN_FILES += mremap_dontunmap
@@ -129,7 +130,7 @@ warn_32bit_failure:
 endif
 endif
 
-$(OUTPUT)/mlock-random-test: LDLIBS += -lcap
+$(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS += -lcap
 
 $(OUTPUT)/gup_test: ../../../../mm/gup_test.h
 
diff --git a/tools/testing/selftests/vm/memfd_secret.c 
b/tools/testing/selftests/vm/memfd_secret.c
new file mode 100644
index ..79578dfd13e6
--- /dev/null
+++ b/tools/testing/selftests/vm/memfd_secret.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corporation, 2020
+ *
+ * Author: Mike Rapoport 
+ */
+
+#define _GNU_SOURCE
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "../kselftest.h"
+
+#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__)
+#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__)
+#define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__)
+
+#ifdef __NR_memfd_secret
+
+#include 
+
+#define PATTERN0x55
+
+static const int prot = PROT_READ | PROT_WRITE;
+static const int mode = MAP_SHARED;
+
+static unsigned long page_size;
+static unsigned long mlock_limit_cur;
+static unsigned long mlock_limit_max;
+
+static int memfd_secret(unsigned long flags)
+{
+   return syscall(__NR_memfd_secret, flags);
+}
+
+static void test_file_apis(int fd)
+{
+   char buf[64];
+
+   if ((read(fd, buf, sizeof(buf)) >= 0) ||
+   (write(fd, buf, sizeof(buf)) >= 0) ||
+   (pread(fd, buf, sizeof(buf), 0) >= 0) ||
+   (pwrite(fd, buf, sizeof(buf), 0) >= 0))
+   fail("unexpected file IO\n");
+   else
+   pass("file IO is blocked as expected\n");
+}
+
+static void test_mlock_limit(int fd)
+{
+   size_t len;
+   char *mem;
+
+   len = mlock_limit_cur;
+   mem = mmap(NULL, len, prot, mode, fd, 0);
+   if (mem == MAP_FAILED) {
+   fail("unable to mmap secret memory\n");
+   return;
+   }
+   munmap(mem, len);
+
+   len = mlock_limit_max * 2;
+   mem = mmap(NULL, len, prot, mode, fd, 0);
+   if (mem != MAP_FAILED) {
+   fail("unexpected mlock limit violation\n");
+   munmap(mem, len);
+   return;
+   }
+
+   pass("mlock limit is respected\n");
+}
+
+static void try_process_vm_read(int fd, int pipefd[2])
+{
+   struct iovec liov, riov;
+   char buf[64];
+   char *mem;
+
+   if (read(pipefd[0], , sizeof(mem)) < 0) {
+   fail("pipe write: %s\n", strerror(errno));
+   exit(KSFT_FAIL);
+   }
+
+   liov.iov_len = riov.iov_len = sizeof(buf);
+   liov.iov_base = buf;
+   riov.iov_base = mem;
+
+   if (process_vm_readv(getppid(), , 1, , 1, 0) < 0) {
+   if (errno == ENOSYS)
+   exit(KSFT_SKIP);
+   exit(KSFT_PASS);
+   }
+
+   exit(KSFT_FAIL);
+}
+
+static void try_ptrace(int fd, int pipefd[2])
+{
+   pid_t ppid = getppid();
+   int status;
+   char *mem;
+   long ret;
+
+   if (read(pipefd[0], , sizeof(mem)) < 0) {
+   perror("pipe write");
+   exit(KSFT_FAIL);
+   }
+
+   ret = ptrace(PTRACE_ATTACH, ppid, 0, 0);
+   if (ret) {
+   perror("ptrace_attach");
+   exit(KSFT_FAIL);
+   }
+
+   ret = waitpid(ppid, , WUNTRACED);
+   if ((ret != ppid) || !(WIFSTOPPED(status))) {
+   fprintf(stderr, "weird