Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 May 2017 18:27:54 +0000 (11:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 May 2017 18:27:54 +0000 (11:27 -0700)
Pull more arm64 updates from Catalin Marinas:

 - Silence module allocation failures when CONFIG_ARM*_MODULE_PLTS is
   enabled. This requires a check for __GFP_NOWARN in alloc_vmap_area()

 - Improve/sanitise user tagged pointers handling in the kernel

 - Inline asm fixes/cleanups

* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: Silence first allocation with CONFIG_ARM64_MODULE_PLTS=y
  ARM: Silence first allocation with CONFIG_ARM_MODULE_PLTS=y
  mm: Silence vmap() allocation failures based on caller gfp_flags
  arm64: uaccess: suppress spurious clang warning
  arm64: atomic_lse: match asm register sizes
  arm64: armv8_deprecated: ensure extension of addr
  arm64: uaccess: ensure extension of access_ok() addr
  arm64: ensure extension of smp_store_release value
  arm64: xchg: hazard against entire exchange variable
  arm64: documentation: document tagged pointer stack constraints
  arm64: entry: improve data abort handling of tagged pointers
  arm64: hw_breakpoint: fix watchpoint matching for tagged pointers
  arm64: traps: fix userspace cache maintenance emulation on a tagged pointer

13 files changed:
Documentation/arm64/tagged-pointers.txt
arch/arm/kernel/module.c
arch/arm64/include/asm/asm-uaccess.h
arch/arm64/include/asm/atomic_lse.h
arch/arm64/include/asm/barrier.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/uaccess.h
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/hw_breakpoint.c
arch/arm64/kernel/module.c
arch/arm64/kernel/traps.c
mm/vmalloc.c

index d9995f1f51b3eb9e678a557a471e4d387db49ca8..a25a99e82bb1c9811ee3e8cb111d356fa53fc979 100644 (file)
@@ -11,24 +11,56 @@ in AArch64 Linux.
 The kernel configures the translation tables so that translations made
 via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of
 the virtual address ignored by the translation hardware. This frees up
-this byte for application use, with the following caveats:
+this byte for application use.
 
-       (1) The kernel requires that all user addresses passed to EL1
-           are tagged with tag 0x00. This means that any syscall
-           parameters containing user virtual addresses *must* have
-           their top byte cleared before trapping to the kernel.
 
-       (2) Non-zero tags are not preserved when delivering signals.
-           This means that signal handlers in applications making use
-           of tags cannot rely on the tag information for user virtual
-           addresses being maintained for fields inside siginfo_t.
-           One exception to this rule is for signals raised in response
-           to watchpoint debug exceptions, where the tag information
-           will be preserved.
+Passing tagged addresses to the kernel
+--------------------------------------
 
-       (3) Special care should be taken when using tagged pointers,
-           since it is likely that C compilers will not hazard two
-           virtual addresses differing only in the upper byte.
+All interpretation of userspace memory addresses by the kernel assumes
+an address tag of 0x00.
+
+This includes, but is not limited to, addresses found in:
+
+ - pointer arguments to system calls, including pointers in structures
+   passed to system calls,
+
+ - the stack pointer (sp), e.g. when interpreting it to deliver a
+   signal,
+
+ - the frame pointer (x29) and frame records, e.g. when interpreting
+   them to generate a backtrace or call graph.
+
+Using non-zero address tags in any of these locations may result in an
+error code being returned, a (fatal) signal being raised, or other modes
+of failure.
+
+For these reasons, passing non-zero address tags to the kernel via
+system calls is forbidden, and using a non-zero address tag for sp is
+strongly discouraged.
+
+Programs maintaining a frame pointer and frame records that use non-zero
+address tags may suffer impaired or inaccurate debug and profiling
+visibility.
+
+
+Preserving tags
+---------------
+
+Non-zero tags are not preserved when delivering signals. This means that
+signal handlers in applications making use of tags cannot rely on the
+tag information for user virtual addresses being maintained for fields
+inside siginfo_t. One exception to this rule is for signals raised in
+response to watchpoint debug exceptions, where the tag information will
+be preserved.
 
 The architecture prevents the use of a tagged PC, so the upper byte will
 be set to a sign-extension of bit 55 on exception return.
+
+
+Other considerations
+--------------------
+
+Special care should be taken when using tagged pointers, since it is
+likely that C compilers will not hazard two virtual addresses differing
+only in the upper byte.
index 80254b47dc3420ec11cb6611f645d5b1faf55b66..3ff571c2c71ce42f47f31730a477f787f4ff91ee 100644 (file)
 #ifdef CONFIG_MMU
 void *module_alloc(unsigned long size)
 {
-       void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-                               GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+       gfp_t gfp_mask = GFP_KERNEL;
+       void *p;
+
+       /* Silence the initial allocation */
+       if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS))
+               gfp_mask |= __GFP_NOWARN;
+
+       p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+                               gfp_mask, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
                                __builtin_return_address(0));
        if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p)
                return p;
