From: Heiko Carstens Date: Mon, 16 Jun 2025 15:00:32 +0000 (+0200) Subject: s390/uaccess: Prevent kprobes on cmpxchg_user_key() functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2b73ce90a7141d5aa34a52de82d69fbb68efc30;p=thirdparty%2Fkernel%2Fstable.git s390/uaccess: Prevent kprobes on cmpxchg_user_key() functions 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 Signed-off-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index 02359c03b809..750360cce02c 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -8,6 +8,7 @@ * Gerald Schaefer (gerald.schaefer@de.ibm.com) */ +#include #include #include #include @@ -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;