Commit f17fb26d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull arm64 fixes from Will Deacon:
 "Three arm64 fixes.

  The main one is a fix to the way in which we evaluate the macro
  arguments to our uaccess routines, which we _think_ might be the root
  cause behind some unkillable tasks we've seen in the Android arm64 CI
  farm (testing is ongoing). In any case, it's worth fixing.

  Other than that, we've toned down an over-zealous VM_BUG_ON() and
  fixed ftrace stack unwinding in a bunch of cases.

  Summary:

   - Evaluate uaccess macro arguments outside of the critical section

   - Tighten up VM_BUG_ON() in pmd_populate_kernel() to avoid false positive

   - Fix ftrace stack unwinding using HAVE_FUNCTION_GRAPH_RET_ADDR_PTR"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: uaccess: avoid blocking within critical sections
  arm64: mm: Fix VM_BUG_ON(mm != &init_mm) for trans_pgd
  arm64: ftrace: use HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
parents a4849f60 94902d84
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -12,6 +12,17 @@

#define HAVE_FUNCTION_GRAPH_FP_TEST

/*
 * HAVE_FUNCTION_GRAPH_RET_ADDR_PTR means that the architecture can provide a
 * "return address pointer" which can be used to uniquely identify a return
 * address which has been overwritten.
 *
 * On arm64 we use the address of the caller's frame record, which remains the
 * same for the lifetime of the instrumented function, unlike the return
 * address in the LR.
 */
#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR

#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
#define ARCH_SUPPORTS_FTRACE_OPS 1
#else
+1 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
static inline void
pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
{
	VM_BUG_ON(mm != &init_mm);
	VM_BUG_ON(mm && mm != &init_mm);
	__pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE | PMD_TABLE_UXN);
}

+0 −6
Original line number Diff line number Diff line
@@ -47,9 +47,6 @@ struct stack_info {
 * @prev_type:   The type of stack this frame record was on, or a synthetic
 *               value of STACK_TYPE_UNKNOWN. This is used to detect a
 *               transition from one stack to another.
 *
 * @graph:       When FUNCTION_GRAPH_TRACER is selected, holds the index of a
 *               replacement lr value in the ftrace graph stack.
 */
struct stackframe {
	unsigned long fp;
@@ -57,9 +54,6 @@ struct stackframe {
	DECLARE_BITMAP(stacks_done, __NR_STACK_TYPES);
	unsigned long prev_fp;
	enum stack_type prev_type;
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	int graph;
#endif
#ifdef CONFIG_KRETPROBES
	struct llist_node *kr_cur;
#endif
+41 −7
Original line number Diff line number Diff line
@@ -281,12 +281,22 @@ do { \
	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
} while (0)

/*
 * We must not call into the scheduler between uaccess_ttbr0_enable() and
 * uaccess_ttbr0_disable(). As `x` and `ptr` could contain blocking functions,
 * we must evaluate these outside of the critical section.
 */
#define __raw_get_user(x, ptr, err)					\
do {									\
	__typeof__(*(ptr)) __user *__rgu_ptr = (ptr);			\
	__typeof__(x) __rgu_val;					\
	__chk_user_ptr(ptr);						\
									\
	uaccess_ttbr0_enable();						\
	__raw_get_mem("ldtr", x, ptr, err);				\
	__raw_get_mem("ldtr", __rgu_val, __rgu_ptr, err);		\
	uaccess_ttbr0_disable();					\
									\
	(x) = __rgu_val;						\
} while (0)

#define __get_user_error(x, ptr, err)					\
@@ -310,14 +320,22 @@ do { \

#define get_user	__get_user

/*
 * We must not call into the scheduler between __uaccess_enable_tco_async() and
 * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking
 * functions, we must evaluate these outside of the critical section.
 */
#define __get_kernel_nofault(dst, src, type, err_label)			\
do {									\
	__typeof__(dst) __gkn_dst = (dst);				\
	__typeof__(src) __gkn_src = (src);				\
	int __gkn_err = 0;						\
									\
	__uaccess_enable_tco_async();					\
	__raw_get_mem("ldr", *((type *)(dst)),				\
		      (__force type *)(src), __gkn_err);		\
	__raw_get_mem("ldr", *((type *)(__gkn_dst)),			\
		      (__force type *)(__gkn_src), __gkn_err);		\
	__uaccess_disable_tco_async();					\
									\
	if (unlikely(__gkn_err))					\
		goto err_label;						\
} while (0)
@@ -351,11 +369,19 @@ do { \
	}								\
} while (0)

/*
 * We must not call into the scheduler between uaccess_ttbr0_enable() and
 * uaccess_ttbr0_disable(). As `x` and `ptr` could contain blocking functions,
 * we must evaluate these outside of the critical section.
 */
#define __raw_put_user(x, ptr, err)					\
do {									\
	__chk_user_ptr(ptr);						\
	__typeof__(*(ptr)) __user *__rpu_ptr = (ptr);			\
	__typeof__(*(ptr)) __rpu_val = (x);				\
	__chk_user_ptr(__rpu_ptr);					\
									\
	uaccess_ttbr0_enable();						\
	__raw_put_mem("sttr", x, ptr, err);				\
	__raw_put_mem("sttr", __rpu_val, __rpu_ptr, err);		\
	uaccess_ttbr0_disable();					\
} while (0)

@@ -380,14 +406,22 @@ do { \

#define put_user	__put_user

/*
 * We must not call into the scheduler between __uaccess_enable_tco_async() and
 * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking
 * functions, we must evaluate these outside of the critical section.
 */
#define __put_kernel_nofault(dst, src, type, err_label)			\
do {									\
	__typeof__(dst) __pkn_dst = (dst);				\
	__typeof__(src) __pkn_src = (src);				\
	int __pkn_err = 0;						\
									\
	__uaccess_enable_tco_async();					\
	__raw_put_mem("str", *((type *)(src)),				\
		      (__force type *)(dst), __pkn_err);		\
	__raw_put_mem("str", *((type *)(__pkn_src)),			\
		      (__force type *)(__pkn_dst), __pkn_err);		\
	__uaccess_disable_tco_async();					\
									\
	if (unlikely(__pkn_err))					\
		goto err_label;						\
} while(0)
+3 −3
Original line number Diff line number Diff line
@@ -244,8 +244,6 @@ void arch_ftrace_update_code(int command)
 * on the way back to parent. For this purpose, this function is called
 * in _mcount() or ftrace_caller() to replace return address (*parent) on
 * the call stack to return_to_handler.
 *
 * Note that @frame_pointer is used only for sanity check later.
 */
void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
			   unsigned long frame_pointer)
@@ -263,9 +261,11 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
	 */
	old = *parent;

	if (!function_graph_enter(old, self_addr, frame_pointer, NULL))
	if (!function_graph_enter(old, self_addr, frame_pointer,
	    (void *)frame_pointer)) {
		*parent = return_hooker;
	}
}

#ifdef CONFIG_DYNAMIC_FTRACE
/*
Loading