Commit 0905809b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'parisc-for-6.17-rc1' of...

Merge tag 'parisc-for-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc updates from Helge Deller:

 - The parisc kernel wrongly allows reading from read-protected
   userspace memory without faulting, e.g. when userspace uses
   mprotect() to read-protect a memory area and then uses a pointer to
   this memory in a write(2, addr, 1) syscall.

   To fix this issue, Dave Anglin developed a set of patches which use
   the proberi assembler instruction to additionally check read access
   permissions at runtime.

 - Randy Dunlap contributed two patches to fix a minor typo and to
   explain why a 32-bit compiler is needed although a 64-bit kernel is
   built

* tag 'parisc-for-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Revise __get_user() to probe user read access
  parisc: Revise gateway LWS calls to probe user read access
  parisc: Drop WARN_ON_ONCE() from flush_cache_vmap
  parisc: Try to fixup kernel exception in bad_area_nosemaphore path of do_page_fault()
  parisc: Define and use set_pte_at()
  parisc: Rename pte_needs_flush() to pte_needs_cache_flush() in cache.c
  parisc: Check region is readable by user in raw_copy_from_user()
  parisc: Update comments in make_insert_tlb
  parisc: Makefile: explain that 64BIT requires both 32-bit and 64-bit compilers
  parisc: Makefile: fix a typo in palo.conf
parents d41e5839 89f686a0
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -39,7 +39,9 @@ endif

export LD_BFD

# Set default 32 bits cross compilers for vdso
# Set default 32 bits cross compilers for vdso.
# This means that for 64BIT, both the 64-bit tools and the 32-bit tools
# need to be in the path.
CC_ARCHES_32 = hppa hppa2.0 hppa1.1
CC_SUFFIXES  = linux linux-gnu unknown-linux-gnu suse-linux
CROSS32_COMPILE := $(call cc-cross-prefix, \
@@ -139,7 +141,7 @@ palo lifimage: vmlinuz
	fi
	@if test ! -f "$(PALOCONF)"; then \
		cp $(srctree)/arch/parisc/defpalo.conf $(objtree)/palo.conf; \
		echo 'A generic palo config file ($(objree)/palo.conf) has been created for you.'; \
		echo 'A generic palo config file ($(objtree)/palo.conf) has been created for you.'; \
		echo 'You should check it and re-run "make palo".'; \
		echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
		false; \
+4 −3
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ extern unsigned long *empty_zero_page;
#define pte_none(x)     (pte_val(x) == 0)
#define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
#define pte_user(x)	(pte_val(x) & _PAGE_USER)
#define pte_clear(mm, addr, xp)  set_pte(xp, __pte(0))
#define pte_clear(mm, addr, xp) set_pte_at((mm), (addr), (xp), __pte(0))

#define pmd_flag(x)	(pmd_val(x) & PxD_FLAG_MASK)
#define pmd_address(x)	((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
@@ -392,6 +392,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
	}
}
#define set_ptes set_ptes
#define set_pte_at(mm, addr, ptep, pte) set_ptes(mm, addr, ptep, pte, 1)

/* Used for deferring calls to flush_dcache_page() */

@@ -456,7 +457,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
	if (!pte_young(pte)) {
		return 0;
	}
	set_pte(ptep, pte_mkold(pte));
	set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte));
	return 1;
}

@@ -466,7 +467,7 @@ pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *pt
struct mm_struct;
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
	set_pte(ptep, pte_wrprotect(*ptep));
	set_pte_at(mm, addr, ptep, pte_wrprotect(*ptep));
}

#define pte_same(A,B)	(pte_val(A) == pte_val(B))
+28 −0
Original line number Diff line number Diff line
@@ -32,6 +32,34 @@
	pa;						\
})

/**
 * prober_user() - Probe user read access
 * @sr:		Space regster.
 * @va:		Virtual address.
 *
 * Return: Non-zero if address is accessible.
 *
 * Due to the way _PAGE_READ is handled in TLB entries, we need
 * a special check to determine whether a user address is accessible.
 * The ldb instruction does the initial access check. If it is
 * successful, the probe instruction checks user access rights.
 */
#define prober_user(sr, va)	({			\
	unsigned long read_allowed;			\
	__asm__ __volatile__(				\
		"copy %%r0,%0\n"			\
		"8:\tldb 0(%%sr%1,%2),%%r0\n"		\
		"\tproberi (%%sr%1,%2),%3,%0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY(8b, 9b,	\
				"or %%r0,%%r0,%%r0")	\
		: "=&r" (read_allowed)			\
		: "i" (sr), "r" (va), "i" (PRIV_USER)	\
		: "memory"				\
	);						\
	read_allowed;					\
})

#define CR_EIEM 15	/* External Interrupt Enable Mask */
#define CR_CR16 16	/* CR16 Interval Timer */
#define CR_EIRR 23	/* External Interrupt Request Register */
+18 −3
Original line number Diff line number Diff line
@@ -42,9 +42,24 @@
	__gu_err;					\
})

#define __probe_user_internal(sr, error, ptr)			\
({								\
	__asm__("\tproberi (%%sr%1,%2),%3,%0\n"			\
		"\tcmpiclr,= 1,%0,%0\n"				\
		"\tldi %4,%0\n"					\
		: "=r"(error)					\
		: "i"(sr), "r"(ptr), "i"(PRIV_USER),		\
		  "i"(-EFAULT));				\
})

#define __get_user(val, ptr)					\
({								\
	__get_user_internal(SR_USER, val, ptr);	\
	register long __gu_err;					\
								\
	__gu_err = __get_user_internal(SR_USER, val, ptr);	\
	if (likely(!__gu_err))					\
		__probe_user_internal(SR_USER, __gu_err, ptr);	\
	__gu_err;						\
})

#define __get_user_asm(sr, val, ldx, ptr)		\
+3 −3
Original line number Diff line number Diff line
@@ -429,7 +429,7 @@ static inline pte_t *get_ptep(struct mm_struct *mm, unsigned long addr)
	return ptep;
}

static inline bool pte_needs_flush(pte_t pte)
static inline bool pte_needs_cache_flush(pte_t pte)
{
	return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE))
		== (_PAGE_PRESENT | _PAGE_ACCESSED);
@@ -630,7 +630,7 @@ static void flush_cache_page_if_present(struct vm_area_struct *vma,
	ptep = get_ptep(vma->vm_mm, vmaddr);
	if (ptep) {
		pte = ptep_get(ptep);
		needs_flush = pte_needs_flush(pte);
		needs_flush = pte_needs_cache_flush(pte);
		pte_unmap(ptep);
	}
	if (needs_flush)
@@ -841,7 +841,7 @@ void flush_cache_vmap(unsigned long start, unsigned long end)
	}

	vm = find_vm_area((void *)start);
	if (WARN_ON_ONCE(!vm)) {
	if (!vm) {
		flush_cache_all();
		return;
	}
Loading