powerpc/pkeys: key allocation/deallocation must not change pkey registers
authorRam Pai <linuxram@us.ibm.com>
Tue, 17 Jul 2018 13:51:04 +0000 (06:51 -0700)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 24 Jul 2018 11:34:08 +0000 (21:34 +1000)
Key allocation and deallocation has the side effect of programming the
UAMOR/AMR/IAMR registers. This is wrong, since its the responsibility of
the application and not that of the kernel, to modify the permission on
the key.

Do not modify the pkey registers at key allocation/deallocation.

This patch also fixes a bug where a sys_pkey_free() resets the UAMOR
bits of the key, thus making its permissions unmodifiable from user
space. Later if the same key gets reallocated from a different thread
this thread will no longer be able to change the permissions on the key.

Fixes: cf43d3b26452 ("powerpc: Enable pkey subsystem")
Cc: stable@vger.kernel.org # v4.16+
Reviewed-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/pkeys.h
arch/powerpc/mm/pkeys.c

index 5ba80cffb505413db4c1b1496d8ec04e5a465c2e..3312606fda07b0b73100eaa83cd3c0345283450d 100644 (file)
@@ -94,8 +94,6 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
                __mm_pkey_is_allocated(mm, pkey));
 }
 
-extern void __arch_activate_pkey(int pkey);
-extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  * Relies on the mmap_sem to protect against concurrency in mm_pkey_alloc() and
@@ -124,11 +122,6 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
        ret = ffz((u32)mm_pkey_allocation_map(mm));
        __mm_pkey_allocated(mm, ret);
 
-       /*
-        * Enable the key in the hardware
-        */
-       if (ret > 0)
-               __arch_activate_pkey(ret);
        return ret;
 }
 
@@ -140,10 +133,6 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
        if (!mm_pkey_is_allocated(mm, pkey))
                return -EINVAL;
 
-       /*
-        * Disable the key in the hardware
-        */
-       __arch_deactivate_pkey(pkey);
        __mm_pkey_free(mm, pkey);
 
        return 0;
index 98180f49ac5ef556e02de4e80dcc1eabee2e3872..8f0052b15b8411a632dc0067fc82ab305f64cec4 100644 (file)
@@ -218,33 +218,6 @@ static inline void init_iamr(int pkey, u8 init_bits)
        write_iamr(old_iamr | new_iamr_bits);
 }
 
-static void pkey_status_change(int pkey, bool enable)
-{
-       u64 old_uamor;
-
-       /* Reset the AMR and IAMR bits for this key */
-       init_amr(pkey, 0x0);
-       init_iamr(pkey, 0x0);
-
-       /* Enable/disable key */
-       old_uamor = read_uamor();
-       if (enable)
-               old_uamor |= (0x3ul << pkeyshift(pkey));
-       else
-               old_uamor &= ~(0x3ul << pkeyshift(pkey));
-       write_uamor(old_uamor);
-}
-
-void __arch_activate_pkey(int pkey)
-{
-       pkey_status_change(pkey, true);
-}
-
-void __arch_deactivate_pkey(int pkey)
-{
-       pkey_status_change(pkey, false);
-}
-
 /*
  * Set the access rights in AMR IAMR and UAMOR registers for @pkey to that
  * specified in @init_val.