Skip to content

Commit

Permalink
powerpc/ptrace: Add memory protection key regset
Browse files Browse the repository at this point in the history
The AMR/IAMR/UAMOR are part of the program context.
Allow it to be accessed via ptrace and through core files.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
  • Loading branch information
Thiago Jung Bauermann authored and Michael Ellerman committed Jan 20, 2018
1 parent 99cd130 commit c5cc1f4
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
5 changes: 5 additions & 0 deletions arch/powerpc/include/asm/pkeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
return __arch_set_user_pkey_access(tsk, pkey, init_val);
}

static inline bool arch_pkeys_enabled(void)
{
return !static_branch_likely(&pkey_disabled);
}

extern void pkey_mm_init(struct mm_struct *mm);
extern void thread_pkey_regs_save(struct thread_struct *thread);
extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/include/uapi/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
#define ELF_NTMSPRREG 3 /* include tfhar, tfiar, texasr */
#define ELF_NEBB 3 /* includes ebbrr, ebbhr, bescr */
#define ELF_NPMU 5 /* includes siar, sdar, sier, mmcr2, mmcr0 */
#define ELF_NPKEY 3 /* includes amr, iamr, uamor */

typedef unsigned long elf_greg_t64;
typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
Expand Down
66 changes: 66 additions & 0 deletions arch/powerpc/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/context_tracking.h>

#include <linux/uaccess.h>
#include <linux/pkeys.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/switch_to.h>
Expand Down Expand Up @@ -1787,6 +1788,61 @@ static int pmu_set(struct task_struct *target,
return ret;
}
#endif

#ifdef CONFIG_PPC_MEM_KEYS
static int pkey_active(struct task_struct *target,
const struct user_regset *regset)
{
if (!arch_pkeys_enabled())
return -ENODEV;

return regset->n;
}

static int pkey_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr));
BUILD_BUG_ON(TSO(iamr) + sizeof(unsigned long) != TSO(uamor));

if (!arch_pkeys_enabled())
return -ENODEV;

return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.amr, 0,
ELF_NPKEY * sizeof(unsigned long));
}

static int pkey_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
u64 new_amr;
int ret;

if (!arch_pkeys_enabled())
return -ENODEV;

/* Only the AMR can be set from userspace */
if (pos != 0 || count != sizeof(new_amr))
return -EINVAL;

ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&new_amr, 0, sizeof(new_amr));
if (ret)
return ret;

/* UAMOR determines which bits of the AMR can be set from userspace. */
target->thread.amr = (new_amr & target->thread.uamor) |
(target->thread.amr & ~target->thread.uamor);

return 0;
}
#endif /* CONFIG_PPC_MEM_KEYS */

/*
* These are our native regset flavors.
*/
Expand Down Expand Up @@ -1821,6 +1877,9 @@ enum powerpc_regset {
REGSET_EBB, /* EBB registers */
REGSET_PMR, /* Performance Monitor Registers */
#endif
#ifdef CONFIG_PPC_MEM_KEYS
REGSET_PKEY, /* AMR register */
#endif
};

static const struct user_regset native_regsets[] = {
Expand Down Expand Up @@ -1926,6 +1985,13 @@ static const struct user_regset native_regsets[] = {
.active = pmu_active, .get = pmu_get, .set = pmu_set
},
#endif
#ifdef CONFIG_PPC_MEM_KEYS
[REGSET_PKEY] = {
.core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,
.size = sizeof(u64), .align = sizeof(u64),
.active = pkey_active, .get = pkey_get, .set = pkey_set
},
#endif
};

static const struct user_regset_view user_ppc_native_view = {
Expand Down
7 changes: 7 additions & 0 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,13 @@ void _exception_pkey(int signr, struct pt_regs *regs, int code,
local_irq_enable();

current->thread.trap_nr = code;

/*
* Save all the pkey registers AMR/IAMR/UAMOR. Eg: Core dumps need
* to capture the content, if the task gets killed.
*/
thread_pkey_regs_save(&current->thread);

memset(&info, 0, sizeof(info));
info.si_signo = signr;
info.si_code = code;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ typedef struct elf64_shdr {
#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */
#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */
#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */
#define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
Expand Down

0 comments on commit c5cc1f4

Please sign in to comment.