Commit 974bcde8 authored by Helge Deller's avatar Helge Deller Committed by Cheng Yu
Browse files

parisc: Switch user access functions to signal errors in r29 instead of r8

mainline inclusion
from mainline-v5.17-rc1
commit 4b9d2a73
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9E2GP
CVE: CVE-2024-26706

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4b9d2a731c3d22a05c1bccdb11b6e00054ff5fda



--------------------------------

Use register r29 instead of register r8 to signal faults when accessing
user memory. In case of faults, the fixup routine will store -EFAULT in
this register.

This change saves up to 752 bytes on a 32bit kernel, partly because the
compiler doesn't need to save and restore the old r8 value on the stack.

bloat-o-meter results for usage with r29 register:
add/remove: 0/0 grow/shrink: 23/86 up/down: 228/-980 (-752)

bloat-o-meter results for usage with r28 register:
add/remove: 0/0 grow/shrink: 28/83 up/down: 296/-956 (-660)

Signed-off-by: default avatarHelge Deller <deller@gmx.de>
Signed-off-by: default avatarCheng Yu <serein.chengyu@huawei.com>
parent bcaaddc2
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -61,9 +61,12 @@ struct exception_table_entry {
/*
 * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
 * (with lowest bit set) for which the fault handler in fixup_exception() will
 * load -EFAULT into %r8 for a read or write fault, and zeroes the target
 * load -EFAULT into %r29 for a read or write fault, and zeroes the target
 * register in case of a read fault in get_user().
 */
#define ASM_EXCEPTIONTABLE_REG	29
#define ASM_EXCEPTIONTABLE_VAR(__variable)		\
	register long __variable __asm__ ("r29") = 0
#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\
	ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1)

@@ -82,7 +85,7 @@ struct exception_table_entry {

#define __get_user_internal(val, ptr)			\
({							\
	register long __gu_err __asm__ ("r8") = 0;	\
	ASM_EXCEPTIONTABLE_VAR(__gu_err);		\
							\
	switch (sizeof(*(ptr))) {			\
	case 1: __get_user_asm(val, "ldb", ptr); break;	\
@@ -140,7 +143,7 @@ struct exception_table_entry {

#define __put_user_internal(x, ptr)				\
({								\
	register long __pu_err __asm__ ("r8") = 0;      	\
	ASM_EXCEPTIONTABLE_VAR(__pu_err);		      	\
        __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x);	\
								\
	switch (sizeof(*(ptr))) {				\
@@ -167,7 +170,8 @@ struct exception_table_entry {
 * gcc knows about, so there are no aliasing issues. These macros must
 * also be aware that fixups are executed in the context of the fault,
 * and any registers used there must be listed as clobbers.
 * r8 is already listed as err.
 * The register holding the possible EFAULT error (ASM_EXCEPTIONTABLE_REG)
 * is already listed as input and output register.
 */

#define __put_user_asm(stx, x, ptr)                         \
+3 −3
Original line number Diff line number Diff line
@@ -148,11 +148,11 @@ int fixup_exception(struct pt_regs *regs)
		 * Fix up get_user() and put_user().
		 * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant
		 * bit in the relative address of the fixup routine to indicate
		 * that %r8 should be loaded with -EFAULT to report a userspace
		 * access error.
		 * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with
		 * -EFAULT to report a userspace access error.
		 */
		if (fix->fixup & 1) {
			regs->gr[8] = -EFAULT;
			regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT;

			/* zero target register for get_user() */
			if (parisc_acctyp(0, regs->iir) == VM_READ) {