Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5cc1f4d authored by Thiago Jung Bauermann's avatar Thiago Jung Bauermann Committed by Michael Ellerman
Browse files

powerpc/ptrace: Add memory protection key regset



The AMR/IAMR/UAMOR are part of the program context.
Allow it to be accessed via ptrace and through core files.

Signed-off-by: default avatarRam Pai <linuxram@us.ibm.com>
Signed-off-by: default avatarThiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 99cd1302
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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];
+66 −0
Original line number Diff line number Diff line
@@ -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>
@@ -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.
 */
@@ -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[] = {
@@ -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 = {
+7 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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 */