x86: use the new generic strnlen_user() function
This throws away the old x86-specific functions in favor of the generic optimized version. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
a08c5356a3
commit
5723aa993d
@ -94,6 +94,7 @@ config X86
|
|||||||
select GENERIC_TIME_VSYSCALL if X86_64
|
select GENERIC_TIME_VSYSCALL if X86_64
|
||||||
select KTIME_SCALAR if X86_32
|
select KTIME_SCALAR if X86_32
|
||||||
select GENERIC_STRNCPY_FROM_USER
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
|
select GENERIC_STRNLEN_USER
|
||||||
|
|
||||||
config INSTRUCTION_DECODER
|
config INSTRUCTION_DECODER
|
||||||
def_bool (KPROBES || PERF_EVENTS || UPROBES)
|
def_bool (KPROBES || PERF_EVENTS || UPROBES)
|
||||||
|
@ -566,6 +566,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
|
|||||||
extern __must_check long
|
extern __must_check long
|
||||||
strncpy_from_user(char *dst, const char __user *src, long count);
|
strncpy_from_user(char *dst, const char __user *src, long count);
|
||||||
|
|
||||||
|
extern __must_check long strlen_user(const char __user *str);
|
||||||
|
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* movsl can be slow when source and dest are not both 8-byte aligned
|
* movsl can be slow when source and dest are not both 8-byte aligned
|
||||||
*/
|
*/
|
||||||
|
@ -213,23 +213,6 @@ static inline unsigned long __must_check copy_from_user(void *to,
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* strlen_user: - Get the size of a string in user space.
|
|
||||||
* @str: The string to measure.
|
|
||||||
*
|
|
||||||
* Context: User context only. This function may sleep.
|
|
||||||
*
|
|
||||||
* Get the size of a NUL-terminated string in user space.
|
|
||||||
*
|
|
||||||
* Returns the size of the string INCLUDING the terminating NUL.
|
|
||||||
* On exception, returns 0.
|
|
||||||
*
|
|
||||||
* If there is a limit on the length of a valid string, you may wish to
|
|
||||||
* consider using strnlen_user() instead.
|
|
||||||
*/
|
|
||||||
#define strlen_user(str) strnlen_user(str, LONG_MAX)
|
|
||||||
|
|
||||||
long strnlen_user(const char __user *str, long n);
|
|
||||||
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
|
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
|
||||||
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
|
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
|
||||||
|
|
||||||
|
@ -208,9 +208,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__must_check long strnlen_user(const char __user *str, long n);
|
|
||||||
__must_check long __strnlen_user(const char __user *str, long n);
|
|
||||||
__must_check long strlen_user(const char __user *str);
|
|
||||||
__must_check unsigned long clear_user(void __user *mem, unsigned long len);
|
__must_check unsigned long clear_user(void __user *mem, unsigned long len);
|
||||||
__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
|
__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
|
||||||
|
|
||||||
|
@ -95,47 +95,6 @@ __clear_user(void __user *to, unsigned long n)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__clear_user);
|
EXPORT_SYMBOL(__clear_user);
|
||||||
|
|
||||||
/**
|
|
||||||
* strnlen_user: - Get the size of a string in user space.
|
|
||||||
* @s: The string to measure.
|
|
||||||
* @n: The maximum valid length
|
|
||||||
*
|
|
||||||
* Get the size of a NUL-terminated string in user space.
|
|
||||||
*
|
|
||||||
* Returns the size of the string INCLUDING the terminating NUL.
|
|
||||||
* On exception, returns 0.
|
|
||||||
* If the string is too long, returns a value greater than @n.
|
|
||||||
*/
|
|
||||||
long strnlen_user(const char __user *s, long n)
|
|
||||||
{
|
|
||||||
unsigned long mask = -__addr_ok(s);
|
|
||||||
unsigned long res, tmp;
|
|
||||||
|
|
||||||
might_fault();
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
" testl %0, %0\n"
|
|
||||||
" jz 3f\n"
|
|
||||||
" andl %0,%%ecx\n"
|
|
||||||
"0: repne; scasb\n"
|
|
||||||
" setne %%al\n"
|
|
||||||
" subl %%ecx,%0\n"
|
|
||||||
" addl %0,%%eax\n"
|
|
||||||
"1:\n"
|
|
||||||
".section .fixup,\"ax\"\n"
|
|
||||||
"2: xorl %%eax,%%eax\n"
|
|
||||||
" jmp 1b\n"
|
|
||||||
"3: movb $1,%%al\n"
|
|
||||||
" jmp 1b\n"
|
|
||||||
".previous\n"
|
|
||||||
_ASM_EXTABLE(0b,2b)
|
|
||||||
:"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp)
|
|
||||||
:"0" (n), "1" (s), "2" (0), "3" (mask)
|
|
||||||
:"cc");
|
|
||||||
return res & mask;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strnlen_user);
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_INTEL_USERCOPY
|
#ifdef CONFIG_X86_INTEL_USERCOPY
|
||||||
static unsigned long
|
static unsigned long
|
||||||
__copy_user_intel(void __user *to, const void *from, unsigned long size)
|
__copy_user_intel(void __user *to, const void *from, unsigned long size)
|
||||||
|
@ -52,54 +52,6 @@ unsigned long clear_user(void __user *to, unsigned long n)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(clear_user);
|
EXPORT_SYMBOL(clear_user);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the size of a string (including the ending 0)
|
|
||||||
*
|
|
||||||
* Return 0 on exception, a value greater than N if too long
|
|
||||||
*/
|
|
||||||
|
|
||||||
long __strnlen_user(const char __user *s, long n)
|
|
||||||
{
|
|
||||||
long res = 0;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (res>n)
|
|
||||||
return n+1;
|
|
||||||
if (__get_user(c, s))
|
|
||||||
return 0;
|
|
||||||
if (!c)
|
|
||||||
return res+1;
|
|
||||||
res++;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(__strnlen_user);
|
|
||||||
|
|
||||||
long strnlen_user(const char __user *s, long n)
|
|
||||||
{
|
|
||||||
if (!access_ok(VERIFY_READ, s, 1))
|
|
||||||
return 0;
|
|
||||||
return __strnlen_user(s, n);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strnlen_user);
|
|
||||||
|
|
||||||
long strlen_user(const char __user *s)
|
|
||||||
{
|
|
||||||
long res = 0;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (get_user(c, s))
|
|
||||||
return 0;
|
|
||||||
if (!c)
|
|
||||||
return res+1;
|
|
||||||
res++;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strlen_user);
|
|
||||||
|
|
||||||
unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
|
unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
|
||||||
{
|
{
|
||||||
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
|
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user