diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ec33376f8e2b..71fc5dd4123f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -42,6 +42,7 @@ config ARM select ARCH_SUPPORTS_CFI select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE select ARCH_SUPPORTS_PER_VMA_LOCK + select ARCH_SUPPORTS_RT select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 354ce16d83cb..b5338fe59706 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -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) { diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index ed4330cc3f4e..e62cc4be5adf 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -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) @@ -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, @@ -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))) { @@ -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) @@ -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); @@ -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(). */ @@ -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; + if (!user_mode(regs) && vmalloc_fault(addr)) + return 0; - 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); - return 0; - -bad_area: do_kernel_address_page_fault(current->mm, addr, fsr, regs); return 0; diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index e8f8c1902544..207f1b06941d 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -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 @@ -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 @@ -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); diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 19470d938b23..4d7ef5cc36b6 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -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(); diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 2c5b2076acf9..a4cd0a5159dd 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -317,6 +317,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, if (adfs_checkdiscrecord(dr)) return -EILSEQ; + if ((dr->nzones | dr->nzones_high << 8) == 0) + return -EILSEQ; + *drp = dr; return 0; }