Commit 5ded8871 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Will Deacon:
 "The main thing is a fix to our FUTEX_WAKE_OP implementation which was
  unbelievably broken, but did actually work for the one scenario that
  GLIBC used to use.

  Summary:

   - Fix stack unwinding so we ignore user stacks

   - Fix ftrace module PLT trampoline initialisation checks

   - Fix terminally broken implementation of FUTEX_WAKE_OP atomics"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: futex: Fix FUTEX_WAKE_OP atomic ops with non-zero result value
  arm64: backtrace: Don't bother trying to unwind the userspace stack
  arm64/ftrace: fix inadvertent BUG() in trampoline check
parents 6d0a5984 045afc24
...@@ -30,8 +30,8 @@ do { \ ...@@ -30,8 +30,8 @@ do { \
" prfm pstl1strm, %2\n" \ " prfm pstl1strm, %2\n" \
"1: ldxr %w1, %2\n" \ "1: ldxr %w1, %2\n" \
insn "\n" \ insn "\n" \
"2: stlxr %w3, %w0, %2\n" \ "2: stlxr %w0, %w3, %2\n" \
" cbnz %w3, 1b\n" \ " cbnz %w0, 1b\n" \
" dmb ish\n" \ " dmb ish\n" \
"3:\n" \ "3:\n" \
" .pushsection .fixup,\"ax\"\n" \ " .pushsection .fixup,\"ax\"\n" \
...@@ -50,30 +50,30 @@ do { \ ...@@ -50,30 +50,30 @@ do { \
static inline int static inline int
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr) arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
{ {
int oldval = 0, ret, tmp; int oldval, ret, tmp;
u32 __user *uaddr = __uaccess_mask_ptr(_uaddr); u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
pagefault_disable(); pagefault_disable();
switch (op) { switch (op) {
case FUTEX_OP_SET: case FUTEX_OP_SET:
__futex_atomic_op("mov %w0, %w4", __futex_atomic_op("mov %w3, %w4",
ret, oldval, uaddr, tmp, oparg); ret, oldval, uaddr, tmp, oparg);
break; break;
case FUTEX_OP_ADD: case FUTEX_OP_ADD:
__futex_atomic_op("add %w0, %w1, %w4", __futex_atomic_op("add %w3, %w1, %w4",
ret, oldval, uaddr, tmp, oparg); ret, oldval, uaddr, tmp, oparg);
break; break;
case FUTEX_OP_OR: case FUTEX_OP_OR:
__futex_atomic_op("orr %w0, %w1, %w4", __futex_atomic_op("orr %w3, %w1, %w4",
ret, oldval, uaddr, tmp, oparg); ret, oldval, uaddr, tmp, oparg);
break; break;
case FUTEX_OP_ANDN: case FUTEX_OP_ANDN:
__futex_atomic_op("and %w0, %w1, %w4", __futex_atomic_op("and %w3, %w1, %w4",
ret, oldval, uaddr, tmp, ~oparg); ret, oldval, uaddr, tmp, ~oparg);
break; break;
case FUTEX_OP_XOR: case FUTEX_OP_XOR:
__futex_atomic_op("eor %w0, %w1, %w4", __futex_atomic_op("eor %w3, %w1, %w4",
ret, oldval, uaddr, tmp, oparg); ret, oldval, uaddr, tmp, oparg);
break; break;
default: default:
......
...@@ -73,4 +73,9 @@ static inline bool is_forbidden_offset_for_adrp(void *place) ...@@ -73,4 +73,9 @@ static inline bool is_forbidden_offset_for_adrp(void *place)
struct plt_entry get_plt_entry(u64 dst, void *pc); struct plt_entry get_plt_entry(u64 dst, void *pc);
bool plt_entries_equal(const struct plt_entry *a, const struct plt_entry *b); bool plt_entries_equal(const struct plt_entry *a, const struct plt_entry *b);
static inline bool plt_entry_is_initialized(const struct plt_entry *e)
{
return e->adrp || e->add || e->br;
}
#endif /* __ASM_MODULE_H */ #endif /* __ASM_MODULE_H */
...@@ -107,8 +107,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -107,8 +107,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline); trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline);
if (!plt_entries_equal(mod->arch.ftrace_trampoline, if (!plt_entries_equal(mod->arch.ftrace_trampoline,
&trampoline)) { &trampoline)) {
if (!plt_entries_equal(mod->arch.ftrace_trampoline, if (plt_entry_is_initialized(mod->arch.ftrace_trampoline)) {
&(struct plt_entry){})) {
pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n"); pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -102,10 +102,16 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) ...@@ -102,10 +102,16 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{ {
struct stackframe frame; struct stackframe frame;
int skip; int skip = 0;
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
if (regs) {
if (user_mode(regs))
return;
skip = 1;
}
if (!tsk) if (!tsk)
tsk = current; tsk = current;
...@@ -126,7 +132,6 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) ...@@ -126,7 +132,6 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.graph = 0; frame.graph = 0;
#endif #endif
skip = !!regs;
printk("Call trace:\n"); printk("Call trace:\n");
do { do {
/* skip until specified stack frame */ /* skip until specified stack frame */
...@@ -176,15 +181,13 @@ static int __die(const char *str, int err, struct pt_regs *regs) ...@@ -176,15 +181,13 @@ static int __die(const char *str, int err, struct pt_regs *regs)
return ret; return ret;
print_modules(); print_modules();
__show_regs(regs);
pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk),
end_of_stack(tsk)); end_of_stack(tsk));
show_regs(regs);
if (!user_mode(regs)) { if (!user_mode(regs))
dump_backtrace(regs, tsk);
dump_instr(KERN_EMERG, regs); dump_instr(KERN_EMERG, regs);
}
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment