Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 298921
b: refs/heads/master
c: 92ae03f
h: refs/heads/master
i:
  298919: 914aa47
v: v3
  • Loading branch information
Linus Torvalds committed Apr 11, 2012
1 parent a559a67 commit 9a813c7
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 146 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 79549c6dfda0603dba9a70a53467ce62d9335c33
refs/heads/master: 92ae03f2ef99fbc23bfa9080d6b58f25227bd7ef
2 changes: 2 additions & 0 deletions trunk/arch/x86/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,8 @@ struct __large_struct { unsigned long buf[100]; };

extern unsigned long
copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
extern __must_check long
strncpy_from_user(char *dst, const char __user *src, long count);

/*
* movsl can be slow when source and dest are not both 8-byte aligned
Expand Down
5 changes: 0 additions & 5 deletions trunk/arch/x86/include/asm/uaccess_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,6 @@ static inline unsigned long __must_check copy_from_user(void *to,
return n;
}

long __must_check strncpy_from_user(char *dst, const char __user *src,
long count);
long __must_check __strncpy_from_user(char *dst,
const char __user *src, long count);

/**
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
Expand Down
4 changes: 0 additions & 4 deletions trunk/arch/x86/include/asm/uaccess_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
}
}

__must_check long
strncpy_from_user(char *dst, const char __user *src, long count);
__must_check long
__strncpy_from_user(char *dst, const char __user *src, long count);
__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);
Expand Down
103 changes: 103 additions & 0 deletions trunk/arch/x86/lib/usercopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <linux/highmem.h>
#include <linux/module.h>

#include <asm/word-at-a-time.h>

/*
* best effort, GUP based copy_from_user() that is NMI-safe
*/
Expand Down Expand Up @@ -41,3 +43,104 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
return len;
}
EXPORT_SYMBOL_GPL(copy_from_user_nmi);

static inline unsigned long count_bytes(unsigned long mask)
{
mask = (mask - 1) & ~mask;
mask >>= 7;
return count_masked_bytes(mask);
}

/*
* Do a strncpy, return length of string without final '\0'.
* 'count' is the user-supplied count (return 'count' if we
* hit it), 'max' is the address space maximum (and we return
* -EFAULT if we hit it).
*/
static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, long max)
{
long res = 0;

/*
* Truncate 'max' to the user-specified limit, so that
* we only have one limit we need to check in the loop
*/
if (max > count)
max = count;

while (max >= sizeof(unsigned long)) {
unsigned long c;

/* Fall back to byte-at-a-time if we get a page fault */
if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
break;
/* This can write a few bytes past the NUL character, but that's ok */
*(unsigned long *)(dst+res) = c;
c = has_zero(c);
if (c)
return res + count_bytes(c);
res += sizeof(unsigned long);
max -= sizeof(unsigned long);
}

while (max) {
char c;

if (unlikely(__get_user(c,src+res)))
return -EFAULT;
dst[res] = c;
if (!c)
return res;
res++;
max--;
}

/*
* Uhhuh. We hit 'max'. But was that the user-specified maximum
* too? If so, that's ok - we got as much as the user asked for.
*/
if (res >= count)
return count;

/*
* Nope: we hit the address space limit, and we still had more
* characters the caller would have wanted. That's an EFAULT.
*/
return -EFAULT;
}

/**
* strncpy_from_user: - Copy a NUL terminated string from userspace.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long
strncpy_from_user(char *dst, const char __user *src, long count)
{
unsigned long max_addr, src_addr;

if (unlikely(count <= 0))
return 0;

max_addr = current_thread_info()->addr_limit.seg;
src_addr = (unsigned long)src;
if (likely(src_addr < max_addr)) {
unsigned long max = max_addr - src_addr;
return do_strncpy_from_user(dst, src, count, max);
}
return -EFAULT;
}
EXPORT_SYMBOL(strncpy_from_user);
87 changes: 0 additions & 87 deletions trunk/arch/x86/lib/usercopy_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,93 +32,6 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon
#define movsl_is_ok(a1, a2, n) \
__movsl_is_ok((unsigned long)(a1), (unsigned long)(a2), (n))

/*
* Copy a null terminated string from userspace.
*/

#define __do_strncpy_from_user(dst, src, count, res) \
do { \
int __d0, __d1, __d2; \
might_fault(); \
__asm__ __volatile__( \
" testl %1,%1\n" \
" jz 2f\n" \
"0: lodsb\n" \
" stosb\n" \
" testb %%al,%%al\n" \
" jz 1f\n" \
" decl %1\n" \
" jnz 0b\n" \
"1: subl %1,%0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(0b,3b) \
: "=&d"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \
"=&D" (__d2) \
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
: "memory"); \
} while (0)

/**
* __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
* Caller must check the specified block with access_ok() before calling
* this function.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long
__strncpy_from_user(char *dst, const char __user *src, long count)
{
long res;
__do_strncpy_from_user(dst, src, count, res);
return res;
}
EXPORT_SYMBOL(__strncpy_from_user);

/**
* strncpy_from_user: - Copy a NUL terminated string from userspace.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long
strncpy_from_user(char *dst, const char __user *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1))
__do_strncpy_from_user(dst, src, count, res);
return res;
}
EXPORT_SYMBOL(strncpy_from_user);

/*
* Zero Userspace
*/
Expand Down
49 changes: 0 additions & 49 deletions trunk/arch/x86/lib/usercopy_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,6 @@
#include <linux/module.h>
#include <asm/uaccess.h>

/*
* Copy a null terminated string from userspace.
*/

#define __do_strncpy_from_user(dst,src,count,res) \
do { \
long __d0, __d1, __d2; \
might_fault(); \
__asm__ __volatile__( \
" testq %1,%1\n" \
" jz 2f\n" \
"0: lodsb\n" \
" stosb\n" \
" testb %%al,%%al\n" \
" jz 1f\n" \
" decq %1\n" \
" jnz 0b\n" \
"1: subq %1,%0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movq %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(0b,3b) \
: "=&r"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \
"=&D" (__d2) \
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
: "memory"); \
} while (0)

long
__strncpy_from_user(char *dst, const char __user *src, long count)
{
long res;
__do_strncpy_from_user(dst, src, count, res);
return res;
}
EXPORT_SYMBOL(__strncpy_from_user);

long
strncpy_from_user(char *dst, const char __user *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1))
return __strncpy_from_user(dst, src, count);
return res;
}
EXPORT_SYMBOL(strncpy_from_user);

/*
* Zero Userspace
*/
Expand Down

0 comments on commit 9a813c7

Please sign in to comment.