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>
This commit is contained in:
Jiamin Ma
2019-04-30 16:07:17 +08:00
committed by Luke Go
parent 27b4db3b95
commit 04fedcc7e8
6 changed files with 89 additions and 0 deletions

View File

@@ -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);
/*

View File

@@ -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);
/*

View File

@@ -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);

View File

@@ -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

View File

@@ -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));

View File

@@ -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;