Skip to content

Commit 0905809

Browse files
committed
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
2 parents d41e583 + 89f686a commit 0905809

File tree

9 files changed

+112
-26
lines changed

9 files changed

+112
-26
lines changed

arch/parisc/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ endif
3939

4040
export LD_BFD
4141

42-
# Set default 32 bits cross compilers for vdso
42+
# Set default 32 bits cross compilers for vdso.
43+
# This means that for 64BIT, both the 64-bit tools and the 32-bit tools
44+
# need to be in the path.
4345
CC_ARCHES_32 = hppa hppa2.0 hppa1.1
4446
CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
4547
CROSS32_COMPILE := $(call cc-cross-prefix, \
@@ -139,7 +141,7 @@ palo lifimage: vmlinuz
139141
fi
140142
@if test ! -f "$(PALOCONF)"; then \
141143
cp $(srctree)/arch/parisc/defpalo.conf $(objtree)/palo.conf; \
142-
echo 'A generic palo config file ($(objree)/palo.conf) has been created for you.'; \
144+
echo 'A generic palo config file ($(objtree)/palo.conf) has been created for you.'; \
143145
echo 'You should check it and re-run "make palo".'; \
144146
echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
145147
false; \

arch/parisc/include/asm/pgtable.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ extern unsigned long *empty_zero_page;
276276
#define pte_none(x) (pte_val(x) == 0)
277277
#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
278278
#define pte_user(x) (pte_val(x) & _PAGE_USER)
279-
#define pte_clear(mm, addr, xp) set_pte(xp, __pte(0))
279+
#define pte_clear(mm, addr, xp) set_pte_at((mm), (addr), (xp), __pte(0))
280280

281281
#define pmd_flag(x) (pmd_val(x) & PxD_FLAG_MASK)
282282
#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,
392392
}
393393
}
394394
#define set_ptes set_ptes
395+
#define set_pte_at(mm, addr, ptep, pte) set_ptes(mm, addr, ptep, pte, 1)
395396

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

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

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

472473
#define pte_same(A,B) (pte_val(A) == pte_val(B))

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/include/asm/uaccess.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,24 @@
4242
__gu_err; \
4343
})
4444

45-
#define __get_user(val, ptr) \
46-
({ \
47-
__get_user_internal(SR_USER, val, ptr); \
45+
#define __probe_user_internal(sr, error, ptr) \
46+
({ \
47+
__asm__("\tproberi (%%sr%1,%2),%3,%0\n" \
48+
"\tcmpiclr,= 1,%0,%0\n" \
49+
"\tldi %4,%0\n" \
50+
: "=r"(error) \
51+
: "i"(sr), "r"(ptr), "i"(PRIV_USER), \
52+
"i"(-EFAULT)); \
53+
})
54+
55+
#define __get_user(val, ptr) \
56+
({ \
57+
register long __gu_err; \
58+
\
59+
__gu_err = __get_user_internal(SR_USER, val, ptr); \
60+
if (likely(!__gu_err)) \
61+
__probe_user_internal(SR_USER, __gu_err, ptr); \
62+
__gu_err; \
4863
})
4964

5065
#define __get_user_asm(sr, val, ldx, ptr) \

arch/parisc/kernel/cache.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ static inline pte_t *get_ptep(struct mm_struct *mm, unsigned long addr)
429429
return ptep;
430430
}
431431

432-
static inline bool pte_needs_flush(pte_t pte)
432+
static inline bool pte_needs_cache_flush(pte_t pte)
433433
{
434434
return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE))
435435
== (_PAGE_PRESENT | _PAGE_ACCESSED);
@@ -630,7 +630,7 @@ static void flush_cache_page_if_present(struct vm_area_struct *vma,
630630
ptep = get_ptep(vma->vm_mm, vmaddr);
631631
if (ptep) {
632632
pte = ptep_get(ptep);
633-
needs_flush = pte_needs_flush(pte);
633+
needs_flush = pte_needs_cache_flush(pte);
634634
pte_unmap(ptep);
635635
}
636636
if (needs_flush)
@@ -841,7 +841,7 @@ void flush_cache_vmap(unsigned long start, unsigned long end)
841841
}
842842

