This test program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <err.h>
/* Return the value of the AMR register. */
static inline unsigned long int
pkey_read (void)
{
unsigned long int result;
__asm__ volatile ("mfspr %0, 13" : "=r" (result));
return result;
}
/* Overwrite the AMR register with VALUE. */
static inline void
pkey_write (unsigned long int value)
{
__asm__ volatile ("mtspr 13, %0" : : "r" (value));
}
int
main (int argc, char **argv)
{
printf ("AMR (PID %d): 0x%016lx\n", (int) getpid (), pkey_read());
if (argc > 1)
{
int key = syscall (__NR_pkey_alloc, 0, 0);
if (key < 0)
err (1, "pkey_alloc");
printf ("Allocated key (PID %d): %d\n", (int) getpid (), key);
return 0;
}
pid_t pid = fork ();
if (pid == 0)
{
execl ("/proc/self/exe", argv[0], "subprocess", NULL);
_exit (1);
}
if (pid < 0)
err (1, "fork");
int status;
if (waitpid (pid, &status, 0) < 0)
err (1, "waitpid");
int key = syscall (__NR_pkey_alloc, 0, 0);
if (key < 0)
err (1, "pkey_alloc");
printf ("Allocated key (PID %d): %d\n", (int) getpid (), key);
unsigned long int amr = -1;
printf ("Setting AMR: 0x%016lx\n", amr);
pkey_write (amr);
printf ("New AMR value (PID %d, before execl): 0x%016lx\n",
(int) getpid (), pkey_read());
execl ("/proc/self/exe", argv[0], "subprocess", NULL);
err (1, "exec");
return 1;
}
shows that the AMR register value is not reset on execve:
AMR (PID 112291): 0x0000000000000000
AMR (PID 112292): 0x0000000000000000
Allocated key (PID 112292): 2
Allocated key (PID 112291): 2
Setting AMR: 0xffffffffffffffff
New AMR value (PID 112291, before execl): 0x0c00000000000000
AMR (PID 112291): 0x0c00000000000000
Allocated key (PID 112291): 2
I think this is a real bug and needs to be fixed even if the defaults
are kept as-is (see the other thread).
(Seen on 4.17.0-rc5.)
Thanks,
Florian