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

Commit d0dc5d85 authored by Sami Tolvanen's avatar Sami Tolvanen Committed by Alistair Delva
Browse files

ANDROID: cfi: ensure RCU is watching in __cfi_slowpath



Indirect calls can happen when RCU is not watching, so we need to wake
it up again for the CFI shadow and __module_address. As these calls can
happen anywhere, use rcu_nmi_enter() similarly to kernel_text_address(),
and switch to rcu_read_lock_sched() for shadow access.

Bug: 169017431
Change-Id: Iebb857df898e644b4952a62d86fa5ff9852b5711
Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
parent 77bc008d
Loading
Loading
Loading
Loading
+22 −12
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 */

#include <linux/gfp.h>
#include <linux/hardirq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/printk.h>
@@ -246,33 +247,36 @@ static inline cfi_check_fn ptr_to_check_fn(const struct cfi_shadow __rcu *s,

static inline cfi_check_fn find_module_cfi_check(void *ptr)
{
	cfi_check_fn f = CFI_CHECK_FN;
	struct module *mod;

	preempt_disable();
	mod = __module_address((unsigned long)ptr);
	preempt_enable();

	if (mod)
		return mod->cfi_check;
		f = mod->cfi_check;
	preempt_enable();

	return CFI_CHECK_FN;
	return f;
}

static inline cfi_check_fn find_cfi_check(void *ptr)
{
#ifdef CONFIG_CFI_CLANG_SHADOW
	bool rcu;
	cfi_check_fn f;

	if (!rcu_access_pointer(cfi_shadow))
		return CFI_CHECK_FN; /* No loaded modules */
	rcu = rcu_is_watching();
	if (!rcu)
		rcu_nmi_enter();

#ifdef CONFIG_CFI_CLANG_SHADOW
	/* Look up the __cfi_check function to use */
	rcu_read_lock();
	f = ptr_to_check_fn(rcu_dereference(cfi_shadow), (unsigned long)ptr);
	rcu_read_unlock();
	rcu_read_lock_sched();
	f = ptr_to_check_fn(rcu_dereference_sched(cfi_shadow),
			    (unsigned long)ptr);
	rcu_read_unlock_sched();

	if (f)
		return f;
		goto out;

	/*
	 * Fall back to find_module_cfi_check, which works also for a larger
@@ -280,7 +284,13 @@ static inline cfi_check_fn find_cfi_check(void *ptr)
	 */
#endif /* CONFIG_CFI_CLANG_SHADOW */

	return find_module_cfi_check(ptr);
	f = find_module_cfi_check(ptr);

out:
	if (!rcu)
		rcu_nmi_exit();

	return f;
}

void cfi_slowpath_handler(uint64_t id, void *ptr, void *diag)