843843
vm = find_vm_area((void *)start);
844-
if (WARN_ON_ONCE(!vm)) {
844+
if (!vm) {
845845
flush_cache_all();
846846
return;
847847
}

arch/parisc/kernel/entry.S

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,12 @@
499499
* this happens is quite subtle, read below */
500500
.macro make_insert_tlb spc,pte,prot,tmp
501501
space_to_prot \spc \prot /* create prot id from space */
502+
503+
#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT
504+
/* need to drop DMB bit, as it's used as SPECIAL flag */
505+
depi 0,_PAGE_SPECIAL_BIT,1,\pte
506+
#endif
507+
502508
/* The following is the real subtlety. This is depositing
503509
* T <-> _PAGE_REFTRAP
504510
* D <-> _PAGE_DIRTY
@@ -511,17 +517,18 @@
511517
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
512518
* trigger an access rights trap in user space if the user
513519
* tries to read an unreadable page */
514-
#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT
515-
/* need to drop DMB bit, as it's used as SPECIAL flag */
516-
depi 0,_PAGE_SPECIAL_BIT,1,\pte
517-
#endif
518520
depd \pte,8,7,\prot
519521

520522
/* PAGE_USER indicates the page can be read with user privileges,
521523
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
522-
* contains _PAGE_READ) */
524+
* contains _PAGE_READ). While the kernel can't directly write
525+
* user pages which have _PAGE_WRITE zero, it can read pages
526+
* which have _PAGE_READ zero (PL <= PL1). Thus, the kernel
527+
* exception fault handler doesn't trigger when reading pages
528+
* that aren't user read accessible */
523529
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
524530
depdi 7,11,3,\prot
531+
525532
/* If we're a gateway page, drop PL2 back to zero for promotion
526533
* to kernel privilege (so we can execute the page as kernel).
527534
* Any privilege promotion page always denys read and write */

arch/parisc/kernel/syscall.S

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,9 @@ lws_compare_and_swap32:
613613
lws_compare_and_swap:
614614
/* Trigger memory reference interruptions without writing to memory */
615615
1: ldw 0(%r26), %r28
616+
proberi (%r26), PRIV_USER, %r28
617+
comb,=,n %r28, %r0, lws_fault /* backwards, likely not taken */
618+
nop
616619
2: stbys,e %r0, 0(%r26)
617620

618621
/* Calculate 8-bit hash index from virtual address */
@@ -767,6 +770,9 @@ cas2_lock_start:
767770
copy %r26, %r28
768771
depi_safe 0, 31, 2, %r28
769772
10: ldw 0(%r28), %r1
773+
proberi (%r28), PRIV_USER, %r1
774+
comb,=,n %r1, %r0, lws_fault /* backwards, likely not taken */
775+
nop
770776
11: stbys,e %r0, 0(%r28)
771777

772778
/* Calculate 8-bit hash index from virtual address */
@@ -951,41 +957,47 @@ atomic_xchg_begin:
951957

952958
/* 8-bit exchange */
953959
1: ldb 0(%r24), %r20
960+
proberi (%r24), PRIV_USER, %r20
961+
comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
962+
nop
954963
copy %r23, %r20
955964
depi_safe 0, 31, 2, %r20
956965
b atomic_xchg_start
957966
2: stbys,e %r0, 0(%r20)
958-
nop
959-
nop
960-
nop
961967

962968
/* 16-bit exchange */
963969
3: ldh 0(%r24), %r20
970+
proberi (%r24), PRIV_USER, %r20
971+
comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
972+
nop
964973
copy %r23, %r20
965974
depi_safe 0, 31, 2, %r20
966975
b atomic_xchg_start
967976
4: stbys,e %r0, 0(%r20)
968-
nop
969-
nop
970-
nop
971977

972978
/* 32-bit exchange */
973979
5: ldw 0(%r24), %r20
980+
proberi (%r24), PRIV_USER, %r20
981+
comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
982+
nop
974983
b atomic_xchg_start
975984
6: stbys,e %r0, 0(%r23)
976985
nop
977986
nop
978-
nop
979-
nop
980-
nop
981987

982988
/* 64-bit exchange */
983989
#ifdef CONFIG_64BIT
984990
7: ldd 0(%r24), %r20
991+
proberi (%r24), PRIV_USER, %r20
992+
comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
993+
nop
985994
8: stdby,e %r0, 0(%r23)
986995
#else
987996
7: ldw 0(%r24), %r20
988997
8: ldw 4(%r24), %r20
998+
proberi (%r24), PRIV_USER, %r20
999+
comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
1000+
nop
9891001
copy %r23, %r20
9901002
depi_safe 0, 31, 2, %r20
9911003
9: stbys,e %r0, 0(%r20)

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

arch/parisc/mm/fault.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
363363
mmap_read_unlock(mm);
364364

365365
bad_area_nosemaphore:
366+
if (!user_mode(regs) && fixup_exception(regs)) {
367+
return;
368+
}
369+
366370
if (user_mode(regs)) {
367371
int signo, si_code;
368372

0 commit comments

Comments
 (0)