2023-06-30 03:19:49

by Jeff Xu

[permalink] [raw]
Subject: [PATCH v1 0/2] mm/memfd: fix sysctl MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

From: Jeff Xu <[email protected]>

When sysctl vm.memfd_noexec is 2 (MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED),
memfd_create(.., MFD_EXEC) should fail.

This complies with how MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED is
defined - "memfd_create() without MFD_NOEXEC_SEAL will be rejected"

Thanks to Dominique Martinet <[email protected]> who reported the bug.
see [1] for context.

[1] https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/

Jeff Xu (2):
mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
selftests/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

mm/memfd.c | 48 +++++++++++-----------
tools/testing/selftests/memfd/memfd_test.c | 5 +++
2 files changed, 30 insertions(+), 23 deletions(-)

--
2.41.0.255.g8b1d071c50-goog



2023-06-30 03:20:53

by Jeff Xu

[permalink] [raw]
Subject: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

From: Jeff Xu <[email protected]>

When vm.memfd_noexec is 2 (MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED),
memfd_create(.., MFD_EXEC) should fail.

This complies with how MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED is
defined - "memfd_create() without MFD_NOEXEC_SEAL will be rejected"

Link:https://lore.kernel.org/linux-mm/CABi2SkXUX_QqTQ10Yx9bBUGpN1wByOi_=gZU6WEy5a8MaQY3Jw@mail.gmail.com/T/
Fixes: 105ff5339f49 ("mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC")
Reported-by: Dominique Martinet <[email protected]>
Signed-off-by: Jeff Xu <[email protected]>
---
mm/memfd.c | 48 +++++++++++++++++++++++++-----------------------
1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/mm/memfd.c b/mm/memfd.c
index e763e76f1106..812750298e8a 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -268,6 +268,19 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg)

#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | MFD_NOEXEC_SEAL | MFD_EXEC)

+static int sysctl_memfd_noexec(void)
+{
+ int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
+#ifdef CONFIG_SYSCTL
+ struct pid_namespace *ns;
+
+ ns = task_active_pid_ns(current);
+ if (ns)
+ sysctl = ns->memfd_noexec_scope;
+#endif
+ return sysctl;
+}
+
SYSCALL_DEFINE2(memfd_create,
const char __user *, uname,
unsigned int, flags)
@@ -278,6 +291,7 @@ SYSCALL_DEFINE2(memfd_create,
int fd, error;
char *name;
long len;
+ int sysctl = sysctl_memfd_noexec();

if (!(flags & MFD_HUGETLB)) {
if (flags & ~(unsigned int)MFD_ALL_FLAGS)
@@ -294,35 +308,23 @@ SYSCALL_DEFINE2(memfd_create,
return -EINVAL;

if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
-#ifdef CONFIG_SYSCTL
- int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
- struct pid_namespace *ns;
-
- ns = task_active_pid_ns(current);
- if (ns)
- sysctl = ns->memfd_noexec_scope;
-
- switch (sysctl) {
- case MEMFD_NOEXEC_SCOPE_EXEC:
- flags |= MFD_EXEC;
- break;
- case MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL:
+ if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
flags |= MFD_NOEXEC_SEAL;
- break;
- default:
- pr_warn_once(
- "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n",
- task_pid_nr(current), get_task_comm(comm, current));
- return -EINVAL;
- }
-#else
- flags |= MFD_EXEC;
-#endif
+ else
+ flags |= MFD_EXEC;
+
pr_warn_once(
"memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
task_pid_nr(current), get_task_comm(comm, current));
}

+ if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
+ pr_warn_once(
+ "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n",
+ task_pid_nr(current), get_task_comm(comm, current));
+ return -EACCES;
+ }
+
/* length includes terminating zero */
len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
if (len <= 0)
--
2.41.0.255.g8b1d071c50-goog


2023-06-30 03:27:26

by Jeff Xu

[permalink] [raw]
Subject: [PATCH v1 2/2] selftests/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

From: Jeff Xu <[email protected]>

Add selftest for sysctl vm.memfd_noexec is 2
(MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED)

memfd_create(.., MFD_EXEC) should fail in this case.

Signed-off-by: Jeff Xu <[email protected]>
---
tools/testing/selftests/memfd/memfd_test.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
index dba0e8ba002f..dbdd9ec5e397 100644
--- a/tools/testing/selftests/memfd/memfd_test.c
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -1147,6 +1147,11 @@ static void test_sysctl_child(void)
sysctl_assert_write("2");
mfd_fail_new("kern_memfd_sysctl_2",
MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_fail_new("kern_memfd_sysctl_2_MFD_EXEC",
+ MFD_CLOEXEC | MFD_EXEC);
+ fd = mfd_assert_new("", 0, MFD_NOEXEC_SEAL);
+ close(fd);
+
sysctl_fail_write("0");
sysctl_fail_write("1");
}
--
2.41.0.255.g8b1d071c50-goog


2023-06-30 05:53:43

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]

