99
1010#ifndef __ASSEMBLY__
1111
12- #include <linux/jump_label.h>
13-
14- extern struct static_key_false disable_kuap_key ;
15-
16- static __always_inline bool kuep_is_disabled (void )
17- {
18- return !IS_ENABLED (CONFIG_PPC_KUEP );
19- }
20-
2112#ifdef CONFIG_PPC_KUAP
2213
2314#include <linux/sched.h>
2415
2516#define KUAP_NONE (~0UL)
26- #define KUAP_ALL (~1UL)
2717
28- static __always_inline bool kuap_is_disabled (void )
29- {
30- return static_branch_unlikely (& disable_kuap_key );
31- }
32-
33- static inline void kuap_lock_one (unsigned long addr )
18+ static __always_inline void kuap_lock_one (unsigned long addr )
3419{
3520 mtsr (mfsr (addr ) | SR_KS , addr );
3621 isync (); /* Context sync required after mtsr() */
3722}
3823
39- static inline void kuap_unlock_one (unsigned long addr )
24+ static __always_inline void kuap_unlock_one (unsigned long addr )
4025{
4126 mtsr (mfsr (addr ) & ~SR_KS , addr );
4227 isync (); /* Context sync required after mtsr() */
4328}
4429
45- static inline void kuap_lock_all ( void )
30+ static __always_inline void uaccess_begin_32s ( unsigned long addr )
4631{
47- update_user_segments (mfsr (0 ) | SR_KS );
48- isync (); /* Context sync required after mtsr() */
49- }
32+ unsigned long tmp ;
5033
51- static inline void kuap_unlock_all (void )
52- {
53- update_user_segments (mfsr (0 ) & ~SR_KS );
54- isync (); /* Context sync required after mtsr() */
34+ asm volatile (ASM_MMU_FTR_IFSET (
35+ "mfsrin %0, %1;"
36+ "rlwinm %0, %0, 0, %2;"
37+ "mtsrin %0, %1;"
38+ "isync" , "" , %3 )
39+ : "=&r" (tmp )
40+ : "r" (addr ), "i" (~SR_KS ), "i" (MMU_FTR_KUAP )
41+ : "memory" );
5542}
5643
57- void kuap_lock_all_ool (void );
58- void kuap_unlock_all_ool (void );
59-
60- static inline void kuap_lock_addr (unsigned long addr , bool ool )
44+ static __always_inline void uaccess_end_32s (unsigned long addr )
6145{
62- if (likely (addr != KUAP_ALL ))
63- kuap_lock_one (addr );
64- else if (!ool )
65- kuap_lock_all ();
66- else
67- kuap_lock_all_ool ();
68- }
46+ unsigned long tmp ;
6947
70- static inline void kuap_unlock ( unsigned long addr , bool ool )
71- {
72- if ( likely ( addr != KUAP_ALL ))
73- kuap_unlock_one ( addr );
74- else if (! ool )
75- kuap_unlock_all ();
76- else
77- kuap_unlock_all_ool ( );
48+ asm volatile ( ASM_MMU_FTR_IFSET (
49+ "mfsrin %0, %1;"
50+ "oris %0, %0, %2;"
51+ "mtsrin %0, %1;"
52+ "isync" , "" , % 3 )
53+ : "=&r" ( tmp )
54+ : "r" ( addr ), "i" ( SR_KS >> 16 ), "i" ( MMU_FTR_KUAP )
55+ : "memory" );
7856}
7957
80- static inline void __kuap_lock (void )
81- {
82- }
83-
84- static inline void __kuap_save_and_lock (struct pt_regs * regs )
58+ static __always_inline void __kuap_save_and_lock (struct pt_regs * regs )
8559{
8660 unsigned long kuap = current -> thread .kuap ;
8761
@@ -90,50 +64,52 @@ static inline void __kuap_save_and_lock(struct pt_regs *regs)
9064 return ;
9165
9266 current -> thread .kuap = KUAP_NONE ;
93- kuap_lock_addr (kuap , false );
67+ kuap_lock_one (kuap );
9468}
69+ #define __kuap_save_and_lock __kuap_save_and_lock
9570
96- static inline void kuap_user_restore (struct pt_regs * regs )
71+ static __always_inline void kuap_user_restore (struct pt_regs * regs )
9772{
9873}
9974
100- static inline void __kuap_kernel_restore (struct pt_regs * regs , unsigned long kuap )
75+ static __always_inline void __kuap_kernel_restore (struct pt_regs * regs , unsigned long kuap )
10176{
10277 if (unlikely (kuap != KUAP_NONE )) {
10378 current -> thread .kuap = KUAP_NONE ;
104- kuap_lock_addr (kuap , false );
79+ kuap_lock_one (kuap );
10580 }
10681
10782 if (likely (regs -> kuap == KUAP_NONE ))
10883 return ;
10984
11085 current -> thread .kuap = regs -> kuap ;
11186
112- kuap_unlock (regs -> kuap , false );
87+ kuap_unlock_one (regs -> kuap );
11388}
11489
115- static inline unsigned long __kuap_get_and_assert_locked (void )
90+ static __always_inline unsigned long __kuap_get_and_assert_locked (void )
11691{
11792 unsigned long kuap = current -> thread .kuap ;
11893
11994 WARN_ON_ONCE (IS_ENABLED (CONFIG_PPC_KUAP_DEBUG ) && kuap != KUAP_NONE );
12095
12196 return kuap ;
12297}
98+ #define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
12399
124- static __always_inline void __allow_user_access (void __user * to , const void __user * from ,
125- u32 size , unsigned long dir )
100+ static __always_inline void allow_user_access (void __user * to , const void __user * from ,
101+ u32 size , unsigned long dir )
126102{
127103 BUILD_BUG_ON (!__builtin_constant_p (dir ));
128104
129105 if (!(dir & KUAP_WRITE ))
130106 return ;
131107
132108 current -> thread .kuap = (__force u32 )to ;
133- kuap_unlock_one ((__force u32 )to );
109+ uaccess_begin_32s ((__force u32 )to );
134110}
135111
136- static __always_inline void __prevent_user_access (unsigned long dir )
112+ static __always_inline void prevent_user_access (unsigned long dir )
137113{
138114 u32 kuap = current -> thread .kuap ;
139115
@@ -143,42 +119,51 @@ static __always_inline void __prevent_user_access(unsigned long dir)
143119 return ;
144120
145121 current -> thread .kuap = KUAP_NONE ;
146- kuap_lock_addr (kuap , true );
122+ uaccess_end_32s (kuap );
147123}
148124
149- static inline unsigned long __prevent_user_access_return (void )
125+ static __always_inline unsigned long prevent_user_access_return (void )
150126{
151127 unsigned long flags = current -> thread .kuap ;
152128
153129 if (flags != KUAP_NONE ) {
154130 current -> thread .kuap = KUAP_NONE ;
155- kuap_lock_addr (flags , true );
131+ uaccess_end_32s (flags );
156132 }
157133
158134 return flags ;
159135}
160136
161- static inline void __restore_user_access (unsigned long flags )
137+ static __always_inline void restore_user_access (unsigned long flags )
162138{
163139 if (flags != KUAP_NONE ) {
164140 current -> thread .kuap = flags ;
165- kuap_unlock (flags , true );
141+ uaccess_begin_32s (flags );
166142 }
167143}
168144
169- static inline bool
145+ static __always_inline bool
170146__bad_kuap_fault (struct pt_regs * regs , unsigned long address , bool is_write )
171147{
172148 unsigned long kuap = regs -> kuap ;
173149
174- if (!is_write || kuap == KUAP_ALL )
150+ if (!is_write )
175151 return false;
176152 if (kuap == KUAP_NONE )
177153 return true;
178154
179- /* If faulting address doesn't match unlocked segment, unlock all */
180- if ((kuap ^ address ) & 0xf0000000 )
181- regs -> kuap = KUAP_ALL ;
155+ /*
156+ * If faulting address doesn't match unlocked segment, change segment.
157+ * In case of unaligned store crossing two segments, emulate store.
158+ */
159+ if ((kuap ^ address ) & 0xf0000000 ) {
160+ if (!(kuap & 0x0fffffff ) && address > kuap - 4 && fix_alignment (regs )) {
161+ regs_add_return_ip (regs , 4 );
162+ emulate_single_step (regs );
163+ } else {
164+ regs -> kuap = address ;
165+ }
166+ }
182167
183168 return false;
184169}
0 commit comments