index df411f3e083ce7074daedf65c8bb3ed4aed4dc31..ecd9788cd29881074dd04bb9708eddef286677a6 100644 (file)
@@ -62,4 +62,13 @@ alternative_if ARM64_ALT_PAN_NOT_UAO
 alternative_else_nop_endif
        .endm
 
+/*
+ * Remove the address tag from a virtual address, if present.
+ */
+       .macro  clear_address_tag, dst, addr
+       tst     \addr, #(1 << 55)
+       bic     \dst, \addr, #(0xff << 56)
+       csel    \dst, \dst, \addr, eq
+       .endm
+
 #endif
index 7457ce082b5ff06ad6cde7a7935f9d815e2bd256..99fa69c9c3cf3ebf080c7443fb16ac6c11cf234a 100644 (file)
@@ -322,7 +322,7 @@ static inline void atomic64_and(long i, atomic64_t *v)
 #define ATOMIC64_FETCH_OP_AND(name, mb, cl...)                         \
 static inline long atomic64_fetch_and##name(long i, atomic64_t *v)     \
 {                                                                      \
-       register long x0 asm ("w0") = i;                                \
+       register long x0 asm ("x0") = i;                                \
        register atomic64_t *x1 asm ("x1") = v;                         \
                                                                        \
        asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
@@ -394,7 +394,7 @@ ATOMIC64_OP_SUB_RETURN(        , al, "memory")
 #define ATOMIC64_FETCH_OP_SUB(name, mb, cl...)                         \
 static inline long atomic64_fetch_sub##name(long i, atomic64_t *v)     \
 {                                                                      \
-       register long x0 asm ("w0") = i;                                \
+       register long x0 asm ("x0") = i;                                \
        register atomic64_t *x1 asm ("x1") = v;                         \
                                                                        \
        asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
index 4e0497f581a05ea791564badc73ffa7a1f4a0699..0fe7e43b7fbc26bf2f6f2a47354a21943ae56ab9 100644 (file)
 #define __smp_rmb()    dmb(ishld)
 #define __smp_wmb()    dmb(ishst)
 
-#define __smp_store_release(p, v)                                              \
+#define __smp_store_release(p, v)                                      \
 do {                                                                   \
+       union { typeof(*p) __val; char __c[1]; } __u =                  \
+               { .__val = (__force typeof(*p)) (v) };                  \
        compiletime_assert_atomic_type(*p);                             \
        switch (sizeof(*p)) {                                           \
        case 1:                                                         \
                asm volatile ("stlrb %w1, %0"                           \
-                               : "=Q" (*p) : "r" (v) : "memory");      \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u8 *)__u.__c)                \
+                               : "memory");                            \
                break;                                                  \
        case 2:                                                         \
                asm volatile ("stlrh %w1, %0"                           \
-                               : "=Q" (*p) : "r" (v) : "memory");      \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u16 *)__u.__c)               \
+                               : "memory");                            \
                break;                                                  \
        case 4:                                                         \
                asm volatile ("stlr %w1, %0"                            \
-                               : "=Q" (*p) : "r" (v) : "memory");      \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u32 *)__u.__c)               \
+                               : "memory");                            \
                break;                                                  \
        case 8:                                                         \
                asm volatile ("stlr %1, %0"                             \
-                               : "=Q" (*p) : "r" (v) : "memory");      \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u64 *)__u.__c)               \
+                               : "memory");                            \
                break;                                                  \
        }                                                               \
 } while (0)
index 91b26d26af8a5f961ed4d8905daffc11be5d72fa..ae852add053d835cdeb98ede5458419dd2958c6a 100644 (file)
@@ -46,7 +46,7 @@ static inline unsigned long __xchg_case_##name(unsigned long x,               \
        "       swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n"     \
                __nops(3)                                               \
        "       " #nop_lse)                                             \
