diff mbox series

[1/1] pkey01: Add .test_variants

Message ID 20240807090043.229889-1-pvorel@suse.cz
State Rejected
Headers show
Series [1/1] pkey01: Add .test_variants | expand

Commit Message

Petr Vorel Aug. 7, 2024, 9 a.m. UTC
Test both pkey_{alloc,mprotect() raw syscall and libc wrapper.

Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
Hi,

not sure if testing libc wrappers makes ATM sense, because (if I read
glibc code correctly), there is only pkey_mprotect() very thin wrapper
in sysdeps/unix/sysv/linux/pkey_mprotect.c [1]:

int
pkey_mprotect (void *addr, size_t len, int prot, int pkey)
{
  if (pkey == -1)
    /* If the key is -1, the system call is precisely equivalent to
       mprotect.  */
    return __mprotect (addr, len, prot);
  return INLINE_SYSCALL_CALL (pkey_mprotect, addr, len, prot, pkey);
}

pkey_alloc() and others [2]:

	This adds system call wrappers for pkey_alloc, pkey_free, pkey_mprotect,
	and x86-64 implementations of pkey_get and pkey_set, which abstract over
	the PKRU CPU register and hide the actual number of memory protection
	keys supported by the CPU.  pkey_mprotect with a -1 key is implemented
	using mprotect, so it will work even if the kernel does not support the
	pkey_mprotect system call.

	The system call wrapers use unsigned int instead of unsigned long for
	parameters, so that no special treatment for x32 is needed.  The flags
	argument is currently unused, and the access rights bit mask is limited
	to two bits by the current PKRU register layout anyway.

Besides, something like SYSCALL_VARIANT could be added to include/tst_test_macros.h,
to be reused.

Kind regards,
Petr

[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/pkey_mprotect.c;h=b7afa7946d016ddaa8d4dea5b000dfb04b45491e;hb=c2a05c99e34539d16ebf2bb6234c8d2f2fdaa1f9
[2] https://sourceware.org/git/?p=glibc.git;a=commit;h=446d22e91d3113be57a4b0d1151cf337458c3bec

 testcases/kernel/syscalls/pkeys/pkey01.c | 43 +++++++++++++++++++-----
 1 file changed, 34 insertions(+), 9 deletions(-)

Comments

Li Wang Aug. 8, 2024, 7 a.m. UTC | #1
Hi Petr,


Petr Vorel <pvorel@suse.cz> wrote:

not sure if testing libc wrappers makes ATM sense, because (if I read
> glibc code correctly), there is only pkey_mprotect() very thin wrapper
> in sysdeps/unix/sysv/linux/pkey_mprotect.c [1]:
>

Yep, seems pkey_* series wrapper is uncompleted in glibc so far.
I also hesitating to add the variant in LTP test at this moment.

Let's hear other's opinions.

Btw, I additionally add a new test for PKEY_DISABLE_EXECUTE in
separate patch[1], but considering may your patch may be delayed, I
haven't rebase the code from yours.

[1] https://lists.linux.it/pipermail/ltp/2024-August/039719.html



> int
> pkey_mprotect (void *addr, size_t len, int prot, int pkey)
> {
>   if (pkey == -1)
>     /* If the key is -1, the system call is precisely equivalent to
>        mprotect.  */
>     return __mprotect (addr, len, prot);
>   return INLINE_SYSCALL_CALL (pkey_mprotect, addr, len, prot, pkey);
> }
>
> pkey_alloc() and others [2]:
>
>         This adds system call wrappers for pkey_alloc, pkey_free,
> pkey_mprotect,
>         and x86-64 implementations of pkey_get and pkey_set, which
> abstract over
>         the PKRU CPU register and hide the actual number of memory
> protection
>         keys supported by the CPU.  pkey_mprotect with a -1 key is
> implemented
>         using mprotect, so it will work even if the kernel does not
> support the
>         pkey_mprotect system call.
>
>         The system call wrapers use unsigned int instead of unsigned long
> for
>         parameters, so that no special treatment for x32 is needed.  The
> flags
>         argument is currently unused, and the access rights bit mask is
> limited
>         to two bits by the current PKRU register layout anyway.
>
> Besides, something like SYSCALL_VARIANT could be added to
> include/tst_test_macros.h,
>

+1
diff mbox series

Patch

diff --git a/testcases/kernel/syscalls/pkeys/pkey01.c b/testcases/kernel/syscalls/pkeys/pkey01.c
index f1ecfec0bb..52b29b1783 100644
--- a/testcases/kernel/syscalls/pkeys/pkey01.c
+++ b/testcases/kernel/syscalls/pkeys/pkey01.c
@@ -51,11 +51,40 @@  static struct tcase {
 	{0, PKEY_DISABLE_WRITE, "PKEY_DISABLE_WRITE"},
 };
 
+#define PKEY_ALLOC(...) \
+	SYSCALL_VARIANT(TST_EXP_POSITIVE, pkey_alloc, __VA_ARGS__)
+
+#define PKEY_MPROTECT(...) \
+	SYSCALL_VARIANT(TST_EXP_PASS_SILENT, pkey_mprotect, __VA_ARGS__)
+
+#define SYSCALL_VARIANT(TST, SCALL, ...)                                 \
+	({                                                                     \
+		if (tst_variant)                                    \
+			TST(SCALL(__VA_ARGS__));	\
+		else							\
+			TST(tst_syscall(__NR_ ## SCALL, __VA_ARGS__));	\
+		TST_RET;                                                       \
+	})
+
+static void variant_check(void)
+{
+	if (tst_variant) {
+		tst_res(TINFO, "Testing variant: libc pkey_{alloc,mprotect()");
+#ifndef HAVE_PKEY_MPROTECT
+		tst_brk(TCONF, "libc pkey_{alloc,mprotect() wrappers not available");
+#endif
+	} else {
+		tst_res(TINFO, "Testing variant: syscall __NR_pkey_{alloc,mprotect}");
+	}
+
+	check_pkey_support();
+}
+
 static void setup(void)
 {
 	int i, fd;
 
-	check_pkey_support();
+	variant_check();
 
 	if (tst_hugepages == test.hugepages.number)
 		size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
@@ -146,14 +175,10 @@  static void pkey_test(struct tcase *tc, struct mmap_param *mpa)
 		fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0664);
 
 	buffer = SAFE_MMAP(NULL, size, mpa->prot, mpa->flags, fd, 0);
-
-	pkey = pkey_alloc(tc->flags, tc->access_rights);
-	if (pkey == -1)
-		tst_brk(TBROK | TERRNO, "pkey_alloc failed");
+	pkey = PKEY_ALLOC(tc->flags, tc->access_rights);
 
 	tst_res(TINFO, "Set %s on (%s) buffer", tc->name, flag_to_str(mpa->flags));
-	if (pkey_mprotect(buffer, size, mpa->prot, pkey) == -1)
-		tst_brk(TBROK | TERRNO, "pkey_mprotect failed");
+	PKEY_MPROTECT(buffer, size, mpa->prot, pkey);
 
 	pid = SAFE_FORK();
 	if (pid == 0) {
@@ -181,8 +206,7 @@  static void pkey_test(struct tcase *tc, struct mmap_param *mpa)
                 tst_res(TFAIL, "Child: %s", tst_strstatus(status));
 
 	tst_res(TINFO, "Remove %s from the buffer", tc->name);
-	if (pkey_mprotect(buffer, size, mpa->prot, 0x0) == -1)
-		tst_brk(TBROK | TERRNO, "pkey_mprotect failed");
+	PKEY_MPROTECT(buffer, size, mpa->prot, 0x0);
 
 	switch (mpa->prot) {
 	case PROT_READ:
@@ -230,4 +254,5 @@  static struct tst_test test = {
 	.test = verify_pkey,
 	.setup = setup,
 	.hugepages = {1, TST_REQUEST},
+	.test_variants = 2,
 };