linux-stable/arch/powerpc
Aneesh Kumar K.V 62c1cf71a2 powerpc/book3s64/pkeys: Fix pkey_access_permitted() for execute disable pkey
commit 192b6a7805 upstream.

Even if the IAMR value denies execute access, the current code returns
true from pkey_access_permitted() for an execute permission check, if
the AMR read pkey bit is cleared.

This results in repeated page fault loop with a test like below:

  #define _GNU_SOURCE
  #include <errno.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <signal.h>
  #include <inttypes.h>

  #include <assert.h>
  #include <malloc.h>
  #include <unistd.h>
  #include <pthread.h>
  #include <sys/mman.h>

  #ifdef SYS_pkey_mprotect
  #undef SYS_pkey_mprotect
  #endif

  #ifdef SYS_pkey_alloc
  #undef SYS_pkey_alloc
  #endif

  #ifdef SYS_pkey_free
  #undef SYS_pkey_free
  #endif

  #undef PKEY_DISABLE_EXECUTE
  #define PKEY_DISABLE_EXECUTE	0x4

  #define SYS_pkey_mprotect	386
  #define SYS_pkey_alloc		384
  #define SYS_pkey_free		385

  #define PPC_INST_NOP		0x60000000
  #define PPC_INST_BLR		0x4e800020
  #define PROT_RWX		(PROT_READ | PROT_WRITE | PROT_EXEC)

  static int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
  {
  	return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
  }

  static int sys_pkey_alloc(unsigned long flags, unsigned long access_rights)
  {
  	return syscall(SYS_pkey_alloc, flags, access_rights);
  }

  static int sys_pkey_free(int pkey)
  {
  	return syscall(SYS_pkey_free, pkey);
  }

  static void do_execute(void *region)
  {
  	/* jump to region */
  	asm volatile(
  		"mtctr	%0;"
  		"bctrl"
  		: : "r"(region) : "ctr", "lr");
  }

  static void do_protect(void *region)
  {
  	size_t pgsize;
  	int i, pkey;

  	pgsize = getpagesize();

  	pkey = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
  	assert (pkey > 0);

  	/* perform mprotect */
  	assert(!sys_pkey_mprotect(region, pgsize, PROT_RWX, pkey));
  	do_execute(region);

  	/* free pkey */
  	assert(!sys_pkey_free(pkey));

  }

  int main(int argc, char **argv)
  {
  	size_t pgsize, numinsns;
  	unsigned int *region;
  	int i;

  	/* allocate memory region to protect */
  	pgsize = getpagesize();
  	region = memalign(pgsize, pgsize);
  	assert(region != NULL);
  	assert(!mprotect(region, pgsize, PROT_RWX));

  	/* fill page with NOPs with a BLR at the end */
  	numinsns = pgsize / sizeof(region[0]);
  	for (i = 0; i < numinsns - 1; i++)
  		region[i] = PPC_INST_NOP;
  	region[i] = PPC_INST_BLR;

  	do_protect(region);

  	return EXIT_SUCCESS;
  }

The fix is to only check the IAMR for an execute check, the AMR value
is not relevant.

Fixes: f2407ef3ba ("powerpc: helper to validate key-access permissions of a pte")
Cc: stable@vger.kernel.org # v4.16+
Reported-by: Sandipan Das <sandipan@linux.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
[mpe: Add detail to change log, tweak wording & formatting]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200712132047.1038594-1-aneesh.kumar@linux.ibm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-07-22 09:32:11 +02:00
..
boot powerpc/44x: Adjust indentation in ibm4xx_denali_fixup_memsize 2020-02-11 04:34:12 -08:00
configs scsi: sr: remove references to BLK_DEV_SR_VENDOR, leave it enabled 2020-07-22 09:32:04 +02:00
crypto powerpc updates for 4.19 2018-08-17 11:32:50 -07:00
include powerpc/64s/pgtable: fix an undefined behaviour 2020-06-25 15:32:58 +02:00
kernel powerpc/64: Don't initialise init_task->thread.regs 2020-06-25 15:32:56 +02:00
kvm KVM: PPC: Book3S HV: Ignore kmemleak false positives 2020-06-25 15:33:00 +02:00
lib powerpc/64: Fix memcmp reading past the end of src/dest 2019-04-03 06:26:29 +02:00
math-emu
mm powerpc/book3s64/pkeys: Fix pkey_access_permitted() for execute disable pkey 2020-07-22 09:32:11 +02:00
net powerpc/bpf: Fix tail call implementation 2019-12-05 09:19:39 +01:00
oprofile treewide: kzalloc() -> kcalloc() 2018-06-12 16:19:22 -07:00
perf powerpc/perf/hv-24x7: Fix inconsistent output values incase multiple hv-24x7 events run 2020-06-25 15:32:50 +02:00
platforms powerpc/4xx: Don't unmap NULL mbase 2020-06-25 15:33:00 +02:00
purgatory powerpc updates for 4.19 2018-08-17 11:32:50 -07:00
sysdev powerpc/xive: Clear the page tables for the ESB IO mapping 2020-06-22 09:05:00 +02:00
tools powerpc/tools: Don't quote $objdump in scripts 2020-01-04 19:12:42 +01:00
xmon powerpc: Make setjmp/longjmp signature standard 2020-04-17 10:48:54 +02:00
Kconfig powerpc/64s: Disable STRICT_KERNEL_RWX 2020-05-27 17:37:38 +02:00
Kconfig.debug Kconfig: consolidate the "Kernel hacking" menu 2018-08-02 08:06:48 +09:00
Makefile powerpc: vdso: Make vdso32 installation conditional in vdso_install 2020-01-27 14:50:40 +01:00
Makefile.postlink