summaryrefslogtreecommitdiff
authorJiamin Ma <jiamin.ma@amlogic.com>2019-04-30 08:07:17 (GMT)
committer Jianxin Pan <jianxin.pan@amlogic.com>2019-06-18 05:36:36 (GMT)
commit35ffe6082ff7474ce19b11690dc31d3920401d46 (patch)
tree23dff6ef32fe5105aa8fb9acee94536c1da42a51
parentb0c30ab5a4cd0c1af4b9e7385f3c38333905fc77 (diff)
downloadcommon-35ffe6082ff7474ce19b11690dc31d3920401d46.zip
common-35ffe6082ff7474ce19b11690dc31d3920401d46.tar.gz
common-35ffe6082ff7474ce19b11690dc31d3920401d46.tar.bz2
debug: add more strict checking for show_regs [2/2]
PD#SWPL-7711 Problem: Executing echo l > /proc/sysrq-trigger each 5 seconds for about 15 minius will trigger hardlockup Solution: Add more strict checking for show_regs to filter out addresses in secure monitor region and ioremap region, deferencing which triggers external abort on none-linefetch, and finally leading to hardlockup Verify: Locally pass on U200 Change-Id: I6bd219e7dc3ad29904e6bd1b7d2f4cfb3928d8ed Signed-off-by: Jiamin Ma <jiamin.ma@amlogic.com>
Diffstat
-rw-r--r--arch/arm/kernel/process.c32
-rw-r--r--arch/arm64/kernel/process.c25
-rw-r--r--drivers/amlogic/secmon/secmon.c16
-rw-r--r--drivers/tty/sysrq.c7
-rw-r--r--include/linux/amlogic/secmon.h2
-rw-r--r--lib/nmi_backtrace.c10
-rw-r--r--mm/vmalloc.c4
7 files changed, 89 insertions, 7 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c0c1730..7468ede 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -47,6 +47,10 @@ unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
+#ifdef CONFIG_AMLOGIC_MODIFY
+#include <linux/amlogic/secmon.h>
+#endif
+
static const char *processor_modes[] __maybe_unused = {
"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
"UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
@@ -119,6 +123,34 @@ static void show_data(unsigned long addr, int nbytes, const char *name)
if (addr < PAGE_OFFSET || addr > -256UL)
return;
+#ifdef CONFIG_AMLOGIC_MODIFY
+ /*
+ * Treating data in general purpose register as an address
+ * and dereferencing it is quite a dangerous behaviour,
+ * especially when it is an address belonging to secure
+ * region or ioremap region, which can lead to external
+ * abort on non-linefetch and can not be protected by
+ * probe_kernel_address.
+ * We need more strict filtering rules
+ */
+
+#ifdef CONFIG_AMLOGIC_SEC
+ /*
+ * filter out secure monitor region
+ */
+ if (addr <= (unsigned long)high_memory)
+ if (within_secmon_region(addr))
+ return;
+#endif
+
+ /*
+ * filter out ioremap region
+ */
+ if ((addr >= VMALLOC_START) && (addr <= VMALLOC_END))
+ if (!pfn_valid(vmalloc_to_pfn((void *)addr)))
+ return;
+#endif
+
printk("\n%s: %#lx:\n", name, addr);
/*
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 7f377c1..517bec0 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -62,6 +62,10 @@ unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
+#ifdef CONFIG_AMLOGIC_MODIFY
+#include <linux/amlogic/secmon.h>
+#endif
+
/*
* Function pointers to optional machine specific functions
*/
@@ -195,6 +199,27 @@ static void show_data(unsigned long addr, int nbytes, const char *name)
if (addr < PAGE_OFFSET || addr > -256UL)
return;
+#ifdef CONFIG_AMLOGIC_MODIFY
+ /*
+ * Treating data in general purpose register as an address
+ * and dereferencing it is quite a dangerous behaviour,
+ * especially when it belongs to secure monotor region or
+ * ioremap region(for arm64 vmalloc region is already filtered
+ * out), which can lead to external abort on non-linefetch and
+ * can not be protected by probe_kernel_address.
+ * We need more strict filtering rules
+ */
+
+#ifdef CONFIG_AMLOGIC_SEC
+ /*
+ * filter out secure monitor region
+ */
+ if (addr <= (unsigned long)high_memory)
+ if (within_secmon_region(addr))
+ return;
+#endif
+#endif
+
printk("\n%s: %#lx:\n", name, addr);
/*
diff --git a/drivers/amlogic/secmon/secmon.c b/drivers/amlogic/secmon/secmon.c
index 36ce744..87a2ce9 100644
--- a/drivers/amlogic/secmon/secmon.c
+++ b/drivers/amlogic/secmon/secmon.c
@@ -35,6 +35,8 @@ static void __iomem *sharemem_in_base;
static void __iomem *sharemem_out_base;
static long phy_in_base;
static long phy_out_base;
+static unsigned long secmon_start_virt;
+
#ifdef CONFIG_ARM64
#define IN_SIZE 0x1000
#else
@@ -55,6 +57,19 @@ static long get_sharemem_info(unsigned int function_id)
}
#define RESERVE_MEM_SIZE 0x300000
+
+int within_secmon_region(unsigned long addr)
+{
+ if (!secmon_start_virt)
+ return 0;
+
+ if ((addr >= secmon_start_virt) &&
+ (addr <= (secmon_start_virt + RESERVE_MEM_SIZE)))
+ return 1;
+
+ return 0;
+}
+
static int secmon_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -87,6 +102,7 @@ static int secmon_probe(struct platform_device *pdev)
return -ENOMEM;
}
pr_info("get page:%p, %lx\n", page, page_to_pfn(page));
+ secmon_start_virt = (unsigned long)page_to_virt(page);
if (pfn_valid(__phys_to_pfn(phy_in_base)))
sharemem_in_base = (void __iomem *)__phys_to_virt(phy_in_base);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 649d930..359fbd5 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -258,13 +258,6 @@ static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
static void sysrq_handle_showallcpus(int key)
{
/*
- * Temporarily disable this function
- * Remove it later
- */
-#ifdef CONFIG_AMLOGIC_MODIFY
- return;
-#endif
- /*
* Fall back to the workqueue based printing if the
* backtrace printing did not succeed or the
* architecture has no support for it:
diff --git a/include/linux/amlogic/secmon.h b/include/linux/amlogic/secmon.h
index 2003ac2..183d21e 100644
--- a/include/linux/amlogic/secmon.h
+++ b/include/linux/amlogic/secmon.h
@@ -27,4 +27,6 @@ void sharemem_mutex_lock(void);
void sharemem_mutex_unlock(void);
void secmon_clear_cma_mmu(void);
+int within_secmon_region(unsigned long addr);
+
#endif
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index 7555475..0fc9803d 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -93,9 +93,19 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
cpu, instruction_pointer(regs));
} else {
pr_warn("NMI backtrace for cpu %d\n", cpu);
+ /*
+ * two reasons for not calling show_regs here
+ * 1. two many logs(100 lines per second) are
+ * introduced, which makes the wanted stack
+ * infos missed
+ * 2. leads to potential external abort on
+ * non-linefetch issue
+ */
+#ifndef CONFIG_AMLOGIC_MODIFY
if (regs)
show_regs(regs);
else
+#endif
dump_stack();
}
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 101aeeb..5928204 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -254,10 +254,14 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
*/
if (!pgd_none(*pgd)) {
pud_t *pud = pud_offset(pgd, addr);
+#ifndef CONFIG_AMLOGIC_MODIFY
WARN_ON_ONCE(pud_bad(*pud));
+#endif
if (!pud_none(*pud) && !pud_bad(*pud)) {
pmd_t *pmd = pmd_offset(pud, addr);
+#ifndef CONFIG_AMLOGIC_MODIFY
WARN_ON_ONCE(pmd_bad(*pmd));
+#endif
if (!pmd_none(*pmd) && !pmd_bad(*pmd)) {
pte_t *ptep, pte;