mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 08:02:30 +00:00
s390/uaccess: fix __put_get_user_asm define
The __put_get_user_asm defines an inline assmembly which makes use of the asm register construct. The parameters passed to that define may also contain function calls. It is a gcc restriction that between register asm statements and the use of any such annotated variables function calls may clobber the register / variable contents. Or in other words: gcc would generate broken code. This can be achieved e.g. with the following code: get_user(x, func() ? a : b); where the call of func would clobber register zero which is used by the __put_get_user_asm define. To avoid this add two static inline functions which don't have these side effects. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
109ab95471
commit
dc4aace160
1 changed files with 59 additions and 2 deletions
|
@ -151,8 +151,65 @@ unsigned long __must_check __copy_to_user(void __user *to, const void *from,
|
||||||
__rc; \
|
__rc; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define __put_user_fn(x, ptr, size) __put_get_user_asm(ptr, x, size, 0x810000UL)
|
static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
|
||||||
#define __get_user_fn(x, ptr, size) __put_get_user_asm(x, ptr, size, 0x81UL)
|
{
|
||||||
|
unsigned long spec = 0x810000UL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
rc = __put_get_user_asm((unsigned char __user *)ptr,
|
||||||
|
(unsigned char *)x,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rc = __put_get_user_asm((unsigned short __user *)ptr,
|
||||||
|
(unsigned short *)x,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rc = __put_get_user_asm((unsigned int __user *)ptr,
|
||||||
|
(unsigned int *)x,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
rc = __put_get_user_asm((unsigned long __user *)ptr,
|
||||||
|
(unsigned long *)x,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long spec = 0x81UL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
rc = __put_get_user_asm((unsigned char *)x,
|
||||||
|
(unsigned char __user *)ptr,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rc = __put_get_user_asm((unsigned short *)x,
|
||||||
|
(unsigned short __user *)ptr,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rc = __put_get_user_asm((unsigned int *)x,
|
||||||
|
(unsigned int __user *)ptr,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
rc = __put_get_user_asm((unsigned long *)x,
|
||||||
|
(unsigned long __user *)ptr,
|
||||||
|
size, spec);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */
|
#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue