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

Commit 5586cf61 authored by Ram Pai's avatar Ram Pai Committed by Michael Ellerman
Browse files

powerpc: introduce execute-only pkey



This patch provides the implementation of execute-only pkey.
The architecture-independent layer expects the arch-dependent
layer, to support the ability to create and enable a special
key which has execute-only permission.

Acked-by: default avatarBalbir Singh <bsingharora@gmail.com>
Signed-off-by: default avatarRam Pai <linuxram@us.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 06bb53b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ typedef struct {
	 * bit unset -> key available for allocation
	 */
	u32 pkey_allocation_map;
	s16 execute_only_pkey; /* key holding execute-only protection */
#endif
} mm_context_t;

+5 −1
Original line number Diff line number Diff line
@@ -117,9 +117,13 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 * Try to dedicate one of the protection keys to be used as an
 * execute-only protection key.
 */
extern int __execute_only_pkey(struct mm_struct *mm);
static inline int execute_only_pkey(struct mm_struct *mm)
{
	return 0;
	if (static_branch_likely(&pkey_disabled))
		return -1;

	return __execute_only_pkey(mm);
}

static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
+58 −0
Original line number Diff line number Diff line
@@ -92,6 +92,8 @@ void pkey_mm_init(struct mm_struct *mm)
	if (static_branch_likely(&pkey_disabled))
		return;
	mm_pkey_allocation_map(mm) = initial_allocation_mask;
	/* -1 means unallocated or invalid */
	mm->context.execute_only_pkey = -1;
}

static inline u64 read_amr(void)
@@ -256,3 +258,59 @@ void thread_pkey_regs_init(struct thread_struct *thread)
	write_iamr(read_iamr() & pkey_iamr_mask);
	write_uamor(read_uamor() & pkey_amr_uamor_mask);
}

static inline bool pkey_allows_readwrite(int pkey)
{
	int pkey_shift = pkeyshift(pkey);

	if (!is_pkey_enabled(pkey))
		return true;

	return !(read_amr() & ((AMR_RD_BIT|AMR_WR_BIT) << pkey_shift));
}

int __execute_only_pkey(struct mm_struct *mm)
{
	bool need_to_set_mm_pkey = false;
	int execute_only_pkey = mm->context.execute_only_pkey;
	int ret;

	/* Do we need to assign a pkey for mm's execute-only maps? */
	if (execute_only_pkey == -1) {
		/* Go allocate one to use, which might fail */
		execute_only_pkey = mm_pkey_alloc(mm);
		if (execute_only_pkey < 0)
			return -1;
		need_to_set_mm_pkey = true;
	}

	/*
	 * We do not want to go through the relatively costly dance to set AMR
	 * if we do not need to. Check it first and assume that if the
	 * execute-only pkey is readwrite-disabled than we do not have to set it
	 * ourselves.
	 */
	if (!need_to_set_mm_pkey && !pkey_allows_readwrite(execute_only_pkey))
		return execute_only_pkey;

	/*
	 * Set up AMR so that it denies access for everything other than
	 * execution.
	 */
	ret = __arch_set_user_pkey_access(current, execute_only_pkey,
					  PKEY_DISABLE_ACCESS |
					  PKEY_DISABLE_WRITE);
	/*
	 * If the AMR-set operation failed somehow, just return 0 and
	 * effectively disable execute-only support.
	 */
	if (ret) {
		mm_pkey_free(mm, execute_only_pkey);
		return -1;
	}

	/* We got one, store it and use it from here on out */
	if (need_to_set_mm_pkey)
		mm->context.execute_only_pkey = execute_only_pkey;
	return execute_only_pkey;
}