]> Pileus Git - ~andy/linux/blob - lib/strncpy_from_user.c
Merge branch 'x86/mce' into x86/urgent
[~andy/linux] / lib / strncpy_from_user.c
1 #include <linux/module.h>
2 #include <linux/uaccess.h>
3 #include <linux/kernel.h>
4 #include <linux/errno.h>
5
6 #include <asm/byteorder.h>
7
8 static inline long find_zero(unsigned long mask)
9 {
10         long byte = 0;
11
12 #ifdef __BIG_ENDIAN
13 #ifdef CONFIG_64BIT
14         if (mask >> 32)
15                 mask >>= 32;
16         else
17                 byte = 4;
18 #endif
19         if (mask >> 16)
20                 mask >>= 16;
21         else
22                 byte += 2;
23         return (mask >> 8) ? byte : byte + 1;
24 #else
25 #ifdef CONFIG_64BIT
26         if (!((unsigned int) mask)) {
27                 mask >>= 32;
28                 byte = 4;
29         }
30 #endif
31         if (!(mask & 0xffff)) {
32                 mask >>= 16;
33                 byte += 2;
34         }
35         return (mask & 0xff) ? byte : byte + 1;
36 #endif
37 }
38
39 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
40 #define IS_UNALIGNED(src, dst)  0
41 #else
42 #define IS_UNALIGNED(src, dst)  \
43         (((long) dst | (long) src) & (sizeof(long) - 1))
44 #endif
45
46 /*
47  * Do a strncpy, return length of string without final '\0'.
48  * 'count' is the user-supplied count (return 'count' if we
49  * hit it), 'max' is the address space maximum (and we return
50  * -EFAULT if we hit it).
51  */
52 static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
53 {
54         const unsigned long high_bits = REPEAT_BYTE(0xfe) + 1;
55         const unsigned long low_bits = REPEAT_BYTE(0x7f);
56         long res = 0;
57
58         /*
59          * Truncate 'max' to the user-specified limit, so that
60          * we only have one limit we need to check in the loop
61          */
62         if (max > count)
63                 max = count;
64
65         if (IS_UNALIGNED(src, dst))
66                 goto byte_at_a_time;
67
68         while (max >= sizeof(unsigned long)) {
69                 unsigned long c, v, rhs;
70
71                 /* Fall back to byte-at-a-time if we get a page fault */
72                 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
73                         break;
74                 rhs = c | low_bits;
75                 v = (c + high_bits) & ~rhs;
76                 *(unsigned long *)(dst+res) = c;
77                 if (v) {
78                         v = (c & low_bits) + low_bits;
79                         v = ~(v | rhs);
80                         return res + find_zero(v);
81                 }
82                 res += sizeof(unsigned long);
83                 max -= sizeof(unsigned long);
84         }
85
86 byte_at_a_time:
87         while (max) {
88                 char c;
89
90                 if (unlikely(__get_user(c,src+res)))
91                         return -EFAULT;
92                 dst[res] = c;
93                 if (!c)
94                         return res;
95                 res++;
96                 max--;
97         }
98
99         /*
100          * Uhhuh. We hit 'max'. But was that the user-specified maximum
101          * too? If so, that's ok - we got as much as the user asked for.
102          */
103         if (res >= count)
104                 return res;
105
106         /*
107          * Nope: we hit the address space limit, and we still had more
108          * characters the caller would have wanted. That's an EFAULT.
109          */
110         return -EFAULT;
111 }
112
113 /**
114  * strncpy_from_user: - Copy a NUL terminated string from userspace.
115  * @dst:   Destination address, in kernel space.  This buffer must be at
116  *         least @count bytes long.
117  * @src:   Source address, in user space.
118  * @count: Maximum number of bytes to copy, including the trailing NUL.
119  *
120  * Copies a NUL-terminated string from userspace to kernel space.
121  *
122  * On success, returns the length of the string (not including the trailing
123  * NUL).
124  *
125  * If access to userspace fails, returns -EFAULT (some data may have been
126  * copied).
127  *
128  * If @count is smaller than the length of the string, copies @count bytes
129  * and returns @count.
130  */
131 long strncpy_from_user(char *dst, const char __user *src, long count)
132 {
133         unsigned long max_addr, src_addr;
134
135         if (unlikely(count <= 0))
136                 return 0;
137
138         max_addr = user_addr_max();
139         src_addr = (unsigned long)src;
140         if (likely(src_addr < max_addr)) {
141                 unsigned long max = max_addr - src_addr;
142                 return do_strncpy_from_user(dst, src, count, max);
143         }
144         return -EFAULT;
145 }
146 EXPORT_SYMBOL(strncpy_from_user);