summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt7
-rw-r--r--Documentation/speculation.txt90
-rw-r--r--arch/arm/configs/tegra12_defconfig1
-rw-r--r--arch/arm/include/asm/barrier.h4
-rw-r--r--arch/arm/include/asm/cp15.h24
-rw-r--r--arch/arm/mm/Kconfig17
-rw-r--r--arch/arm/mm/fault.c23
-rw-r--r--arch/arm/mm/fsr-2level.c4
-rw-r--r--arch/arm/mm/fsr-3level.c69
-rw-r--r--arch/arm/mm/mmap.c4
-rw-r--r--arch/arm/mm/proc-v7-2level.S12
-rw-r--r--arch/arm/mm/proc-v7-3level.S15
-rw-r--r--arch/arm/mm/proc-v7.S43
-rw-r--r--arch/arm64/include/asm/barrier.h4
-rw-r--r--block/genhd.c1
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c19
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h3
-rw-r--r--drivers/gpu/nvgpu/gk20a/gr_gk20a.c31
-rw-r--r--drivers/gpu/nvgpu/gk20a/gr_gk20a.h5
-rw-r--r--drivers/gpu/nvgpu/gk20a/mm_gk20a.c7
-rw-r--r--drivers/hid/hid-core.c3
-rw-r--r--drivers/media/i2c/ad9389b.c4
-rw-r--r--drivers/media/i2c/adv7604.c4
-rw-r--r--drivers/media/i2c/ov7670.c4
-rw-r--r--drivers/media/i2c/ov9650.c3
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c7
-rw-r--r--drivers/media/i2c/s5k6aa.c3
-rw-r--r--drivers/media/tuners/tuner-xc2028.c3
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c3
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c3
-rw-r--r--drivers/misc/tegra-cryptodev.c70
-rw-r--r--drivers/pci/host/pci-tegra.c21
-rw-r--r--drivers/scsi/sg.c8
-rw-r--r--drivers/staging/android/ion/ion_heap.c12
-rw-r--r--drivers/thermal/thermal_core.c11
-rw-r--r--drivers/tty/tty_ldisc.c7
-rw-r--r--drivers/video/tegra/dc/sor.c4
-rw-r--r--drivers/video/tegra/dc/sor_regs.h2
-rw-r--r--drivers/video/tegra/host/host1x/host1x.c5
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c9
-rw-r--r--fs/ext4/ext4_jbd2.c8
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/ioprio.c2
-rw-r--r--fs/proc/base.c5
-rw-r--r--fs/proc/task_mmu.c4
-rw-r--r--include/linux/mm.h53
-rw-r--r--include/linux/nospec.h72
-rw-r--r--include/linux/nvhost_ioctl.h8
-rw-r--r--include/net/tcp.h2
-rw-r--r--kernel/auditsc.c341
-rw-r--r--kernel/cgroup.c2
-rw-r--r--kernel/events/core.c6
-rw-r--r--mm/memory.c48
-rw-r--r--mm/mmap.c130
-rw-r--r--sound/soc/tegra/tegra30_avp.c7
-rw-r--r--sound/usb/quirks.c17
-rw-r--r--sound/usb/stream.c6
57 files changed, 925 insertions, 357 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1311a48a7367..951b7eedc44e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2884,6 +2884,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
spia_pedr=
spia_peddr=
+ stack_guard_gap= [MM]
+ override the default stack gap protection. The value
+ is in page units and it defines how many pages prior
+ to (for stacks growing down) resp. after (for stacks
+ growing up) the main stack are reserved for no other
+ mapping. Default value is 256 pages.
+
stacktrace [FTRACE]
Enabled the stack tracer on boot up.
diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt
new file mode 100644
index 000000000000..e9e6cbae2841
--- /dev/null
+++ b/Documentation/speculation.txt
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+ int load_array(int *array, unsigned int index)
+ {
+ if (index >= MAX_ARRAY_ELEMS)
+ return 0;
+ else
+ return array[index];
+ }
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+ CMP <index>, #MAX_ARRAY_ELEMS
+ B.LT less
+ MOV <returnval>, #0
+ RET
+ less:
+ LDR <returnval>, [<array>, <index>]
+ RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+ int load_dependent_arrays(int *arr1, int *arr2, int index)
+ {
+ int val1, val2,
+
+ val1 = load_array(arr1, index);
+ val2 = load_array(arr2, val1);
+
+ return val2;
+ }
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+ int load_array(int *array, unsigned int index)
+ {
+ if (index >= MAX_ARRAY_ELEMS)
+ return 0;
+ else {
+ index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+ return array[index];
+ }
+ }
diff --git a/arch/arm/configs/tegra12_defconfig b/arch/arm/configs/tegra12_defconfig
index 5e16975801fe..a0cb43fa35b6 100644
--- a/arch/arm/configs/tegra12_defconfig
+++ b/arch/arm/configs/tegra12_defconfig
@@ -195,7 +195,6 @@ CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
CONFIG_APDS9802ALS=y
CONFIG_SENSORS_NCT1008=y
-CONFIG_TEGRA_CRYPTO_DEV=y
CONFIG_THERM_EST=y
CONFIG_FAN_THERM_EST=y
CONFIG_EEPROM_AT24=y
diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h
index b00ef075bc2e..6af46bfa9837 100644
--- a/arch/arm/include/asm/barrier.h
+++ b/arch/arm/include/asm/barrier.h
@@ -79,5 +79,9 @@ do { \
#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
+#define speculation_barrier() \
+ asm volatile( "dsb sy\n" \
+ "isb\n" : : : "memory")
+
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_BARRIER_H */
diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
index 1f3262e99d81..d820fc5f043a 100644
--- a/arch/arm/include/asm/cp15.h
+++ b/arch/arm/include/asm/cp15.h
@@ -42,8 +42,32 @@
#define vectors_high() (0)
#endif
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \
+ "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
+#define __ACCESS_CP15_64(Op1, CRm) \
+ "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
+
+#define __read_sysreg(r, w, c, t) ({ \
+ t __val; \
+ asm volatile(r " " c : "=r" (__val)); \
+ __val; \
+})
+#define read_sysreg(...) __read_sysreg(__VA_ARGS__)
+
+#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v)))
+#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__)
+
#ifdef CONFIG_CPU_CP15
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \
+ "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
+#define __ACCESS_CP15_64(Op1, CRm) \
+ "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
+
+
+#define BPIALL __ACCESS_CP15(c7, 0, c5, 6)
+#define ICIALLU __ACCESS_CP15(c7, 0, c5, 0)
+
extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
extern unsigned long cr_alignment; /* defined in entry-armv.S */
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 2c7e308f8cab..07c3309b6288 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -947,3 +947,20 @@ config ARM_SAVE_DEBUG_CONTEXT_NO_LOCK
the ARM debug registers across CPU powerdown. This option
should not be selected unless you are actively debugging
the context save/restore code. If unsure, say N.
+
+config HARDEN_BRANCH_PREDICTOR
+ bool "Harden the branch predictor against aliasing attacks" if EXPERT
+ default y
+ help
+ Speculation attacks against some high-performance processors rely on
+ being able to manipulate the branch predictor for a victim context by
+ executing aliasing branches in the attacker context. Such attacks
+ can be partially mitigated against by clearing internal branch
+ predictor state and limiting the prediction logic in some situations.
+
+ This config option will take CPU-specific actions to harden the
+ branch predictor against aliasing attacks and may rely on specific
+ instruction sequences or control bits being set by the system
+ firmware.
+
+ If unsure, say Y.
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 9820ad4b80c0..e8f42821a206 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -20,11 +20,13 @@
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <asm/cp15.h>
#include <asm/exception.h>
#include <asm/pgtable.h>
#include <asm/system_misc.h>
#include <asm/system_info.h>
#include <asm/tlbflush.h>
+#include <asm/cputype.h>
#include "fault.h"
@@ -393,12 +395,33 @@ no_context:
__do_kernel_fault(mm, addr, fsr, regs);
return 0;
}
+
+static int __maybe_unused
+do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ if (addr > TASK_SIZE) {
+ switch (read_cpuid_part_number()) {
+ case ARM_CPU_PART_CORTEX_A15:
+ write_sysreg(0, ICIALLU);
+ break;
+ }
+ }
+#endif
+ return do_page_fault(addr, fsr, regs);
+}
#else /* CONFIG_MMU */
static int
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
return 0;
}
+
+static int
+do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+ return 0;
+}
#endif /* CONFIG_MMU */
/*
diff --git a/arch/arm/mm/fsr-2level.c b/arch/arm/mm/fsr-2level.c
index 18ca74c0f341..4cede9bc7722 100644
--- a/arch/arm/mm/fsr-2level.c
+++ b/arch/arm/mm/fsr-2level.c
@@ -50,7 +50,7 @@ static struct fsr_info ifsr_info[] = {
{ do_bad, SIGBUS, 0, "unknown 4" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" },
- { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
{ do_bad, SIGBUS, 0, "external abort on non-linefetch" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
{ do_bad, SIGBUS, 0, "unknown 10" },
@@ -58,7 +58,7 @@ static struct fsr_info ifsr_info[] = {
{ do_bad, SIGBUS, 0, "external abort on translation" },
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
{ do_bad, SIGBUS, 0, "external abort on translation" },
- { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
{ do_bad, SIGBUS, 0, "unknown 16" },
{ do_bad, SIGBUS, 0, "unknown 17" },
{ do_bad, SIGBUS, 0, "unknown 18" },
diff --git a/arch/arm/mm/fsr-3level.c b/arch/arm/mm/fsr-3level.c
index 47f4c6fb25ba..791ef0c66741 100644
--- a/arch/arm/mm/fsr-3level.c
+++ b/arch/arm/mm/fsr-3level.c
@@ -65,4 +65,73 @@ static struct fsr_info fsr_info[] = {
{ do_bad, SIGBUS, 0, "unknown 63" },
};
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+static struct fsr_info ifsr_info[] = {
+ { do_bad, SIGBUS, 0, "unknown 0" },
+ { do_bad, SIGBUS, 0, "unknown 1" },
+ { do_bad, SIGBUS, 0, "unknown 2" },
+ { do_bad, SIGBUS, 0, "unknown 3" },
+ { do_bad, SIGBUS, 0, "reserved translation fault" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
+ { do_bad, SIGBUS, 0, "reserved access flag fault" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
+ { do_bad, SIGBUS, 0, "reserved permission fault" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
+ { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
+ { do_bad, SIGBUS, 0, "synchronous external abort" },
+ { do_bad, SIGBUS, 0, "asynchronous external abort" },
+ { do_bad, SIGBUS, 0, "unknown 18" },
+ { do_bad, SIGBUS, 0, "unknown 19" },
+ { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous parity error" },
+ { do_bad, SIGBUS, 0, "asynchronous parity error" },
+ { do_bad, SIGBUS, 0, "unknown 26" },
+ { do_bad, SIGBUS, 0, "unknown 27" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
+ { do_bad, SIGBUS, 0, "unknown 32" },
+ { do_bad, SIGBUS, BUS_ADRALN, "alignment fault" },
+ { do_bad, SIGBUS, 0, "debug event" },
+ { do_bad, SIGBUS, 0, "unknown 35" },
+ { do_bad, SIGBUS, 0, "unknown 36" },
+ { do_bad, SIGBUS, 0, "unknown 37" },
+ { do_bad, SIGBUS, 0, "unknown 38" },
+ { do_bad, SIGBUS, 0, "unknown 39" },
+ { do_bad, SIGBUS, 0, "unknown 40" },
+ { do_bad, SIGBUS, 0, "unknown 41" },
+ { do_bad, SIGBUS, 0, "unknown 42" },
+ { do_bad, SIGBUS, 0, "unknown 43" },
+ { do_bad, SIGBUS, 0, "unknown 44" },
+ { do_bad, SIGBUS, 0, "unknown 45" },
+ { do_bad, SIGBUS, 0, "unknown 46" },
+ { do_bad, SIGBUS, 0, "unknown 47" },
+ { do_bad, SIGBUS, 0, "unknown 48" },
+ { do_bad, SIGBUS, 0, "unknown 49" },
+ { do_bad, SIGBUS, 0, "unknown 50" },
+ { do_bad, SIGBUS, 0, "unknown 51" },
+ { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" },
+ { do_bad, SIGBUS, 0, "unknown 53" },
+ { do_bad, SIGBUS, 0, "unknown 54" },
+ { do_bad, SIGBUS, 0, "unknown 55" },
+ { do_bad, SIGBUS, 0, "unknown 56" },
+ { do_bad, SIGBUS, 0, "unknown 57" },
+ { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" },
+ { do_bad, SIGBUS, 0, "unknown 59" },
+ { do_bad, SIGBUS, 0, "unknown 60" },
+ { do_bad, SIGBUS, 0, "unknown 61" },
+ { do_bad, SIGBUS, 0, "unknown 62" },
+ { do_bad, SIGBUS, 0, "unknown 63" },
+};
+#else
#define ifsr_info fsr_info
++#endif
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index a5b1934e711b..86cda2e8ec19 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -90,7 +90,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vm_start_gap(vma)))
return addr;
}
@@ -155,7 +155,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
addr = PAGE_ALIGN(addr);
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vm_start_gap(vma)))
return addr;
}
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index a0cf0dc9f0d7..48db62324291 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -36,7 +36,16 @@
*
* It is assumed that:
* - we are not using split page tables
- */
+ *
+ * Cortex-A15 requires ACTLR[0] to be set from secure in order
+ * for the icache invalidation to also invalidate the BTB.
+ */
+ENTRY(cpu_v7_icinv_switch_mm)
+#ifdef CONFIG_MMU
+ mcr p15, 0, r0, c7, c5, 0 @ ICIALLU
+ /* Fall through to switch_mm... */
+#endif
+
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
@@ -61,6 +70,7 @@ ENTRY(cpu_v7_switch_mm)
#endif
mov pc, lr
ENDPROC(cpu_v7_switch_mm)
+ENDPROC(cpu_v7_icinv_switch_mm)
/*
* cpu_v7_set_pte_ext(ptep, pte)
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index e377cc4031b0..e2bb1ae55047 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -53,6 +53,19 @@
* Set the translation table base pointer to be pgd_phys (physical address of
* the new TTB).
*/
+ENTRY(cpu_v7_icinv_switch_mm)
+#ifdef CONFIG_MMU
+ /*
+ * Cortex-A15 requires ACTLR[0] to be set from secure in order
+ * for the icache invalidation to also invalidate the BTB.
+ */
+ mcr p15, 0, r0, c7, c5, 0 @ ICIALLU
+ /* Fall through to switch_mm... */
+#endif
+ENTRY(cpu_v7_btbinv_switch_mm)
+#ifdef CONFIG_MMU
+ mcr p15, 0, r0, c7, c5, 6 @ flush BTAC/BTB
+#endif
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
mmid r2, r2 @ get mm->context.id
@@ -64,6 +77,8 @@ ENTRY(cpu_v7_switch_mm)
#endif
mov pc, lr
ENDPROC(cpu_v7_switch_mm)
+ENDPROC(cpu_v7_btbinv_switch_mm)
+ENDPROC(cpu_v7_icinv_switch_mm)
/*
* cpu_v7_set_pte_ext(ptep, pte)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index d1dea91517e0..322ecf52c2a7 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -415,6 +415,46 @@ start_restore_wpt:
ENDPROC(cpu_v7_do_resume)
#endif
+/*
+ * Cortex-A15
+ */
+ globl_equ cpu_ca15_proc_init, cpu_v7_proc_init
+ globl_equ cpu_ca15_proc_fin, cpu_v7_proc_fin
+ globl_equ cpu_ca15_reset, cpu_v7_reset
+ globl_equ cpu_ca15_do_idle, cpu_v7_do_idle
+ globl_equ cpu_ca15_dcache_clean_area, cpu_v7_dcache_clean_area
+ globl_equ cpu_ca15_set_pte_ext, cpu_v7_set_pte_ext
+ globl_equ cpu_ca15_suspend_size, cpu_v7_suspend_size
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ globl_equ cpu_ca15_switch_mm, cpu_v7_icinv_switch_mm
+#else
+ globl_equ cpu_ca15_switch_mm, cpu_v7_switch_mm
+#endif
+#ifdef CONFIG_ARM_CPU_SUSPEND
+ globl_equ cpu_ca15_do_suspend, cpu_v7_do_suspend
+ globl_equ cpu_ca15_do_resume, cpu_v7_do_resume
+#endif
+
+/*
+ * Cortex-A12/A17
+ */
+ globl_equ cpu_ca17_proc_init, cpu_v7_proc_init
+ globl_equ cpu_ca17_proc_fin, cpu_v7_proc_fin
+ globl_equ cpu_ca17_reset, cpu_v7_reset
+ globl_equ cpu_ca17_do_idle, cpu_v7_do_idle
+ globl_equ cpu_ca17_dcache_clean_area, cpu_v7_dcache_clean_area
+ globl_equ cpu_ca17_set_pte_ext, cpu_v7_set_pte_ext
+ globl_equ cpu_ca17_suspend_size, cpu_v7_suspend_size
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ globl_equ cpu_ca17_switch_mm, cpu_v7_btbinv_switch_mm
+#else
+ globl_equ cpu_ca17_switch_mm, cpu_v7_switch_mm
+#endif
+#ifdef CONFIG_ARM_CPU_SUSPEND
+ globl_equ cpu_ca17_do_suspend, cpu_v7_do_suspend
+ globl_equ cpu_ca17_do_resume, cpu_v7_do_resume
+#endif
+
#ifdef CONFIG_CPU_PJ4B
globl_equ cpu_pj4b_switch_mm, cpu_v7_switch_mm
globl_equ cpu_pj4b_set_pte_ext, cpu_v7_set_pte_ext
@@ -722,6 +762,7 @@ __v7_setup_stack:
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+ define_processor_functions ca15, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
#ifdef CONFIG_CPU_PJ4B
define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
#endif
@@ -818,7 +859,7 @@ __v7_ca15mp_r3_proc_info:
__v7_ca15mp_proc_info:
.long 0x410fc0f0
.long 0xff0ffff0
- __v7_proc __v7_ca15mp_setup
+ __v7_proc __v7_ca15mp_setup, proc_fns = ca15_processor_functions
.size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
/*
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 9269edba2c90..8059ead5f2d6 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -99,6 +99,10 @@ do { \
#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
#define nop() asm volatile("nop");
+#define speculation_barrier() \
+ asm volatile( "dsb sy\n" \
+ "isb\n" : : : "memory")
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_BARRIER_H */
diff --git a/block/genhd.c b/block/genhd.c
index 6f612a747810..50d8e7ac4d69 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -828,6 +828,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
if (iter) {
class_dev_iter_exit(iter);
kfree(iter);
+ seqf->private = NULL;
}
}
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 3065e8403559..0a48f6a551ae 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -3,7 +3,7 @@
*
* GK20A Graphics channel
*
- * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -669,7 +669,7 @@ void gk20a_free_channel(struct channel_gk20a *ch, bool finish)
memset(&ch->ramfc, 0, sizeof(struct mem_desc_sub));
/* free gpfifo */
- if (ch->gpfifo.gpu_va)
+ if (ch->vm && ch->gpfifo.gpu_va)
gk20a_gmmu_unmap(ch_vm, ch->gpfifo.gpu_va,
ch->gpfifo.size, gk20a_mem_flag_none);
if (ch->gpfifo.cpu_va)
@@ -698,8 +698,9 @@ unbind:
channel_gk20a_unbind(ch);
channel_gk20a_free_inst(g, ch);
- ch->vpr = false;
+ gk20a_vm_put(ch->vm); /* Don't use VM after this. */
ch->vm = NULL;
+ ch->vpr = false;
WARN_ON(ch->sync);
/* unlink all debug sessions */
@@ -2066,6 +2067,18 @@ long gk20a_channel_ioctl(struct file *filp,
(struct nvhost_alloc_obj_ctx_args *)buf);
gk20a_idle(dev);
break;
+ case NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX:
+ err = gk20a_busy(dev);
+ if (err) {
+ dev_err(&dev->dev,
+ "%s: failed to host gk20a for ioctl cmd: 0x%x",
+ __func__, cmd);
+ return err;
+ }
+ err = gk20a_free_obj_ctx(ch,
+ (struct nvhost_free_obj_ctx_args *)buf);
+ gk20a_idle(dev);
+ break;
case NVHOST_IOCTL_CHANNEL_ALLOC_GPFIFO:
err = gk20a_busy(dev);
if (err) {
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index 831db0f4986a..547bb064fd63 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -3,7 +3,7 @@
*
* GK20A graphics channel
*
- * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -98,6 +98,7 @@ struct channel_gk20a {
u64 userd_iova;
u64 userd_gpu_va;
+ s32 num_objects;
u32 obj_class; /* we support only one obj per channel */
struct priv_cmd_queue priv_cmd_q;
diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
index d5a3bbd34a78..db34cc0e85e9 100644
--- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
@@ -1,7 +1,7 @@
/*
* GK20A Graphics
*
- * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -26,6 +26,7 @@
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include <linux/nvhost.h>
+#include <asm/barrier.h>
#include "gk20a.h"
#include "kind_gk20a.h"
@@ -2697,6 +2698,7 @@ void gk20a_free_channel_ctx(struct channel_gk20a *c)
memset(&c->ch_ctx, 0, sizeof(struct channel_ctx_gk20a));
+ c->num_objects = 0;
c->first_init = false;
}
@@ -2847,6 +2849,8 @@ int gk20a_alloc_obj_ctx(struct channel_gk20a *c,
c->first_init = true;
}
+ c->num_objects++;
+
gk20a_dbg_fn("done");
return 0;
out:
@@ -2858,6 +2862,29 @@ out:
return err;
}
+int gk20a_free_obj_ctx(struct channel_gk20a *c,
+ struct nvhost_free_obj_ctx_args *args)
+{
+ unsigned long timeout = gk20a_get_gr_idle_timeout(c->g);
+
+ gk20a_dbg_fn("");
+
+ if (c->num_objects == 0)
+ return 0;
+
+ c->num_objects--;
+
+ if (c->num_objects == 0) {
+ c->first_init = false;
+ gk20a_disable_channel(c,
+ !c->has_timedout,
+ timeout);
+ gr_gk20a_unmap_channel_patch_ctx(c);
+ }
+
+ return 0;
+}
+
static void gk20a_remove_gr_support(struct gr_gk20a *gr)
{
struct gk20a *g = gr->g;
@@ -3568,6 +3595,7 @@ int gr_gk20a_add_zbc(struct gk20a *g, struct gr_gk20a *gr,
mutex_lock(&gr->zbc_lock);
switch (zbc_val->type) {
case GK20A_ZBC_TYPE_COLOR:
+ speculation_barrier();
/* search existing tables */
for (i = 0; i < gr->max_used_color_index; i++) {
@@ -3606,6 +3634,7 @@ int gr_gk20a_add_zbc(struct gk20a *g, struct gr_gk20a *gr,
}
break;
case GK20A_ZBC_TYPE_DEPTH:
+ speculation_barrier();
/* search existing tables */
for (i = 0; i < gr->max_used_depth_index; i++) {
diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.h b/drivers/gpu/nvgpu/gk20a/gr_gk20a.h
index 526eefb46b6f..2a31aa0b830f 100644
--- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.h
@@ -1,7 +1,7 @@
/*
* GK20A Graphics Engine
*
- * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -324,9 +324,12 @@ int gk20a_init_gr_channel(struct channel_gk20a *ch_gk20a);
int gr_gk20a_init_ctx_vars(struct gk20a *g, struct gr_gk20a *gr);
struct nvhost_alloc_obj_ctx_args;
+struct nvhost_free_obj_ctx_args;
int gk20a_alloc_obj_ctx(struct channel_gk20a *c,
struct nvhost_alloc_obj_ctx_args *args);
+int gk20a_free_obj_ctx(struct channel_gk20a *c,
+ struct nvhost_free_obj_ctx_args *args);
void gk20a_free_channel_ctx(struct channel_gk20a *c);
int gk20a_gr_isr(struct gk20a *g);
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
index 2bbd973ad0b1..c5a5791f9489 100644
--- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c
@@ -1329,6 +1329,12 @@ u64 gk20a_vm_map(struct vm_gk20a *vm,
bfr.pgsz_idx = -1;
mapping_size = mapping_size ? mapping_size : bfr.size;
+ if ((mapping_size > bfr.size) ||
+ (buffer_offset > (bfr.size - mapping_size))) {
+ err = -EINVAL;
+ goto clean_up;
+ }
+
/* If FIX_OFFSET is set, pgsz is determined. Otherwise, select
* page size according to memory alignment */
if (flags & NVHOST_AS_MAP_BUFFER_FLAGS_FIXED_OFFSET) {
@@ -2420,6 +2426,7 @@ int gk20a_vm_bind_channel(struct gk20a_as_share *as_share,
gk20a_dbg_fn("");
+ gk20a_vm_get(vm);
ch->vm = vm;
err = channel_gk20a_commit_va(ch);
if (err)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 46b7b12376f9..dcea21ed9cd6 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1138,6 +1138,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
/* Ignore report if ErrorRollOver */
if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
value[n] >= min && value[n] <= max &&
+ value[n] - min < field->maxusage &&
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
goto exit;
}
@@ -1150,11 +1151,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
}
if (field->value[n] >= min && field->value[n] <= max
+ && field->value[n] - min < field->maxusage
&& field->usage[field->value[n] - min].hid
&& search(value, field->value[n], count))
hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
if (value[n] >= min && value[n] <= max
+ && value[n] - min < field->maxusage
&& field->usage[value[n] - min].hid
&& search(field->value, value[n], count))
hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 58344b6c3a55..436b9fd4775e 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -36,6 +36,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/ad9389b.h>
+#include <asm/barrier.h>
static int debug;
module_param(debug, int, 0644);
@@ -627,6 +628,9 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
}
if (edid->start_block >= state->edid.segments * 2)
return -E2BIG;
+
+ speculation_barrier();
+
if (edid->blocks + edid->start_block >= state->edid.segments * 2)
edid->blocks = state->edid.segments * 2 - edid->start_block;
memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 31a63c9324fe..84202010d7d8 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -40,6 +40,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
#include <media/adv7604.h>
+#include <asm/barrier.h>
static int debug;
module_param(debug, int, 0644);
@@ -1593,6 +1594,9 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
return -EINVAL;
if (edid->start_block >= state->edid_blocks)
return -EINVAL;
+
+ speculation_barrier();
+
if (edid->start_block + edid->blocks > state->edid_blocks)
edid->blocks = state->edid_blocks - edid->start_block;
if (!edid->edid)
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 617ad3fff4aa..7124145a210b 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -21,6 +21,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-mediabus.h>
#include <media/ov7670.h>
+#include <asm/barrier.h>
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
@@ -1087,6 +1088,9 @@ static int ov7670_enum_frameintervals(struct v4l2_subdev *sd,
{
if (interval->index >= ARRAY_SIZE(ov7670_frame_rates))
return -EINVAL;
+
+ speculation_barrier();
+
interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
interval->discrete.numerator = 1;
interval->discrete.denominator = ov7670_frame_rates[interval->index];
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 1dbb8118a285..47902efae8d4 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -30,6 +30,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/ov9650.h>
+#include <asm/barrier.h>
static int debug;
module_param(debug, int, 0644);
@@ -1086,6 +1087,8 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
if (fse->index > ARRAY_SIZE(ov965x_framesizes))
return -EINVAL;
+ speculation_barrier();
+
while (--i)
if (fse->code == ov965x_formats[i].code)
break;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 9eac5310942f..a7078441e1e1 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -33,6 +33,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/s5c73m3.h>
+#include <asm/barrier.h>
#include "s5c73m3.h"
@@ -959,6 +960,8 @@ static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd,
if (fie->index >= ARRAY_SIZE(s5c73m3_intervals))
return -EINVAL;
+ speculation_barrier();
+
mutex_lock(&state->lock);
fi = &s5c73m3_intervals[fie->index];
if (fie->width > fi->size.width || fie->height > fi->size.height)
@@ -1228,6 +1231,8 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= s5c73m3_resolutions_len[idx])
return -EINVAL;
+ speculation_barrier();
+
fse->min_width = s5c73m3_resolutions[idx][fse->index].width;
fse->max_width = fse->min_width;
fse->max_height = s5c73m3_resolutions[idx][fse->index].height;
@@ -1272,6 +1277,8 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= s5c73m3_resolutions_len[idx])
return -EINVAL;
+ speculation_barrier();
+
fse->min_width = s5c73m3_resolutions[idx][fse->index].width;
fse->max_width = fse->min_width;
fse->max_height = s5c73m3_resolutions[idx][fse->index].height;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index bdf5e3db31d1..aff91c3bcfde 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -29,6 +29,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/s5k6aa.h>
+#include <asm/barrier.h>
static int debug;
module_param(debug, int, 0644);
@@ -1006,6 +1007,8 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
if (fie->index > ARRAY_SIZE(s5k6aa_intervals))
return -EINVAL;
+ speculation_barrier();
+
v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
S5K6AA_WIN_WIDTH_MAX, 1,
&fie->height, S5K6AA_WIN_HEIGHT_MIN,
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 9771cd83c06e..38afc54ef349 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1385,11 +1385,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
* in order to avoid troubles during device release.
*/
kfree(priv->ctrl.fname);
+ priv->ctrl.fname = NULL;
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
- rc = -ENOMEM;
+ return -ENOMEM;
}
/*
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 6f52e699178b..99b3162ab5b4 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -28,6 +28,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/videobuf2-core.h>
+#include <asm/barrier.h>
/* Zero out the end of the struct pointed to by p. Everything after, but
* not including, the specified field is cleared. */
@@ -2121,6 +2122,7 @@ bool v4l2_is_known_ioctl(unsigned int cmd)
{
if (_IOC_NR(cmd) >= V4L2_IOCTLS)
return false;
+ speculation_barrier();
return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
}
@@ -2130,6 +2132,7 @@ struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd)
return vdev->lock;
if (test_bit(_IOC_NR(cmd), vdev->disable_locking))
return NULL;
+ speculation_barrier();
if (vdev->queue && vdev->queue->lock &&
(v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE))
return vdev->queue->lock;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index e3bdc3be91e1..60ba606afc56 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -23,6 +23,7 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-core.h>
+#include <asm/barrier.h>
static int debug;
module_param(debug, int, 0644);
@@ -1800,6 +1801,8 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
return -EINVAL;
}
+ speculation_barrier();
+
vb = q->bufs[eb->index];
if (eb->plane >= vb->num_planes) {
diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c
index 88c9cb217880..2c0d3918100d 100644
--- a/drivers/misc/tegra-cryptodev.c
+++ b/drivers/misc/tegra-cryptodev.c
@@ -33,6 +33,7 @@
#include <linux/tegra-soc.h>
#include <crypto/rng.h>
#include <crypto/hash.h>
+#include <asm/barrier.h>
#include "tegra-cryptodev.h"
@@ -282,6 +283,8 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re
const u8 *key = NULL;
struct tegra_crypto_completion tcrypt_complete;
+ speculation_barrier();
+
if (crypt_req->op & TEGRA_CRYPTO_ECB) {
req = ablkcipher_request_alloc(ctx->ecb_tfm, GFP_KERNEL);
tfm = ctx->ecb_tfm;
@@ -425,6 +428,33 @@ static int tegra_crypt_rsa(struct tegra_crypto_ctx *ctx,
int ret = 0;
unsigned long *xbuf[XBUFSIZE];
struct tegra_crypto_completion rsa_complete;
+ unsigned int total_key_len;
+ char *key_mem;
+
+ if ((((rsa_req->keylen >> 16) & 0xFFFF) >
+ MAX_RSA_MSG_LEN) ||
+ ((rsa_req->keylen & 0xFFFF) >
+ MAX_RSA_MSG_LEN)) {
+ pr_err("Invalid rsa key length\n");
+ return -EINVAL;
+ }
+
+ total_key_len = (((rsa_req->keylen >> 16) & 0xFFFF) +
+ (rsa_req->keylen & 0xFFFF));
+
+ key_mem = kzalloc(total_key_len, GFP_KERNEL);
+ if (!key_mem)
+ return -ENOMEM;
+
+ ret = copy_from_user(key_mem, (void __user *)rsa_req->key,
+ total_key_len);
+ if (ret) {
+ pr_err("%s: copy_from_user fail(%d)\n", __func__, ret);
+ kfree(key_mem);
+ return -EINVAL;
+ }
+
+ rsa_req->key = key_mem;
switch (rsa_req->algo) {
case TEGRA_RSA512:
@@ -475,10 +505,8 @@ static int tegra_crypt_rsa(struct tegra_crypto_ctx *ctx,
init_completion(&rsa_complete.restart);
result = kzalloc(rsa_req->keylen >> 16, GFP_KERNEL);
- if (!result) {
- pr_err("\nresult alloc fail\n");
+ if (!result)
goto result_fail;
- }
hash_buff = xbuf[0];
@@ -528,6 +556,7 @@ result_fail:
buf_fail:
ahash_request_free(req);
req_fail:
+ kfree(key_mem);
return ret;
}
@@ -537,6 +566,7 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
struct crypto_ahash *tfm;
struct scatterlist sg[1];
char result[64];
+ char algo[64];
struct ahash_request *req;
struct tegra_crypto_completion sha_complete;
void *hash_buff;
@@ -548,17 +578,23 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
return -EINVAL;
}
- tfm = crypto_alloc_ahash(sha_req->algo, 0, 0);
+ if (strncpy_from_user(algo, sha_req->algo, sizeof(algo)) < 0) {
+ ret = -EFAULT;
+ goto out_alloc;
+ }
+ algo[sizeof(algo) - 1] = '\0';
+
+ tfm = crypto_alloc_ahash(algo, 0, 0);
if (IS_ERR(tfm)) {
pr_err("alg:hash:Failed to load transform for %s:%ld\n",
- sha_req->algo, PTR_ERR(tfm));
+ algo, PTR_ERR(tfm));
goto out_alloc;
}
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) {
pr_err("alg:hash:Failed to allocate request for %s\n",
- sha_req->algo);
+ algo);
goto out_noreq;
}
@@ -574,7 +610,14 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
hash_buff = xbuf[0];
- memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz);
+ ret = copy_from_user((void *)hash_buff,
+ (void __user *)sha_req->plaintext,
+ sha_req->plaintext_sz);
+ if (ret) {
+ ret = -EFAULT;
+ pr_err("%s: copy_from_user failed (%d)\n", __func__, ret);
+ goto out;
+ }
sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz);
if (sha_req->keylen) {
@@ -583,7 +626,7 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
sha_req->keylen);
if (ret) {
pr_err("alg:hash:setkey failed on %s:ret=%d\n",
- sha_req->algo, ret);
+ algo, ret);
goto out;
}
@@ -594,21 +637,21 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req));
if (ret) {
pr_err("alg: hash: init failed for %s: ret=%d\n",
- sha_req->algo, ret);
+ algo, ret);
goto out;
}
ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req));
if (ret) {
pr_err("alg: hash: update failed for %s: ret=%d\n",
- sha_req->algo, ret);
+ algo, ret);
goto out;
}
ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req));
if (ret) {
pr_err("alg: hash: final failed for %s: ret=%d\n",
- sha_req->algo, ret);
+ algo, ret);
goto out;
}
@@ -617,7 +660,7 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
if (ret) {
ret = -EFAULT;
pr_err("alg: hash: copy_to_user failed (%d) for %s\n",
- ret, sha_req->algo);
+ ret, algo);
}
out:
@@ -890,6 +933,9 @@ rng_out:
rsa_req.algo);
return -EINVAL;
}
+
+ speculation_barrier();
+
ret = tegra_crypt_rsa(ctx, &rsa_req);
break;
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index bd521b77bc5b..7d7d9feae144 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -182,6 +182,7 @@
#define RP_VEND_XP 0x00000F00
#define RP_VEND_XP_DL_UP (1 << 30)
+#define RP_VEND_XP_UPDATE_FC_THRESHOLD (0xFF << 18)
#define RP_LINK_CONTROL_STATUS 0x00000090
@@ -195,6 +196,13 @@
#define NV_PCIE2_RP_INTR_BCR 0x0000003C
#define NV_PCIE2_RP_INTR_BCR_INTR_LINE (0xFF << 0)
+#define NV_PCIE2_RP_PRIV_XP_DL 0x00000494
+#define PCIE2_RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1FF << 1)
+
+#define NV_PCIE2_RP_RX_HDR_LIMIT 0x00000E00
+#define PCIE2_RP_RX_HDR_LIMIT_PW_MASK (0xFF00)
+#define PCIE2_RP_RX_HDR_LIMIT_PW (0x0E << 8)
+
#define NV_PCIE2_RP_PRIV_MISC 0x00000FE0
#define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
#define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
@@ -1609,6 +1617,19 @@ static void tegra_pcie_apply_sw_war(int index, bool enum_done)
data = rp_readl(NV_PCIE2_RP_INTR_BCR, index);
data |= NV_PCIE2_RP_INTR_BCR_INTR_LINE;
rp_writel(data, NV_PCIE2_RP_INTR_BCR, index);
+ /* WAR for RAW violation on T124/T132 platforms */
+ data = rp_readl(NV_PCIE2_RP_RX_HDR_LIMIT, index);
+ data &= ~PCIE2_RP_RX_HDR_LIMIT_PW_MASK;
+ data |= PCIE2_RP_RX_HDR_LIMIT_PW;
+ rp_writel(data, NV_PCIE2_RP_RX_HDR_LIMIT, index);
+
+ data = rp_readl(NV_PCIE2_RP_PRIV_XP_DL, index);
+ data |= PCIE2_RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD;
+ rp_writel(data, NV_PCIE2_RP_PRIV_XP_DL, index);
+
+ data = rp_readl(RP_VEND_XP, index);
+ data |= RP_VEND_XP_UPDATE_FC_THRESHOLD;
+ rp_writel(data, RP_VEND_XP, index);
}
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index df5e961484e1..47eafb87e038 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -765,8 +765,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return k; /* probably out of space --> ENOMEM */
}
if (sdp->detached) {
- if (srp->bio)
+ if (srp->bio) {
+ if (srp->rq->cmd != srp->rq->__cmd)
+ kfree(srp->rq->cmd);
+
blk_end_request_all(srp->rq, -EIO);
+ srp->rq = NULL;
+ }
+
sg_finish_rem_req(srp);
return -ENODEV;
}
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 551fe2e0bc2d..ec1fb7913f4c 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -269,6 +269,8 @@ static int ion_heap_shrink(struct shrinker *shrinker, struct shrink_control *sc)
{
struct ion_heap *heap = container_of(shrinker, struct ion_heap,
shrinker);
+ if (IS_ERR_OR_NULL(heap))
+ return -EINVAL;
int total = 0;
int freed = 0;
int to_scan = sc->nr_to_scan;
@@ -309,8 +311,9 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
switch (heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
- heap = ion_system_contig_heap_create(heap_data);
- break;
+ pr_err("%s: Heap type is disabled: %d\n", __func__,
+ heap_data->type);
+ return ERR_PTR(-EINVAL);
case ION_HEAP_TYPE_SYSTEM:
heap = ion_system_heap_create(heap_data);
break;
@@ -343,12 +346,13 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
void ion_heap_destroy(struct ion_heap *heap)
{
- if (!heap)
+ if (IS_ERR_OR_NULL(heap))
return;
switch (heap->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
- ion_system_contig_heap_destroy(heap);
+ pr_err("%s: Heap type is disabled: %d\n", __func__,
+ heap->type);
break;
case ION_HEAP_TYPE_SYSTEM:
ion_system_heap_destroy(heap);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index ffb4b9c41a40..68e6e09fdb37 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -944,8 +944,8 @@ thermal_cooling_device_cur_state_store(struct device *dev,
const char *buf, size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int result;
+ unsigned long state, max_state;
+ int result, ret;
if (!sscanf(buf, "%ld\n", &state))
return -EINVAL;
@@ -953,6 +953,13 @@ thermal_cooling_device_cur_state_store(struct device *dev,
if ((long)state < 0)
return -EINVAL;
+ ret = cdev->ops->get_max_state(cdev, &max_state);
+ if (ret)
+ return ret;
+
+ if (state > max_state)
+ return -EINVAL;
+
result = cdev->ops->set_cur_state(cdev, state);
if (result)
return result;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 1afe192bef6a..b5cbe12e2815 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -400,6 +400,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_mutex
*/
@@ -408,6 +412,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
mutex_lock(&tty->termios_mutex);
tty->termios.c_line = num;
mutex_unlock(&tty->termios_mutex);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
diff --git a/drivers/video/tegra/dc/sor.c b/drivers/video/tegra/dc/sor.c
index 1326155cd183..5fee008d122a 100644
--- a/drivers/video/tegra/dc/sor.c
+++ b/drivers/video/tegra/dc/sor.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/sor.c
*
- * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -1287,7 +1287,7 @@ void tegra_dc_sor_enable_lvds(struct tegra_dc_sor_data *sor,
6 << NV_SOR_LVDS_ROTDAT_SHIFT:
0 << NV_SOR_LVDS_ROTDAT_SHIFT);
tegra_sor_writel(sor, NV_SOR_LANE4_DRIVE_CURRENT(sor->portnum),
- 0x40);
+ 0x40);
}
#if 0
diff --git a/drivers/video/tegra/dc/sor_regs.h b/drivers/video/tegra/dc/sor_regs.h
index 8e1cc1c3231c..8080e2925d82 100644
--- a/drivers/video/tegra/dc/sor_regs.h
+++ b/drivers/video/tegra/dc/sor_regs.h
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/sor_regs.h
*
- * Copyright (c) 2011-2013, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION, All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
diff --git a/drivers/video/tegra/host/host1x/host1x.c b/drivers/video/tegra/host/host1x/host1x.c
index 522219484286..6af16bab059c 100644
--- a/drivers/video/tegra/host/host1x/host1x.c
+++ b/drivers/video/tegra/host/host1x/host1x.c
@@ -33,6 +33,8 @@
#include <linux/tegra-soc.h>
#include <linux/tegra_pm_domains.h>
+#include <linux/version.h>
+#include <asm/barrier.h>
#include "dev.h"
#include <trace/events/nvhost.h>
@@ -267,6 +269,8 @@ static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
args->lock > 1)
return -EINVAL;
+ speculation_barrier();
+
trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
if (args->lock && !ctx->mod_locks[args->id]) {
if (args->id == 0)
@@ -379,6 +383,7 @@ static int nvhost_ioctl_ctrl_syncpt_read_max(struct nvhost_ctrl_userctx *ctx,
{
if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt))
return -EINVAL;
+ speculation_barrier();
args->value = nvhost_syncpt_read_max(&ctx->dev->syncpt, args->id);
return 0;
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index b0af8a143bd2..4d431cc14890 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -3,7 +3,7 @@
*
* Tegra Graphics Host Syncpoints
*
- * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2010-2018, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -650,13 +650,18 @@ static ssize_t syncpt_name_show(struct kobject *kobj,
{
struct nvhost_syncpt_attr *syncpt_attr =
container_of(attr, struct nvhost_syncpt_attr, attr);
+ ssize_t count = 0;
if (syncpt_attr->id < 0)
return snprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ mutex_lock(&syncpt_attr->host->syncpt.syncpt_mutex);
+ count = snprintf(buf, PAGE_SIZE, "%s\n",
nvhost_syncpt_get_name(syncpt_attr->host->dev,
syncpt_attr->id));
+ mutex_unlock(&syncpt_attr->host->syncpt.syncpt_mutex);
+
+ return count;
}
static ssize_t syncpt_min_show(struct kobject *kobj,
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 1be3996b5942..3517d5af2574 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -75,8 +75,14 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
ext4_put_nojournal(handle);
return 0;
}
- sb = handle->h_transaction->t_journal->j_private;
+
err = handle->h_err;
+ if (!handle->h_transaction) {
+ rc = jbd2_journal_stop(handle);
+ return err ? err : rc;
+ }
+
+ sb = handle->h_transaction->t_journal->j_private;
rc = jbd2_journal_stop(handle);
if (!err)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 4e5f332f15d9..db7d89cea2ce 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -169,7 +169,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
addr = ALIGN(addr, huge_page_size(h));
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vm_start_gap(vma)))
return addr;
}
diff --git a/fs/ioprio.c b/fs/ioprio.c
index e50170ca7c33..46f0e24f43e9 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -149,8 +149,10 @@ static int get_task_ioprio(struct task_struct *p)
if (ret)
goto out;
ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+ task_lock(p);
if (p->io_context)
ret = p->io_context->ioprio;
+ task_unlock(p);
out:
return ret;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4823113f2584..464df13a1c19 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -46,7 +46,7 @@
* Paul Mundt <paul.mundt@nokia.com>:
* Overall revision about smaps.
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
*/
#include <asm/uaccess.h>
@@ -857,7 +857,8 @@ static ssize_t environ_read(struct file *file, char __user *buf,
int ret = 0;
struct mm_struct *mm = file->private_data;
- if (!mm)
+ /* Ensure the process spawned far enough to have an environment. */
+ if (!mm || !mm->env_end)
return 0;
page = (char *)__get_free_page(GFP_TEMPORARY);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index db17f98bc564..fb705f672960 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -329,11 +329,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
/* We don't show the stack guard page in /proc/maps */
start = vma->vm_start;
- if (stack_guard_page_start(vma, start))
- start += PAGE_SIZE;
end = vma->vm_end;
- if (stack_guard_page_end(vma, end))
- end -= PAGE_SIZE;
seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
start,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 03a60a38ec45..9d572d445e3e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1066,34 +1066,6 @@ int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
-/* Is the vma a continuation of the stack vma above it? */
-static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
-{
- return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN);
-}
-
-static inline int stack_guard_page_start(struct vm_area_struct *vma,
- unsigned long addr)
-{
- return (vma->vm_flags & VM_GROWSDOWN) &&
- (vma->vm_start == addr) &&
- !vma_growsdown(vma->vm_prev, addr);
-}
-
-/* Is the vma a continuation of the stack vma below it? */
-static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr)
-{
- return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP);
-}
-
-static inline int stack_guard_page_end(struct vm_area_struct *vma,
- unsigned long addr)
-{
- return (vma->vm_flags & VM_GROWSUP) &&
- (vma->vm_end == addr) &&
- !vma_growsup(vma->vm_next, addr);
-}
-
extern pid_t
vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group);
@@ -1620,6 +1592,7 @@ unsigned long ra_submit(struct file_ra_state *ra,
struct address_space *mapping,
struct file *filp);
+extern unsigned long stack_guard_gap;
/* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
@@ -1648,6 +1621,30 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m
return vma;
}
+static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
+{
+ unsigned long vm_start = vma->vm_start;
+
+ if (vma->vm_flags & VM_GROWSDOWN) {
+ vm_start -= stack_guard_gap;
+ if (vm_start > vma->vm_start)
+ vm_start = 0;
+ }
+ return vm_start;
+}
+
+static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
+{
+ unsigned long vm_end = vma->vm_end;
+
+ if (vma->vm_flags & VM_GROWSUP) {
+ vm_end += stack_guard_gap;
+ if (vm_end < vma->vm_end)
+ vm_end = -PAGE_SIZE;
+ }
+ return vm_end;
+}
+
static inline unsigned long vma_pages(struct vm_area_struct *vma)
{
return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
new file mode 100644
index 000000000000..b99bced39ac2
--- /dev/null
+++ b/include/linux/nospec.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set. Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+ unsigned long size)
+{
+ /*
+ * Warn developers about inappropriate array_index_nospec() usage.
+ *
+ * Even if the CPU speculates past the WARN_ONCE branch, the
+ * sign bit of @index is taken into account when generating the
+ * mask.
+ *
+ * This warning is compiled out when the compiler can infer that
+ * @index and @size are less than LONG_MAX.
+ */
+ if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX,
+ "array_index_nospec() limited to range of [0, LONG_MAX]\n"))
+ return 0;
+
+ /*
+ * Always calculate and emit the mask even if the compiler
+ * thinks the mask is not needed. The compiler does not take
+ * into account the value of @index under speculation.
+ */
+ OPTIMIZER_HIDE_VAR(index);
+ return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ * if (index < size) {
+ * index = array_index_nospec(index, size);
+ * val = array[index];
+ * }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size) \
+({ \
+ typeof(index) _i = (index); \
+ typeof(size) _s = (size); \
+ unsigned long _mask = array_index_mask_nospec(_i, _s); \
+ \
+ BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \
+ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \
+ \
+ _i &= _mask; \
+ _i; \
+})
+#endif /* _LINUX_NOSPEC_H */
diff --git a/include/linux/nvhost_ioctl.h b/include/linux/nvhost_ioctl.h
index a1011e5a1daf..b060864ff1d1 100644
--- a/include/linux/nvhost_ioctl.h
+++ b/include/linux/nvhost_ioctl.h
@@ -3,7 +3,7 @@
*
* Tegra graphics host driver
*
- * Copyright (c) 2009-2017, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2009-2014, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -118,6 +118,10 @@ struct nvhost_alloc_obj_ctx_args {
__u64 obj_id; /* output, used to free later */
};
+struct nvhost_free_obj_ctx_args {
+ __u64 obj_id; /* obj ctx to free */
+};
+
struct nvhost_alloc_gpfifo_args {
__u32 num_entries;
#define NVHOST_ALLOC_GPFIFO_FLAGS_VPR_ENABLED (1 << 0) /* set owner channel of this gpfifo as a vpr channel */
@@ -386,6 +390,8 @@ struct nvhost_set_ctxswitch_args {
_IOWR(NVHOST_IOCTL_MAGIC, 107, struct nvhost_submit_gpfifo_args)
#define NVHOST_IOCTL_CHANNEL_ALLOC_OBJ_CTX \
_IOWR(NVHOST_IOCTL_MAGIC, 108, struct nvhost_alloc_obj_ctx_args)
+#define NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX \
+ _IOR(NVHOST_IOCTL_MAGIC, 109, struct nvhost_free_obj_ctx_args)
#define NVHOST_IOCTL_CHANNEL_ZCULL_BIND \
_IOWR(NVHOST_IOCTL_MAGIC, 110, struct nvhost_zcull_bind_args)
#define NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER \
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 13f12c10f03b..013daf1494ba 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1392,6 +1392,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
{
if (sk->sk_send_head == skb_unlinked)
sk->sk_send_head = NULL;
+ if (tcp_sk(sk)->highest_sack == skb_unlinked)
+ tcp_sk(sk)->highest_sack = NULL;
}
static inline void tcp_init_send_head(struct sock *sk)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 9845cb32b60a..04a257b4a2da 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -68,6 +68,7 @@
#include <linux/capability.h>
#include <linux/fs_struct.h>
#include <linux/compat.h>
+#include <linux/uaccess.h>
#include "audit.h"
@@ -76,7 +77,8 @@
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
-/* no execve audit message should be longer than this (userspace limits) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
#define MAX_EXECVE_AUDIT_LEN 7500
/* number of audit rules */
@@ -1001,189 +1003,184 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
return rc;
}
-/*
- * to_send and len_sent accounting are very loose estimates. We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf? an int is up to 12 digits long. if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message. In one 7500 byte message we can log up to
- * about 1000 min size arguments. That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
- struct audit_buffer **ab,
- int arg_num,
- size_t *len_sent,
- const char __user *p,
- char *buf)
+static void audit_log_execve_info(struct audit_context *context,
+ struct audit_buffer **ab,
+ struct audit_aux_data_execve *axi)
{
- char arg_num_len_buf[12];
- const char __user *tmp_p = p;
- /* how many digits are in arg_num? 5 is the length of ' a=""' */
- size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
- size_t len, len_left, to_send;
- size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
- unsigned int i, has_cntl = 0, too_long = 0;
- int ret;
-
- /* strnlen_user includes the null we don't want to send */
- len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+ long len_max;
+ long len_rem;
+ long len_full;
+ long len_buf;
+ long len_abuf;
+ long len_tmp;
+ bool require_data;
+ bool encode;
+ unsigned int iter;
+ unsigned int arg;
+ char *buf_head;
+ char *buf;
+ const char __user *p;
- /*
- * We just created this mm, if we can't find the strings
- * we just copied into it something is _very_ wrong. Similar
- * for strings that are too long, we should not have created
- * any.
- */
- if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
+ /* NOTE: this buffer needs to be large enough to hold all the non-arg
+ * data we put in the audit record for this argument (see the
+ * code below) ... at this point in time 96 is plenty */
+ char abuf[96];
+
+ if (axi->mm != current->mm)
+ return; /* execve failed, no additional info */
+
+ p = (const char __user *)axi->mm->arg_start;
+
+ /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+ * current value of 7500 is not as important as the fact that it
+ * is less than 8k, a setting of 7500 gives us plenty of wiggle
+ * room if we go over a little bit in the logging below */
+ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+ len_max = MAX_EXECVE_AUDIT_LEN;
+
+ /* scratch buffer to hold the userspace args */
+ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+ if (!buf_head) {
+ audit_panic("out of memory for argv string");
+ return;
}
+ buf = buf_head;
+
+ audit_log_format(*ab, "argc=%d", axi->argc);
- /* walk the whole argument looking for non-ascii chars */
+ len_rem = len_max;
+ len_buf = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ iter = 0;
+ arg = 0;
do {
- if (len_left > MAX_EXECVE_AUDIT_LEN)
- to_send = MAX_EXECVE_AUDIT_LEN;
- else
- to_send = len_left;
- ret = copy_from_user(buf, tmp_p, to_send);
- /*
- * There is no reason for this copy to be short. We just
- * copied them here, and the mm hasn't been exposed to user-
- * space yet.
- */
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
- }
- buf[to_send] = '\0';
- has_cntl = audit_string_contains_control(buf, to_send);
- if (has_cntl) {
- /*
- * hex messages get logged as 2 bytes, so we can only
- * send half as much in each message
- */
- max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
- break;
- }
- len_left -= to_send;
- tmp_p += to_send;
- } while (len_left > 0);
-
- len_left = len;
-
- if (len > max_execve_audit_len)
- too_long = 1;
-
- /* rewalk the argument actually logging the message */
- for (i = 0; len_left > 0; i++) {
- int room_left;
-
- if (len_left > max_execve_audit_len)
- to_send = max_execve_audit_len;
- else
- to_send = len_left;
-
- /* do we have space left to send this argument in this ab? */
- room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
- if (has_cntl)
- room_left -= (to_send * 2);
- else
- room_left -= to_send;
- if (room_left < 0) {
- *len_sent = 0;
- audit_log_end(*ab);
- *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
- if (!*ab)
- return 0;
- }
+ /* NOTE: we don't ever want to trust this value for anything
+ * serious, but the audit record format insists we
+ * provide an argument length for really long arguments,
+ * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+ * to use strncpy_from_user() to obtain this value for
+ * recording in the log, although we don't use it
+ * anywhere here to avoid a double-fetch problem */
+ if (len_full == 0)
+ len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+ /* read more data from userspace */
+ if (require_data) {
+ /* can we make more room in the buffer? */
+ if (buf != buf_head) {
+ memmove(buf_head, buf, len_buf);
+ buf = buf_head;
+ }
- /*
- * first record needs to say how long the original string was
- * so we can be sure nothing was lost.
- */
- if ((i == 0) && (too_long))
- audit_log_format(*ab, " a%d_len=%zu", arg_num,
- has_cntl ? 2*len : len);
-
- /*
- * normally arguments are small enough to fit and we already
- * filled buf above when we checked for control characters
- * so don't bother with another copy_from_user
- */
- if (len >= max_execve_audit_len)
- ret = copy_from_user(buf, p, to_send);
- else
- ret = 0;
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
- }
- buf[to_send] = '\0';
-
- /* actually log it */
- audit_log_format(*ab, " a%d", arg_num);
- if (too_long)
- audit_log_format(*ab, "[%d]", i);
- audit_log_format(*ab, "=");
- if (has_cntl)
- audit_log_n_hex(*ab, buf, to_send);
- else
- audit_log_string(*ab, buf);
-
- p += to_send;
- len_left -= to_send;
- *len_sent += arg_num_len;
- if (has_cntl)
- *len_sent += to_send * 2;
- else
- *len_sent += to_send;
- }
- /* include the null we didn't log */
- return len + 1;
-}
+ /* fetch as much as we can of the argument */
+ len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+ len_max - len_buf);
+ if (len_tmp == -EFAULT) {
+ /* unable to copy from userspace */
+ send_sig(SIGKILL, current, 0);
+ goto out;
+ } else if (len_tmp == (len_max - len_buf)) {
+ /* buffer is not large enough */
+ require_data = true;
+ /* NOTE: if we are going to span multiple
+ * buffers force the encoding so we stand
+ * a chance at a sane len_full value and
+ * consistent record encoding */
+ encode = true;
+ len_full = len_full * 2;
+ p += len_tmp;
+ } else {
+ require_data = false;
+ if (!encode)
+ encode = audit_string_contains_control(
+ buf, len_tmp);
+ /* try to use a trusted value for len_full */
+ if (len_full < len_max)
+ len_full = (encode ?
+ len_tmp * 2 : len_tmp);
+ p += len_tmp + 1;
+ }
+ len_buf += len_tmp;
+ buf_head[len_buf] = '\0';
-static void audit_log_execve_info(struct audit_context *context,
- struct audit_buffer **ab,
- struct audit_aux_data_execve *axi)
-{
- int i, len;
- size_t len_sent = 0;
- const char __user *p;
- char *buf;
+ /* length of the buffer in the audit record? */
+ len_abuf = (encode ? len_buf * 2 : len_buf + 2);
+ }
- if (axi->mm != current->mm)
- return; /* execve failed, no additional info */
+ /* write as much as we can to the audit log */
+ if (len_buf > 0) {
+ /* NOTE: some magic numbers here - basically if we
+ * can't fit a reasonable amount of data into the
+ * existing audit buffer, flush it and start with
+ * a new buffer */
+ if ((sizeof(abuf) + 8) > len_rem) {
+ len_rem = len_max;
+ audit_log_end(*ab);
+ *ab = audit_log_start(context,
+ GFP_KERNEL, AUDIT_EXECVE);
+ if (!*ab)
+ goto out;
+ }
- p = (const char __user *)axi->mm->arg_start;
+ /* create the non-arg portion of the arg record */
+ len_tmp = 0;
+ if (require_data || (iter > 0) ||
+ ((len_abuf + sizeof(abuf)) > len_rem)) {
+ if (iter == 0) {
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d_len=%lu",
+ arg, len_full);
+ }
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d[%d]=", arg, iter++);
+ } else
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d=", arg);
+ WARN_ON(len_tmp >= sizeof(abuf));
+ abuf[sizeof(abuf) - 1] = '\0';
+
+ /* log the arg in the audit record */
+ audit_log_format(*ab, "%s", abuf);
+ len_rem -= len_tmp;
+ len_tmp = len_buf;
+ if (encode) {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem / 2; /* encoding */
+ audit_log_n_hex(*ab, buf, len_tmp);
+ len_rem -= len_tmp * 2;
+ len_abuf -= len_tmp * 2;
+ } else {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem - 2; /* quotes */
+ audit_log_n_string(*ab, buf, len_tmp);
+ len_rem -= len_tmp + 2;
+ /* don't subtract the "2" because we still need
+ * to add quotes to the remaining string */
+ len_abuf -= len_tmp;
+ }
+ len_buf -= len_tmp;
+ buf += len_tmp;
+ }
- audit_log_format(*ab, "argc=%d", axi->argc);
+ /* ready to move to the next argument? */
+ if ((len_buf == 0) && !require_data) {
+ arg++;
+ iter = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ }
+ } while (arg < axi->argc);
- /*
- * we need some kernel buffer to hold the userspace args. Just
- * allocate one big one rather than allocating one of the right size
- * for every single argument inside audit_log_single_execve_arg()
- * should be <8k allocation so should be pretty safe.
- */
- buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
- if (!buf) {
- audit_panic("out of memory for argv string\n");
- return;
- }
+ /* NOTE: the caller handles the final audit_log_end() call */
- for (i = 0; i < axi->argc; i++) {
- len = audit_log_single_execve_arg(context, ab, i,
- &len_sent, p, buf);
- if (len <= 0)
- break;
- p += len;
- }
- kfree(buf);
+out:
+ kfree(buf_head);
}
static void show_special(struct audit_context *context, int *call_panic)
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 05b36e7b9e6b..1e2c3588b990 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -5449,7 +5449,7 @@ static int cgroup_css_links_read(struct cgroup *cont,
struct css_set *cg = link->cg;
struct task_struct *task;
int count = 0;
- seq_printf(seq, "css_set %p\n", cg);
+ seq_printf(seq, "css_set %pK\n", cg);
list_for_each_entry(task, &cg->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS) {
seq_puts(seq, " ...\n");
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f8eb2b154bdb..be3b4cc87eeb 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7450,13 +7450,7 @@ static void perf_event_exit_cpu_context(int cpu)
static void perf_event_exit_cpu(int cpu)
{
- struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
-
perf_event_exit_cpu_context(cpu);
-
- mutex_lock(&swhash->hlist_mutex);
- swevent_hlist_release(swhash);
- mutex_unlock(&swhash->hlist_mutex);
}
#else
static inline void perf_event_exit_cpu(int cpu) { }
diff --git a/mm/memory.c b/mm/memory.c
index 6be9914ddc0d..17c9186c819a 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1659,12 +1659,6 @@ no_page_table:
return page;
}
-static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr)
-{
- return stack_guard_page_start(vma, addr) ||
- stack_guard_page_end(vma, addr+PAGE_SIZE);
-}
-
/**
* replace_cma_page() - migrate page out of CMA page blocks
* @page: source page to be migrated
@@ -1875,10 +1869,6 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
fault_flags = FAULT_FLAG_NO_CMA;
/* For mlock, just skip the stack guard page. */
- if (foll_flags & FOLL_MLOCK) {
- if (stack_guard_page(vma, start))
- goto next_page;
- }
if (foll_flags & FOLL_WRITE)
fault_flags |= FAULT_FLAG_WRITE;
if (nonblocking)
@@ -3171,40 +3161,6 @@ out_release:
return ret;
}
-/*
- * This is like a special single-page "expand_{down|up}wards()",
- * except we must first make sure that 'address{-|+}PAGE_SIZE'
- * doesn't hit another vma.
- */
-static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) {
- struct vm_area_struct *prev = vma->vm_prev;
-
- /*
- * Is there a mapping abutting this one below?
- *
- * That's only ok if it's the same stack mapping
- * that has gotten split..
- */
- if (prev && prev->vm_end == address)
- return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
-
- expand_downwards(vma, address - PAGE_SIZE);
- }
- if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
- struct vm_area_struct *next = vma->vm_next;
-
- /* As VM_GROWSDOWN but s/below/above/ */
- if (next && next->vm_start == address + PAGE_SIZE)
- return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
-
- expand_upwards(vma, address + PAGE_SIZE);
- }
- return 0;
-}
-
bool is_vma_temporary_stack(struct vm_area_struct *vma);
/*
* We enter with non-exclusive mmap_sem (to exclude vma changes,
@@ -3221,10 +3177,6 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
pte_unmap(page_table);
- /* Check if we need to add a guard page to the stack */
- if (check_stack_guard_page(vma, address) < 0)
- return VM_FAULT_SIGBUS;
-
/* Use the zero-page for reads */
if (!(flags & FAULT_FLAG_WRITE)) {
entry = pte_mkspecial(pfn_pte(my_zero_pfn(address),
diff --git a/mm/mmap.c b/mm/mmap.c
index e0a152e2dc10..a323e12f8a6d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -264,6 +264,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
unsigned long rlim, retval;
unsigned long newbrk, oldbrk;
struct mm_struct *mm = current->mm;
+ struct vm_area_struct *next;
unsigned long min_brk;
bool populate;
@@ -309,7 +310,8 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
}
/* Check against existing mmap mappings. */
- if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
+ next = find_vma(mm, oldbrk);
+ if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
goto out;
/* Ok, looks good - let it rip. */
@@ -332,10 +334,22 @@ out:
static long vma_compute_subtree_gap(struct vm_area_struct *vma)
{
- unsigned long max, subtree_gap;
- max = vma->vm_start;
- if (vma->vm_prev)
- max -= vma->vm_prev->vm_end;
+ unsigned long max, prev_end, subtree_gap;
+
+ /*
+ * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we
+ * allow two stack_guard_gaps between them here, and when choosing
+ * an unmapped area; whereas when expanding we only require one.
+ * That's a little inconsistent, but keeps the code here simpler.
+ */
+ max = vm_start_gap(vma);
+ if (vma->vm_prev) {
+ prev_end = vm_end_gap(vma->vm_prev);
+ if (max > prev_end)
+ max -= prev_end;
+ else
+ max = 0;
+ }
if (vma->vm_rb.rb_left) {
subtree_gap = rb_entry(vma->vm_rb.rb_left,
struct vm_area_struct, vm_rb)->rb_subtree_gap;
@@ -419,7 +433,7 @@ void validate_mm(struct mm_struct *mm)
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
anon_vma_interval_tree_verify(avc);
vma_unlock_anon_vma(vma);
- highest_address = vma->vm_end;
+ highest_address = vm_end_gap(vma);
vma = vma->vm_next;
i++;
}
@@ -587,7 +601,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
if (vma->vm_next)
vma_gap_update(vma->vm_next);
else
- mm->highest_vm_end = vma->vm_end;
+ mm->highest_vm_end = vm_end_gap(vma);
/*
* vma->vm_prev wasn't known when we followed the rbtree to find the
@@ -836,7 +850,7 @@ again: remove_next = 1 + (end > next->vm_end);
vma_gap_update(vma);
if (end_changed) {
if (!next)
- mm->highest_vm_end = end;
+ mm->highest_vm_end = vm_end_gap(vma);
else if (!adjust_next)
vma_gap_update(next);
}
@@ -879,7 +893,7 @@ again: remove_next = 1 + (end > next->vm_end);
else if (next)
vma_gap_update(next);
else
- mm->highest_vm_end = end;
+ mm->highest_vm_end = vm_end_gap(vma);
}
if (insert && file)
uprobe_mmap(insert);
@@ -1679,7 +1693,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info)
while (true) {
/* Visit left subtree if it looks promising */
- gap_end = vma->vm_start;
+ gap_end = vm_start_gap(vma);
if (gap_end >= low_limit && vma->vm_rb.rb_left) {
struct vm_area_struct *left =
rb_entry(vma->vm_rb.rb_left,
@@ -1690,7 +1704,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info)
}
}
- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
check_current:
/* Check if current node has a suitable gap */
if (gap_start > high_limit)
@@ -1717,8 +1731,8 @@ check_current:
vma = rb_entry(rb_parent(prev),
struct vm_area_struct, vm_rb);
if (prev == vma->vm_rb.rb_left) {
- gap_start = vma->vm_prev->vm_end;
- gap_end = vma->vm_start;
+ gap_start = vm_end_gap(vma->vm_prev);
+ gap_end = vm_start_gap(vma);
goto check_current;
}
}
@@ -1782,7 +1796,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
while (true) {
/* Visit right subtree if it looks promising */
- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
if (gap_start <= high_limit && vma->vm_rb.rb_right) {
struct vm_area_struct *right =
rb_entry(vma->vm_rb.rb_right,
@@ -1795,7 +1809,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
check_current:
/* Check if current node has a suitable gap */
- gap_end = vma->vm_start;
+ gap_end = vm_start_gap(vma);
if (gap_end < low_limit)
return -ENOMEM;
if (gap_start <= high_limit && gap_end - gap_start >= length)
@@ -1821,7 +1835,7 @@ check_current:
struct vm_area_struct, vm_rb);
if (prev == vma->vm_rb.rb_right) {
gap_start = vma->vm_prev ?
- vma->vm_prev->vm_end : 0;
+ vm_end_gap(vma->vm_prev) : 0;
goto check_current;
}
}
@@ -1859,7 +1873,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
+ struct vm_area_struct *vma, *prev;
struct vm_unmapped_area_info info;
if (len > TASK_SIZE - mmap_min_addr)
@@ -1870,9 +1884,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (addr) {
addr = PAGE_ALIGN(addr);
- vma = find_vma(mm, addr);
+ vma = find_vma_prev(mm, addr, &prev);
if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vm_start_gap(vma)) &&
+ (!prev || addr >= vm_end_gap(prev)))
return addr;
}
@@ -1904,7 +1919,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
const unsigned long len, const unsigned long pgoff,
const unsigned long flags)
{
- struct vm_area_struct *vma;
+ struct vm_area_struct *vma, *prev;
struct mm_struct *mm = current->mm;
unsigned long addr = addr0;
struct vm_unmapped_area_info info;
@@ -1919,9 +1934,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
/* requesting a specific address */
if (addr) {
addr = PAGE_ALIGN(addr);
- vma = find_vma(mm, addr);
+ vma = find_vma_prev(mm, addr, &prev);
if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vm_start_gap(vma)) &&
+ (!prev || addr >= vm_end_gap(prev)))
return addr;
}
@@ -2061,7 +2077,8 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr,
* update accounting. This is shared with both the
* grow-up and grow-down cases.
*/
-static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow)
+static int acct_stack_growth(struct vm_area_struct *vma,
+ unsigned long size, unsigned long grow)
{
struct mm_struct *mm = vma->vm_mm;
struct rlimit *rlim = current->signal->rlim;
@@ -2114,6 +2131,8 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
int expand_upwards(struct vm_area_struct *vma, unsigned long address)
{
int error;
+ struct vm_area_struct *next;
+ unsigned long gap_addr;
if (!(vma->vm_flags & VM_GROWSUP))
return -EFAULT;
@@ -2124,8 +2143,19 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
*/
if (unlikely(anon_vma_prepare(vma)))
return -ENOMEM;
- vma_lock_anon_vma(vma);
+ /* Enforce stack_guard_gap */
+ gap_addr = address + stack_guard_gap;
+ if (gap_addr < address)
+ return -ENOMEM;
+ next = vma->vm_next;
+ if (next && next->vm_start < gap_addr) {
+ if (!(next->vm_flags & VM_GROWSUP))
+ return -ENOMEM;
+ /* Check that both stack segments have the same anon_vma? */
+ }
+
+ vma_lock_anon_vma(vma);
/*
* vma->vm_start/vm_end cannot change under us because the caller
* is required to hold the mmap_sem in read mode. We need the
@@ -2169,7 +2199,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
if (vma->vm_next)
vma_gap_update(vma->vm_next);
else
- vma->vm_mm->highest_vm_end = address;
+ vma->vm_mm->highest_vm_end = vm_end_gap(vma);
spin_unlock(&vma->vm_mm->page_table_lock);
perf_event_mmap(vma);
@@ -2190,6 +2220,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
int expand_downwards(struct vm_area_struct *vma,
unsigned long address)
{
+ struct vm_area_struct *prev;
+ unsigned long gap_addr;
int error;
/*
@@ -2204,6 +2236,17 @@ int expand_downwards(struct vm_area_struct *vma,
if (error)
return error;
+ /* Enforce stack_guard_gap */
+ gap_addr = address - stack_guard_gap;
+ if (gap_addr > address)
+ return -ENOMEM;
+ prev = vma->vm_prev;
+ if (prev && prev->vm_end > gap_addr) {
+ if (!(prev->vm_flags & VM_GROWSDOWN))
+ return -ENOMEM;
+ /* Check that both stack segments have the same anon_vma? */
+ }
+
vma_lock_anon_vma(vma);
/*
@@ -2253,28 +2296,25 @@ int expand_downwards(struct vm_area_struct *vma,
return error;
}
-/*
- * Note how expand_stack() refuses to expand the stack all the way to
- * abut the next virtual mapping, *unless* that mapping itself is also
- * a stack mapping. We want to leave room for a guard page, after all
- * (the guard page itself is not added here, that is done by the
- * actual page faulting logic)
- *
- * This matches the behavior of the guard page logic (see mm/memory.c:
- * check_stack_guard_page()), which only allows the guard page to be
- * removed under these circumstances.
- */
+/* enforced gap between the expanding stack and other mappings. */
+unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
+
+static int __init cmdline_parse_stack_guard_gap(char *p)
+{
+ unsigned long val;
+ char *endptr;
+
+ val = simple_strtoul(p, &endptr, 10);
+ if (!*endptr)
+ stack_guard_gap = val << PAGE_SHIFT;
+
+ return 0;
+}
+__setup("stack_guard_gap=", cmdline_parse_stack_guard_gap);
+
#ifdef CONFIG_STACK_GROWSUP
int expand_stack(struct vm_area_struct *vma, unsigned long address)
{
- struct vm_area_struct *next;
-
- address &= PAGE_MASK;
- next = vma->vm_next;
- if (next && next->vm_start == address + PAGE_SIZE) {
- if (!(next->vm_flags & VM_GROWSUP))
- return -ENOMEM;
- }
return expand_upwards(vma, address);
}
@@ -2400,7 +2440,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
vma->vm_prev = prev;
vma_gap_update(vma);
} else
- mm->highest_vm_end = prev ? prev->vm_end : 0;
+ mm->highest_vm_end = prev ? vm_end_gap(prev) : 0;
tail_vma->vm_next = NULL;
if (mm->unmap_area == arch_unmap_area)
addr = prev ? prev->vm_end : mm->mmap_base;
diff --git a/sound/soc/tegra/tegra30_avp.c b/sound/soc/tegra/tegra30_avp.c
index 44d954561f96..a074e25614d1 100644
--- a/sound/soc/tegra/tegra30_avp.c
+++ b/sound/soc/tegra/tegra30_avp.c
@@ -256,7 +256,7 @@ static int tegra30_avp_load_ucode(void)
struct audio_engine_data *audio_engine;
const struct firmware *ucode_fw;
const struct tegra30_avp_ucode_desc *ucode_desc;
- int ucode_size = 0, ucode_offset = 0, total_ucode_size = 0;
+ ssize_t ucode_size = 0, ucode_offset = 0, total_ucode_size = 0;
int i, ret = 0;
dev_vdbg(audio_avp->dev, "%s", __func__);
@@ -296,13 +296,14 @@ static int tegra30_avp_load_ucode(void)
}
ucode_size = ucode_fw->size;
- if (ucode_size <= 0) {
+ if (ucode_size <= 0 ||
+ ucode_size > avp_ucode_desc[i].max_mem_size) {
dev_err(audio_avp->dev, "Invalid ucode size.");
ret = -EINVAL;
release_firmware(ucode_fw);
goto err_param_mem_free;
}
- dev_vdbg(audio_avp->dev, "%s ucode size = %d bytes",
+ dev_vdbg(audio_avp->dev, "%s ucode size = %zd bytes",
ucode_desc->bin_name, ucode_size);
/* Read ucode */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 3879eae7e874..a72bfeee6de2 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -136,6 +136,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
snd_printk(KERN_ERR "cannot memdup\n");
return -ENOMEM;
}
+ INIT_LIST_HEAD(&fp->list);
if (fp->nr_rates > MAX_NR_RATES) {
kfree(fp);
return -EINVAL;
@@ -154,15 +155,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
- kfree(fp);
- kfree(rate_table);
- return err;
+ goto error;
}
if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
fp->altset_idx >= iface->num_altsetting) {
- kfree(fp);
- kfree(rate_table);
- return -EINVAL;
+ err = -EINVAL;
+ goto error;
}
alts = &iface->altsetting[fp->altset_idx];
if (fp->datainterval == 0)
@@ -173,6 +171,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
snd_usb_init_pitch(chip, fp->iface, alts, fp);
snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max);
return 0;
+error:
+ list_del(&fp->list); /* unlink for avoiding double-free */
+ kfree(fp);
+ kfree(rate_table);
+ return err;
}
/*
@@ -239,6 +242,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
fp->datainterval = 0;
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+ INIT_LIST_HEAD(&fp->list);
switch (fp->maxpacksize) {
case 0x120:
@@ -262,6 +266,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
+ list_del(&fp->list); /* unlink for avoiding double-free */
kfree(fp);
return err;
}
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 5b6f7a027c6a..7ddf4a437e4a 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -307,7 +307,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
/*
* add this endpoint to the chip instance.
* if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream.
+ * if not, create a new pcm stream. note, fp is added to the substream
+ * fmt_list and will be freed on the chip instance release. do not free
+ * fp or do remove it from the substream fmt_list to avoid double-free.
*/
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
@@ -755,6 +757,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
fp->clock = clock;
fp->chmap = convert_chmap(num_channels, chconfig, protocol);
+ INIT_LIST_HEAD(&fp->list);
/* some quirks for attributes here */
@@ -799,6 +802,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
+ list_del(&fp->list); /* unlink for avoiding double-free */
kfree(fp->rate_table);
kfree(fp->chmap);
kfree(fp);