From bc56b7b3e8d79e0d75ed0d19e7e128093f355b18 Mon Sep 17 00:00:00 2001 From: Zou Cao Date: Sun, 1 Dec 2019 22:43:28 +0800 Subject: [PATCH 0789/2944] alinux: Hookers: add arm64 support arm64 has't global write protect set, here we remove the write proctect in pmd table and update the hook data. Signed-off-by: Zou Cao Acked-by: Xunlei Pang --- net/hookers/hookers.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/net/hookers/hookers.c b/net/hookers/hookers.c index ba00e39..c3c2b66 100644 --- a/net/hookers/hookers.c +++ b/net/hookers/hookers.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include @@ -28,6 +31,10 @@ struct hooked_place { struct list_head chain; /* hookers chain */ }; +#ifdef CONFIG_ARM64 +static struct mm_struct *orig_init_mm; +#endif + static spinlock_t hookers_lock; static struct sock * @@ -253,6 +260,7 @@ void hooker_uninstall(struct hooker *h) } EXPORT_SYMBOL_GPL(hooker_uninstall); +#ifdef CONFIG_X86 static inline unsigned int hookers_clear_cr0(void) { unsigned int cr0 = read_cr0(); @@ -265,6 +273,52 @@ static inline void hookers_restore_cr0(unsigned int val) { write_cr0(val); } +#else + +static void remove_memprotect(unsigned long addr) +{ + pgd_t *pgd, pgdd; + pud_t *pud, pudd; + pmd_t *pmd, pmdd; + u64 addr_aligned; + + addr_aligned = addr & PAGE_MASK; + + pgd = pgd_offset(orig_init_mm, (unsigned long)addr_aligned); + pgdd = READ_ONCE(*pgd); + + pud = pud_offset(pgd, (unsigned long)addr_aligned); + pudd = READ_ONCE(*pud); + + pmd = pmd_offset(pud, (unsigned long)addr_aligned); + pmdd = READ_ONCE(*pmd); + + set_pmd(pmd, __pmd(pmd_val(pmdd) & ~PMD_SECT_RDONLY)); + flush_tlb_kernel_range(addr_aligned, addr_aligned + PAGE_SIZE); +} + +static void set_memprotect(unsigned long addr) +{ + pgd_t *pgd, pgdd; + pud_t *pud, pudd; + pmd_t *pmd, pmdd; + u64 addr_aligned; + + addr_aligned = addr & PAGE_MASK; + + pgd = pgd_offset(orig_init_mm, (unsigned long)addr_aligned); + pgdd = READ_ONCE(*pgd); + + pud = pud_offset(pgd, (unsigned long)addr_aligned); + pudd = READ_ONCE(*pud); + + pmd = pmd_offset(pud, (unsigned long)addr_aligned); + pmdd = READ_ONCE(*pmd); + + set_pmd(pmd, __pmd(pmd_val(pmdd) | PMD_SECT_RDONLY)); + flush_tlb_kernel_range(addr_aligned, addr_aligned + PAGE_SIZE); +} +#endif static void *hookers_seq_start(struct seq_file *seq, loff_t *pos) { @@ -321,20 +375,36 @@ static int hookers_init(void) if (!proc_create("hookers", 0444, NULL, &hookers_seq_fops)) return -ENODEV; +#ifdef CONFIG_ARM64 + orig_init_mm = (struct mm_struct *)kallsyms_lookup_name("init_mm"); + if (!orig_init_mm) + return -ENODEV; +#endif + spin_lock_init(&hookers_lock); for (i = 0; i < PLACE_TABLE_SZ; i++) { +#ifdef CONFIG_X86 unsigned int cr0; +#endif void **place = place_table[i].place; place_table[i].orig = *place; if (!place_table[i].stub) break; INIT_LIST_HEAD(&place_table[i].chain); +#ifdef CONFIG_X86 get_online_cpus(); cr0 = hookers_clear_cr0(); *place = place_table[i].stub; hookers_restore_cr0(cr0); put_online_cpus(); +#else + get_online_cpus(); + remove_memprotect((unsigned long)place); + *place = place_table[i].stub; + set_memprotect((unsigned long)place); + put_online_cpus(); +#endif } return 0; @@ -347,14 +417,22 @@ static void hookers_exit(void) remove_proc_entry("hookers", NULL); for (i = 0; i < PLACE_TABLE_SZ; i++) { - unsigned int cr0; void **place = place_table[i].place; +#ifdef CONFIG_X86 + unsigned int cr0; get_online_cpus(); cr0 = hookers_clear_cr0(); *place = place_table[i].orig; hookers_restore_cr0(cr0); put_online_cpus(); +#else + get_online_cpus(); + remove_memprotect((unsigned long)place); + *place = place_table[i].orig; + set_memprotect((unsigned long)place); + put_online_cpus(); +#endif } synchronize_rcu(); } -- 1.8.3.1