url: https://github.com/intel-lab-lkp/linux/commits/jeffxu-chromium-org/mm-memfd-sysctl-fix-MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED/20230630-111827
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20230630031721.623955-2-jeffxu%40google.com
patch subject: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
config: microblaze-randconfig-r003-20230630 (https://download.01.org/0day-ci/archive/20230630/[email protected]/config)
compiler: microblaze-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230630/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

mm/memfd.c: In function 'sysctl_memfd_noexec':
>> mm/memfd.c:273:22: error: 'MEMFD_NOEXEC_SCOPE_EXEC' undeclared (first use in this function)
273 | int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
| ^~~~~~~~~~~~~~~~~~~~~~~
mm/memfd.c:273:22: note: each undeclared identifier is reported only once for each function it appears in
mm/memfd.c: In function '__do_sys_memfd_create':
>> mm/memfd.c:311:31: error: 'MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL' undeclared (first use in this function)
311 | if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> mm/memfd.c:321:43: error: 'MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED' undeclared (first use in this function)
321 | if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/MEMFD_NOEXEC_SCOPE_EXEC +273 mm/memfd.c

270
271 static int sysctl_memfd_noexec(void)
272 {
> 273 int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
274 #ifdef CONFIG_SYSCTL
275 struct pid_namespace *ns;
276
277 ns = task_active_pid_ns(current);
278 if (ns)
279 sysctl = ns->memfd_noexec_scope;
280 #endif
281 return sysctl;
282 }
283
284 SYSCALL_DEFINE2(memfd_create,
285 const char __user *, uname,
286 unsigned int, flags)
287 {
288 char comm[TASK_COMM_LEN];
289 unsigned int *file_seals;
290 struct file *file;
291 int fd, error;
292 char *name;
293 long len;
294 int sysctl = sysctl_memfd_noexec();
295
296 if (!(flags & MFD_HUGETLB)) {
297 if (flags & ~(unsigned int)MFD_ALL_FLAGS)
298 return -EINVAL;
299 } else {
300 /* Allow huge page size encoding in flags. */
301 if (flags & ~(unsigned int)(MFD_ALL_FLAGS |
302 (MFD_HUGE_MASK << MFD_HUGE_SHIFT)))
303 return -EINVAL;
304 }
305
306 /* Invalid if both EXEC and NOEXEC_SEAL are set.*/
307 if ((flags & MFD_EXEC) && (flags & MFD_NOEXEC_SEAL))
308 return -EINVAL;
309
310 if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
> 311 if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
312 flags |= MFD_NOEXEC_SEAL;
313 else
314 flags |= MFD_EXEC;
315
316 pr_warn_once(
317 "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
318 task_pid_nr(current), get_task_comm(comm, current));
319 }
320
> 321 if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-06-30 06:58:28

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]

