]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
s390/uaccess: Prevent kprobes on cmpxchg_user_key() functions
authorHeiko Carstens <hca@linux.ibm.com>
Mon, 16 Jun 2025 15:00:32 +0000 (17:00 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Sun, 29 Jun 2025 11:12:02 +0000 (13:12 +0200)
Code regions within cmpxchg_user_key() functions may be executed with a
non-default access key, which may lead to a protection exception if the
corresponding page has the fetch-protection bit enabled.

There is code in place which initializes the storage keys of such pages
when needed. However there is also the possibility of out-of-line execution
of such code in case a kprobe is set within such a region.

To avoid this problem prevent that any kprobe can be set within the
cmpxchg_user_key() functions.

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/lib/uaccess.c

index 02359c03b809533e2c6b1c3ca9e8a1ad951f2acc..750360cce02c0ca020e0025b0abedd476e04a0fd 100644 (file)
@@ -8,6 +8,7 @@
  *              Gerald Schaefer (gerald.schaefer@de.ibm.com)
  */
 
+#include <linux/kprobes.h>
 #include <linux/uaccess.h>
 #include <linux/export.h>
 #include <linux/mm.h>
@@ -149,8 +150,8 @@ EXPORT_SYMBOL(_copy_to_user_key);
 
 #define CMPXCHG_USER_KEY_MAX_LOOPS 128
 
-int __cmpxchg_user_key1(unsigned long address, unsigned char *uval,
-                       unsigned char old, unsigned char new, unsigned long key)
+int __kprobes __cmpxchg_user_key1(unsigned long address, unsigned char *uval,
+                                 unsigned char old, unsigned char new, unsigned long key)
 {
        unsigned int prev, shift, mask, _old, _new;
        unsigned long count;
@@ -208,8 +209,8 @@ int __cmpxchg_user_key1(unsigned long address, unsigned char *uval,
 }
 EXPORT_SYMBOL(__cmpxchg_user_key1);
 
-int __cmpxchg_user_key2(unsigned long address, unsigned short *uval,
-                       unsigned short old, unsigned short new, unsigned long key)
+int __kprobes __cmpxchg_user_key2(unsigned long address, unsigned short *uval,
+                                 unsigned short old, unsigned short new, unsigned long key)
 {
        unsigned int prev, shift, mask, _old, _new;
        unsigned long count;
@@ -267,8 +268,8 @@ int __cmpxchg_user_key2(unsigned long address, unsigned short *uval,
 }
 EXPORT_SYMBOL(__cmpxchg_user_key2);
 
-int __cmpxchg_user_key4(unsigned long address, unsigned int *uval,
-                       unsigned int old, unsigned int new, unsigned long key)
+int __kprobes __cmpxchg_user_key4(unsigned long address, unsigned int *uval,
+                                 unsigned int old, unsigned int new, unsigned long key)
 {
        unsigned int prev = old;
        bool sacf_flag;
@@ -299,8 +300,8 @@ int __cmpxchg_user_key4(unsigned long address, unsigned int *uval,
 }
 EXPORT_SYMBOL(__cmpxchg_user_key4);
 
-int __cmpxchg_user_key8(unsigned long address, unsigned long *uval,
-                       unsigned long old, unsigned long new, unsigned long key)
+int __kprobes __cmpxchg_user_key8(unsigned long address, unsigned long *uval,
+                                 unsigned long old, unsigned long new, unsigned long key)
 {
        unsigned long prev = old;
        bool sacf_flag;
@@ -331,8 +332,8 @@ int __cmpxchg_user_key8(unsigned long address, unsigned long *uval,
 }
 EXPORT_SYMBOL(__cmpxchg_user_key8);
 
-int __cmpxchg_user_key16(unsigned long address, __uint128_t *uval,
-                        __uint128_t old, __uint128_t new, unsigned long key)
+int __kprobes __cmpxchg_user_key16(unsigned long address, __uint128_t *uval,
+                                  __uint128_t old, __uint128_t new, unsigned long key)
 {
        __uint128_t prev = old;
        bool sacf_flag;