Skip to content

Commit 91428ca

Browse files
danglin44hdeller
authored andcommitted
parisc: Check region is readable by user in raw_copy_from_user()
Because of the way the _PAGE_READ is handled in the parisc PTE, an access interruption is not generated when the kernel reads from a region where the _PAGE_READ is zero. The current code was written assuming read access faults would also occur in the kernel. This change adds user access checks to raw_copy_from_user(). The prober_user() define checks whether user code has read access to a virtual address. Note that page faults are not handled in the exception support for the probe instruction. For this reason, we precede the probe by a ldb access check. Signed-off-by: John David Anglin <[email protected]> Signed-off-by: Helge Deller <[email protected]> Cc: [email protected] # v5.12+
1 parent cb22f24 commit 91428ca

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

arch/parisc/include/asm/special_insns.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,34 @@
3232
pa; \
3333
})
3434

35+
/**
36+
* prober_user() - Probe user read access
37+
* @sr: Space regster.
38+
* @va: Virtual address.
39+
*
40+
* Return: Non-zero if address is accessible.
41+
*
42+
* Due to the way _PAGE_READ is handled in TLB entries, we need
43+
* a special check to determine whether a user address is accessible.
44+
* The ldb instruction does the initial access check. If it is
45+
* successful, the probe instruction checks user access rights.
46+
*/
47+
#define prober_user(sr, va) ({ \
48+
unsigned long read_allowed; \
49+
__asm__ __volatile__( \
50+
"copy %%r0,%0\n" \
51+
"8:\tldb 0(%%sr%1,%2),%%r0\n" \
52+
"\tproberi (%%sr%1,%2),%3,%0\n" \
53+
"9:\n" \
54+
ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \
55+
"or %%r0,%%r0,%%r0") \
56+
: "=&r" (read_allowed) \
57+
: "i" (sr), "r" (va), "i" (PRIV_USER) \
58+
: "memory" \
59+
); \
60+
read_allowed; \
61+
})
62+
3563
#define CR_EIEM 15 /* External Interrupt Enable Mask */
3664
#define CR_CR16 16 /* CR16 Interval Timer */
3765
#define CR_EIRR 23 /* External Interrupt Request Register */

arch/parisc/lib/memcpy.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/module.h>
1313
#include <linux/compiler.h>
1414
#include <linux/uaccess.h>
15+
#include <linux/mm.h>
1516

1617
#define get_user_space() mfsp(SR_USER)
1718
#define get_kernel_space() SR_KERNEL
@@ -32,9 +33,25 @@ EXPORT_SYMBOL(raw_copy_to_user);
3233
unsigned long raw_copy_from_user(void *dst, const void __user *src,
3334
unsigned long len)
3435
{
36+
unsigned long start = (unsigned long) src;
37+
unsigned long end = start + len;
38+
unsigned long newlen = len;
39+
3540
mtsp(get_user_space(), SR_TEMP1);
3641
mtsp(get_kernel_space(), SR_TEMP2);
37-
return pa_memcpy(dst, (void __force *)src, len);
42+
43+
/* Check region is user accessible */
44+
if (start)
45+
while (start < end) {
46+
if (!prober_user(SR_TEMP1, start)) {
47+
newlen = (start - (unsigned long) src);
48+
break;
49+
}
50+
start += PAGE_SIZE;
51+
/* align to page boundry which may have different permission */
52+
start = PAGE_ALIGN_DOWN(start);
53+
}
54+
return len - newlen + pa_memcpy(dst, (void __force *)src, newlen);
3855
}
3956
EXPORT_SYMBOL(raw_copy_from_user);
4057

0 commit comments

Comments
 (0)