-       : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)                   \
+       : "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr)        \
        : "r" (x)                                                       \
        : cl);                                                          \
                                                                        \
index ba497172610dbcda77d638a874c8e62c6ad04da5..7b8a04789cef69e161f3956ce42a7d608884698e 100644 (file)
@@ -69,20 +69,21 @@ static inline void set_fs(mm_segment_t fs)
  */
 #define __range_ok(addr, size)                                         \
 ({                                                                     \
+       unsigned long __addr = (unsigned long __force)(addr);           \
        unsigned long flag, roksum;                                     \
        __chk_user_ptr(addr);                                           \
        asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls"         \
                : "=&r" (flag), "=&r" (roksum)                          \
-               : "1" (addr), "Ir" (size),                              \
+               : "1" (__addr), "Ir" (size),                            \
                  "r" (current_thread_info()->addr_limit)               \
                : "cc");                                                \
        flag;                                                           \
 })
 
 /*
- * When dealing with data aborts or instruction traps we may end up with
- * a tagged userland pointer. Clear the tag to get a sane pointer to pass
- * on to access_ok(), for instance.
+ * When dealing with data aborts, watchpoints, or instruction traps we may end
+ * up with a tagged userland pointer. Clear the tag to get a sane pointer to
+ * pass on to access_ok(), for instance.
  */
 #define untagged_addr(addr)            sign_extend64(addr, 55)
 
@@ -230,7 +231,7 @@ do {                                                                        \
                               (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 8:                                                         \
-               __get_user_asm("ldr", "ldtr", "%",  __gu_val, (ptr),    \
+               __get_user_asm("ldr", "ldtr", "%x",  __gu_val, (ptr),   \
                               (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        default:                                                        \
@@ -297,7 +298,7 @@ do {                                                                        \
                               (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 8:                                                         \
-               __put_user_asm("str", "sttr", "%", __pu_val, (ptr),     \
+               __put_user_asm("str", "sttr", "%x", __pu_val, (ptr),    \
                               (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        default:                                                        \
index 657977e77ec8fa49e55fc9cacc1415db81a7cc2d..f0e6d717885b1fcf3b22f64c10c38f19c25f809d 100644 (file)
@@ -306,7 +306,8 @@ do {                                                                \
        _ASM_EXTABLE(0b, 4b)                                    \
        _ASM_EXTABLE(1b, 4b)                                    \
        : "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
-       : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT),             \
+       : "r" ((unsigned long)addr), "i" (-EAGAIN),             \
+         "i" (-EFAULT),                                        \
          "i" (__SWP_LL_SC_LOOPS)                               \
        : "memory");                                            \
        uaccess_disable();                                      \
index 43512d4d7df219b4b7093927fc1d9107004b6775..b738880350f9e43b8e2f3234210bda153586caf5 100644 (file)
@@ -428,12 +428,13 @@ el1_da:
        /*
         * Data abort handling
         */
-       mrs     x0, far_el1
+       mrs     x3, far_el1
        enable_dbg
        // re-enable interrupts if they were enabled in the aborted context
        tbnz    x23, #7, 1f                     // PSR_I_BIT
        enable_irq
 1:
+       clear_address_tag x0, x3
        mov     x2, sp                          // struct pt_regs
        bl      do_mem_abort
 
@@ -594,7 +595,7 @@ el0_da:
        // enable interrupts before calling the main handler
        enable_dbg_and_irq
        ct_user_exit
-       bic     x0, x26, #(0xff << 56)
+       clear_address_tag x0, x26
        mov     x1, x25
        mov     x2, sp
        bl      do_mem_abort
index 0296e79242402008837da11d97cfe682d711c18e..749f81779420c7bab2ead0d8f5b9a6cf108e6a45 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/traps.h>
 #include <asm/cputype.h>
 #include <asm/system_misc.h>
+#include <asm/uaccess.h>
 
 /* Breakpoint currently in use for each BRP. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -721,6 +722,8 @@ static u64 get_distance_from_watchpoint(unsigned long addr, u64 val,
        u64 wp_low, wp_high;
        u32 lens, lene;
 
+       addr = untagged_addr(addr);
+
        lens = __ffs(ctrl->len);
        lene = __fls(ctrl->len);
 
index c9a2ab446dc6fceb4a141fce131937048432da56..f035ff6fb223fb55b3f8b11c48f58f2ee46ac3cf 100644 (file)
 
 void *module_alloc(unsigned long size)
 {
+       gfp_t gfp_mask = GFP_KERNEL;
        void *p;
 
+       /* Silence the initial allocation */
+       if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
+               gfp_mask |= __GFP_NOWARN;
+
        p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
                                module_alloc_base + MODULES_VSIZE,
-                               GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
+                               gfp_mask, PAGE_KERNEL_EXEC, 0,
                                NUMA_NO_NODE, __builtin_return_address(0));
 
        if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
index d4d6ae02cd558d6d2d7ff6a89db7cc9490e6cccf..0805b44f986a5707d2129e74fd4490f1b3650223 100644 (file)
@@ -443,7 +443,7 @@ int cpu_enable_cache_maint_trap(void *__unused)
 }
 
 #define __user_cache_maint(insn, address, res)                 \
-       if (untagged_addr(address) >= user_addr_max()) {        \
+       if (address >= user_addr_max()) {                       \
                res = -EFAULT;                                  \
        } else {                                                \
                uaccess_ttbr0_enable();                         \
@@ -469,7 +469,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
        int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
        int ret = 0;
 
-       address = pt_regs_read_reg(regs, rt);
+       address = untagged_addr(pt_regs_read_reg(regs, rt));
 
        switch (crm) {
        case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:     /* DC CVAU, gets promoted */
index 1dda6d8a200a899bb95874ab88d0800340c669be..194c22eccb9db0054a84a2583f58935a09152ebe 100644 (file)
@@ -521,7 +521,7 @@ overflow:
                }
        }
 
-       if (printk_ratelimit())
+       if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit())
                pr_warn("vmap allocation for size %lu failed: use vmalloc=<size> to increase size\n",
                        size);
        kfree(va);