url: https://github.com/intel-lab-lkp/linux/commits/jeffxu-chromium-org/mm-memfd-sysctl-fix-MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED/20230630-111827
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20230630031721.623955-2-jeffxu%40google.com
patch subject: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
config: riscv-randconfig-r042-20230630 (https://download.01.org/0day-ci/archive/20230630/[email protected]/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230630/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> mm/memfd.c:273:15: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_EXEC'
273 | int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
| ^
>> mm/memfd.c:311:17: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL'
311 | if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
| ^
>> mm/memfd.c:321:36: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED'
321 | if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
| ^
3 errors generated.


vim +/MEMFD_NOEXEC_SCOPE_EXEC +273 mm/memfd.c

270
271 static int sysctl_memfd_noexec(void)
272 {
> 273 int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
274 #ifdef CONFIG_SYSCTL
275 struct pid_namespace *ns;
276
277 ns = task_active_pid_ns(current);
278 if (ns)
279 sysctl = ns->memfd_noexec_scope;
280 #endif
281 return sysctl;
282 }
283
284 SYSCALL_DEFINE2(memfd_create,
285 const char __user *, uname,
286 unsigned int, flags)
287 {
288 char comm[TASK_COMM_LEN];
289 unsigned int *file_seals;
290 struct file *file;
291 int fd, error;
292 char *name;
293 long len;
294 int sysctl = sysctl_memfd_noexec();
295
296 if (!(flags & MFD_HUGETLB)) {
297 if (flags & ~(unsigned int)MFD_ALL_FLAGS)
298 return -EINVAL;
299 } else {
300 /* Allow huge page size encoding in flags. */
301 if (flags & ~(unsigned int)(MFD_ALL_FLAGS |
302 (MFD_HUGE_MASK << MFD_HUGE_SHIFT)))
303 return -EINVAL;
304 }
305
306 /* Invalid if both EXEC and NOEXEC_SEAL are set.*/
307 if ((flags & MFD_EXEC) && (flags & MFD_NOEXEC_SEAL))
308 return -EINVAL;
309
310 if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
> 311 if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
312 flags |= MFD_NOEXEC_SEAL;
313 else
314 flags |= MFD_EXEC;
315
316 pr_warn_once(
317 "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
318 task_pid_nr(current), get_task_comm(comm, current));
319 }
320
> 321 if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-06-30 06:59:20

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]

url: https://github.com/intel-lab-lkp/linux/commits/jeffxu-chromium-org/mm-memfd-sysctl-fix-MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED/20230630-111827
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20230630031721.623955-2-jeffxu%40google.com
patch subject: [PATCH v1 1/2] mm/memfd: sysctl: fix MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
config: hexagon-randconfig-r005-20230630 (https://download.01.org/0day-ci/archive/20230630/[email protected]/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230630/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from mm/memfd.c:12:
In file included from include/linux/pagemap.h:11:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
547 | val = __raw_readb(PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
| ^
In file included from mm/memfd.c:12:
In file included from include/linux/pagemap.h:11:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
| ^
In file included from mm/memfd.c:12:
In file included from include/linux/pagemap.h:11:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
584 | __raw_writeb(value, PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
>> mm/memfd.c:273:15: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_EXEC'
273 | int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
| ^
>> mm/memfd.c:311:17: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL'
311 | if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
| ^
>> mm/memfd.c:321:36: error: use of undeclared identifier 'MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED'
321 | if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {
| ^
6 warnings and 3 errors generated.


vim +/MEMFD_NOEXEC_SCOPE_EXEC +273 mm/memfd.c

270
271 static int sysctl_memfd_noexec(void)
272 {
> 273 int sysctl = MEMFD_NOEXEC_SCOPE_EXEC;
274 #ifdef CONFIG_SYSCTL
275 struct pid_namespace *ns;
276
277 ns = task_active_pid_ns(current);
278 if (ns)
279 sysctl = ns->memfd_noexec_scope;
280 #endif
281 return sysctl;
282 }
283
284 SYSCALL_DEFINE2(memfd_create,
285 const char __user *, uname,
286 unsigned int, flags)
287 {
288 char comm[TASK_COMM_LEN];
289 unsigned int *file_seals;
290 struct file *file;
291 int fd, error;
292 char *name;
293 long len;
294 int sysctl = sysctl_memfd_noexec();
295
296 if (!(flags & MFD_HUGETLB)) {
297 if (flags & ~(unsigned int)MFD_ALL_FLAGS)
298 return -EINVAL;
299 } else {
300 /* Allow huge page size encoding in flags. */
301 if (flags & ~(unsigned int)(MFD_ALL_FLAGS |
302 (MFD_HUGE_MASK << MFD_HUGE_SHIFT)))
303 return -EINVAL;
304 }
305
306 /* Invalid if both EXEC and NOEXEC_SEAL are set.*/
307 if ((flags & MFD_EXEC) && (flags & MFD_NOEXEC_SEAL))
308 return -EINVAL;
309
310 if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) {
> 311 if (sysctl == MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL)
312 flags |= MFD_NOEXEC_SEAL;
313 else
314 flags |= MFD_EXEC;
315
316 pr_warn_once(
317 "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n",
318 task_pid_nr(current), get_task_comm(comm, current));
319 }
320
> 321 if (flags & MFD_EXEC && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) {

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki