Loading arch/arm/kernel/module-plts.c +12 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,18 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt = s; else if (s->sh_type == SHT_SYMTAB) syms = (Elf32_Sym *)s->sh_addr; #if defined(CONFIG_ARM_UNWIND) && !defined(CONFIG_VMSPLIT_3G) else if (s->sh_type == ELF_SECTION_UNWIND || (strncmp(".ARM.extab", secstrings + s->sh_name, 10) == 0)) { /* * To avoid the possible relocation out of range issue for * R_ARM_PREL31, mark unwind section .ARM.extab and .ARM.exidx as * executable so they will be allocated along with .text section to * meet +/-1GB range requirement of the R_ARM_PREL31 relocation */ s->sh_flags |= SHF_EXECINSTR; } #endif } if (!mod->arch.core.plt || !mod->arch.init.plt) { Loading arch/arm/mm/fault.c +73 −85 Original line number Diff line number Diff line Loading @@ -115,32 +115,6 @@ static inline bool is_write_fault(unsigned int fsr) return (fsr & FSR_WRITE) && !(fsr & FSR_CM); } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); #ifdef CONFIG_ARM_LPAE if ((fs & FS_MMU_NOLL_MASK) == FS_TRANS_NOLL) return true; #else if (fs == FS_L1_TRANS || fs == FS_L2_TRANS) return true; #endif return false; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); #ifdef CONFIG_ARM_LPAE if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL) return true; #else if (fs == FS_L1_PERM || fs == FS_L2_PERM) return true; #endif return false; } static void die_kernel_fault(const char *msg, struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs) Loading Loading @@ -190,7 +164,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, /* * Something tried to access memory that isn't in our memory map.. * User mode accesses just cause a SIGSEGV * User mode accesses just cause a SIGSEGV. Ensure interrupts are enabled * for preempt RT. */ static void __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, Loading @@ -198,6 +173,8 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, { struct task_struct *tsk = current; local_irq_enable(); #ifdef CONFIG_DEBUG_USER if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || ((user_debug & UDBG_BUS) && (sig == SIGBUS))) { Loading Loading @@ -258,6 +235,70 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs) } #endif /* * Handle a vmalloc fault, copying the non-leaf page table entries from * init_mm.pgd. Any kernel context can trigger this, so we must not sleep * or enable interrupts. Having two CPUs execute this for the same page is * no problem, we'll just copy the same data twice. * * Returns false on failure. */ static bool __kprobes __maybe_unused vmalloc_fault(unsigned long addr) { unsigned int index; pgd_t *pgd, *pgd_k; p4d_t *p4d, *p4d_k; pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; index = pgd_index(addr); pgd = cpu_get_pgd() + index; pgd_k = init_mm.pgd + index; p4d = p4d_offset(pgd, addr); p4d_k = p4d_offset(pgd_k, addr); if (p4d_none(*p4d_k)) return false; if (!p4d_present(*p4d)) set_p4d(p4d, *p4d_k); pud = pud_offset(p4d, addr); pud_k = pud_offset(p4d_k, addr); if (pud_none(*pud_k)) return false; if (!pud_present(*pud)) set_pud(pud, *pud_k); pmd = pmd_offset(pud, addr); pmd_k = pmd_offset(pud_k, addr); #ifdef CONFIG_ARM_LPAE /* * Only one hardware entry per PMD with LPAE. */ index = 0; #else /* * On ARM one Linux PGD entry contains two hardware entries (see page * tables layout in pgtable.h). We normally guarantee that we always * fill both L1 entries. But create_mapping() doesn't follow the rule. * It can create inidividual L1 entries, so here we have to call * pmd_none() check for the entry really corresponded to address, not * for the first of pair. */ index = (addr >> SECTION_SHIFT) & 1; #endif if (pmd_none(pmd_k[index])) return false; copy_pmd(pmd, pmd_k); return true; } static int __kprobes do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs) Loading @@ -268,6 +309,7 @@ do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr, * should not be faulting in kernel space, which includes the * vector/khelper page. Handle the branch predictor hardening * while interrupts are still disabled, then send a SIGSEGV. * Note that __do_user_fault() will enable interrupts. */ harden_branch_predictor(); __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs); Loading Loading @@ -492,10 +534,9 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) * directly to do_kernel_address_page_fault() to handle. * * Otherwise, we're probably faulting in the vmalloc() area, so try to fix * that up. Note that we must not take any locks or enable interrupts in * this case. * that up via vmalloc_fault(). * * If vmalloc() fixup fails, that means the non-leaf page tables did not * If vmalloc_fault() fails, that means the non-leaf page tables did not * contain an entry for this address, so handle this via * do_kernel_address_page_fault(). */ Loading @@ -504,65 +545,12 @@ static int __kprobes do_translation_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { unsigned int index; pgd_t *pgd, *pgd_k; p4d_t *p4d, *p4d_k; pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; if (addr < TASK_SIZE) return do_page_fault(addr, fsr, regs); if (user_mode(regs)) goto bad_area; index = pgd_index(addr); pgd = cpu_get_pgd() + index; pgd_k = init_mm.pgd + index; p4d = p4d_offset(pgd, addr); p4d_k = p4d_offset(pgd_k, addr); if (p4d_none(*p4d_k)) goto bad_area; if (!p4d_present(*p4d)) set_p4d(p4d, *p4d_k); pud = pud_offset(p4d, addr); pud_k = pud_offset(p4d_k, addr); if (pud_none(*pud_k)) goto bad_area; if (!pud_present(*pud)) set_pud(pud, *pud_k); pmd = pmd_offset(pud, addr); pmd_k = pmd_offset(pud_k, addr); #ifdef CONFIG_ARM_LPAE /* * Only one hardware entry per PMD with LPAE. */ index = 0; #else /* * On ARM one Linux PGD entry contains two hardware entries (see page * tables layout in pgtable.h). We normally guarantee that we always * fill both L1 entries. But create_mapping() doesn't follow the rule. * It can create inidividual L1 entries, so here we have to call * pmd_none() check for the entry really corresponded to address, not * for the first of pair. */ index = (addr >> SECTION_SHIFT) & 1; #endif if (pmd_none(pmd_k[index])) goto bad_area; copy_pmd(pmd, pmd_k); if (!user_mode(regs) && vmalloc_fault(addr)) return 0; bad_area: do_kernel_address_page_fault(current->mm, addr, fsr, regs); return 0; Loading arch/arm/mm/fault.h +36 −6 Original line number Diff line number Diff line Loading @@ -5,12 +5,9 @@ /* * Fault status register encodings. We steal bit 31 for our own purposes. */ #define FSR_LNX_PF (1 << 31) #define FSR_CM (1 << 13) #define FSR_WRITE (1 << 11) #define FSR_FS4 (1 << 10) #define FSR_FS3_0 (15) #define FSR_FS5_0 (0x3f) #define FSR_LNX_PF BIT(31) #define FSR_CM BIT(13) #define FSR_WRITE BIT(11) #ifdef CONFIG_ARM_LPAE #define FSR_FS_AEA 17 Loading @@ -18,10 +15,26 @@ #define FS_PERM_NOLL 0xC #define FS_MMU_NOLL_MASK 0x3C #define FSR_FS5_0 GENMASK(5, 0) static inline int fsr_fs(unsigned int fsr) { return fsr & FSR_FS5_0; } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return (fs & FS_MMU_NOLL_MASK) == FS_TRANS_NOLL; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return (fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL; } #else #define FSR_FS_AEA 22 #define FS_L1_TRANS 0x5 Loading @@ -29,10 +42,27 @@ static inline int fsr_fs(unsigned int fsr) #define FS_L1_PERM 0xD #define FS_L2_PERM 0xF #define FSR_FS4 BIT(10) #define FSR_FS3_0 GENMASK(3, 0) static inline int fsr_fs(unsigned int fsr) { return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return fs == FS_L1_TRANS || fs == FS_L2_TRANS; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return fs == FS_L1_PERM || fs == FS_L2_PERM; } #endif void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); Loading arch/arm/mm/flush.c +3 −1 Original line number Diff line number Diff line Loading @@ -304,8 +304,10 @@ void __sync_icache_dcache(pte_t pteval) else mapping = NULL; if (!test_and_set_bit(PG_dcache_clean, &folio->flags.f)) if (!test_bit(PG_dcache_clean, &folio->flags.f)) { __flush_dcache_folio(mapping, folio); set_bit(PG_dcache_clean, &folio->flags.f); } if (pte_exec(pteval)) __flush_icache_all(); Loading Loading
arch/arm/kernel/module-plts.c +12 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,18 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt = s; else if (s->sh_type == SHT_SYMTAB) syms = (Elf32_Sym *)s->sh_addr; #if defined(CONFIG_ARM_UNWIND) && !defined(CONFIG_VMSPLIT_3G) else if (s->sh_type == ELF_SECTION_UNWIND || (strncmp(".ARM.extab", secstrings + s->sh_name, 10) == 0)) { /* * To avoid the possible relocation out of range issue for * R_ARM_PREL31, mark unwind section .ARM.extab and .ARM.exidx as * executable so they will be allocated along with .text section to * meet +/-1GB range requirement of the R_ARM_PREL31 relocation */ s->sh_flags |= SHF_EXECINSTR; } #endif } if (!mod->arch.core.plt || !mod->arch.init.plt) { Loading
arch/arm/mm/fault.c +73 −85 Original line number Diff line number Diff line Loading @@ -115,32 +115,6 @@ static inline bool is_write_fault(unsigned int fsr) return (fsr & FSR_WRITE) && !(fsr & FSR_CM); } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); #ifdef CONFIG_ARM_LPAE if ((fs & FS_MMU_NOLL_MASK) == FS_TRANS_NOLL) return true; #else if (fs == FS_L1_TRANS || fs == FS_L2_TRANS) return true; #endif return false; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); #ifdef CONFIG_ARM_LPAE if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL) return true; #else if (fs == FS_L1_PERM || fs == FS_L2_PERM) return true; #endif return false; } static void die_kernel_fault(const char *msg, struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs) Loading Loading @@ -190,7 +164,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, /* * Something tried to access memory that isn't in our memory map.. * User mode accesses just cause a SIGSEGV * User mode accesses just cause a SIGSEGV. Ensure interrupts are enabled * for preempt RT. */ static void __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, Loading @@ -198,6 +173,8 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, { struct task_struct *tsk = current; local_irq_enable(); #ifdef CONFIG_DEBUG_USER if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || ((user_debug & UDBG_BUS) && (sig == SIGBUS))) { Loading Loading @@ -258,6 +235,70 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs) } #endif /* * Handle a vmalloc fault, copying the non-leaf page table entries from * init_mm.pgd. Any kernel context can trigger this, so we must not sleep * or enable interrupts. Having two CPUs execute this for the same page is * no problem, we'll just copy the same data twice. * * Returns false on failure. */ static bool __kprobes __maybe_unused vmalloc_fault(unsigned long addr) { unsigned int index; pgd_t *pgd, *pgd_k; p4d_t *p4d, *p4d_k; pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; index = pgd_index(addr); pgd = cpu_get_pgd() + index; pgd_k = init_mm.pgd + index; p4d = p4d_offset(pgd, addr); p4d_k = p4d_offset(pgd_k, addr); if (p4d_none(*p4d_k)) return false; if (!p4d_present(*p4d)) set_p4d(p4d, *p4d_k); pud = pud_offset(p4d, addr); pud_k = pud_offset(p4d_k, addr); if (pud_none(*pud_k)) return false; if (!pud_present(*pud)) set_pud(pud, *pud_k); pmd = pmd_offset(pud, addr); pmd_k = pmd_offset(pud_k, addr); #ifdef CONFIG_ARM_LPAE /* * Only one hardware entry per PMD with LPAE. */ index = 0; #else /* * On ARM one Linux PGD entry contains two hardware entries (see page * tables layout in pgtable.h). We normally guarantee that we always * fill both L1 entries. But create_mapping() doesn't follow the rule. * It can create inidividual L1 entries, so here we have to call * pmd_none() check for the entry really corresponded to address, not * for the first of pair. */ index = (addr >> SECTION_SHIFT) & 1; #endif if (pmd_none(pmd_k[index])) return false; copy_pmd(pmd, pmd_k); return true; } static int __kprobes do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs) Loading @@ -268,6 +309,7 @@ do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr, * should not be faulting in kernel space, which includes the * vector/khelper page. Handle the branch predictor hardening * while interrupts are still disabled, then send a SIGSEGV. * Note that __do_user_fault() will enable interrupts. */ harden_branch_predictor(); __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs); Loading Loading @@ -492,10 +534,9 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) * directly to do_kernel_address_page_fault() to handle. * * Otherwise, we're probably faulting in the vmalloc() area, so try to fix * that up. Note that we must not take any locks or enable interrupts in * this case. * that up via vmalloc_fault(). * * If vmalloc() fixup fails, that means the non-leaf page tables did not * If vmalloc_fault() fails, that means the non-leaf page tables did not * contain an entry for this address, so handle this via * do_kernel_address_page_fault(). */ Loading @@ -504,65 +545,12 @@ static int __kprobes do_translation_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { unsigned int index; pgd_t *pgd, *pgd_k; p4d_t *p4d, *p4d_k; pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; if (addr < TASK_SIZE) return do_page_fault(addr, fsr, regs); if (user_mode(regs)) goto bad_area; index = pgd_index(addr); pgd = cpu_get_pgd() + index; pgd_k = init_mm.pgd + index; p4d = p4d_offset(pgd, addr); p4d_k = p4d_offset(pgd_k, addr); if (p4d_none(*p4d_k)) goto bad_area; if (!p4d_present(*p4d)) set_p4d(p4d, *p4d_k); pud = pud_offset(p4d, addr); pud_k = pud_offset(p4d_k, addr); if (pud_none(*pud_k)) goto bad_area; if (!pud_present(*pud)) set_pud(pud, *pud_k); pmd = pmd_offset(pud, addr); pmd_k = pmd_offset(pud_k, addr); #ifdef CONFIG_ARM_LPAE /* * Only one hardware entry per PMD with LPAE. */ index = 0; #else /* * On ARM one Linux PGD entry contains two hardware entries (see page * tables layout in pgtable.h). We normally guarantee that we always * fill both L1 entries. But create_mapping() doesn't follow the rule. * It can create inidividual L1 entries, so here we have to call * pmd_none() check for the entry really corresponded to address, not * for the first of pair. */ index = (addr >> SECTION_SHIFT) & 1; #endif if (pmd_none(pmd_k[index])) goto bad_area; copy_pmd(pmd, pmd_k); if (!user_mode(regs) && vmalloc_fault(addr)) return 0; bad_area: do_kernel_address_page_fault(current->mm, addr, fsr, regs); return 0; Loading
arch/arm/mm/fault.h +36 −6 Original line number Diff line number Diff line Loading @@ -5,12 +5,9 @@ /* * Fault status register encodings. We steal bit 31 for our own purposes. */ #define FSR_LNX_PF (1 << 31) #define FSR_CM (1 << 13) #define FSR_WRITE (1 << 11) #define FSR_FS4 (1 << 10) #define FSR_FS3_0 (15) #define FSR_FS5_0 (0x3f) #define FSR_LNX_PF BIT(31) #define FSR_CM BIT(13) #define FSR_WRITE BIT(11) #ifdef CONFIG_ARM_LPAE #define FSR_FS_AEA 17 Loading @@ -18,10 +15,26 @@ #define FS_PERM_NOLL 0xC #define FS_MMU_NOLL_MASK 0x3C #define FSR_FS5_0 GENMASK(5, 0) static inline int fsr_fs(unsigned int fsr) { return fsr & FSR_FS5_0; } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return (fs & FS_MMU_NOLL_MASK) == FS_TRANS_NOLL; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return (fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL; } #else #define FSR_FS_AEA 22 #define FS_L1_TRANS 0x5 Loading @@ -29,10 +42,27 @@ static inline int fsr_fs(unsigned int fsr) #define FS_L1_PERM 0xD #define FS_L2_PERM 0xF #define FSR_FS4 BIT(10) #define FSR_FS3_0 GENMASK(3, 0) static inline int fsr_fs(unsigned int fsr) { return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; } static inline bool is_translation_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return fs == FS_L1_TRANS || fs == FS_L2_TRANS; } static inline bool is_permission_fault(unsigned int fsr) { int fs = fsr_fs(fsr); return fs == FS_L1_PERM || fs == FS_L2_PERM; } #endif void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); Loading
arch/arm/mm/flush.c +3 −1 Original line number Diff line number Diff line Loading @@ -304,8 +304,10 @@ void __sync_icache_dcache(pte_t pteval) else mapping = NULL; if (!test_and_set_bit(PG_dcache_clean, &folio->flags.f)) if (!test_bit(PG_dcache_clean, &folio->flags.f)) { __flush_dcache_folio(mapping, folio); set_bit(PG_dcache_clean, &folio->flags.f); } if (pte_exec(pteval)) __flush_icache_all(); Loading