Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/lib/usercopy_64.c
10817 views
1
/*
2
* User address space access functions.
3
*
4
* Copyright 1997 Andi Kleen <[email protected]>
5
* Copyright 1997 Linus Torvalds
6
* Copyright 2002 Andi Kleen <[email protected]>
7
*/
8
#include <linux/module.h>
9
#include <asm/uaccess.h>
10
11
/*
12
* Copy a null terminated string from userspace.
13
*/
14
15
#define __do_strncpy_from_user(dst,src,count,res) \
16
do { \
17
long __d0, __d1, __d2; \
18
might_fault(); \
19
__asm__ __volatile__( \
20
" testq %1,%1\n" \
21
" jz 2f\n" \
22
"0: lodsb\n" \
23
" stosb\n" \
24
" testb %%al,%%al\n" \
25
" jz 1f\n" \
26
" decq %1\n" \
27
" jnz 0b\n" \
28
"1: subq %1,%0\n" \
29
"2:\n" \
30
".section .fixup,\"ax\"\n" \
31
"3: movq %5,%0\n" \
32
" jmp 2b\n" \
33
".previous\n" \
34
_ASM_EXTABLE(0b,3b) \
35
: "=&r"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \
36
"=&D" (__d2) \
37
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
38
: "memory"); \
39
} while (0)
40
41
long
42
__strncpy_from_user(char *dst, const char __user *src, long count)
43
{
44
long res;
45
__do_strncpy_from_user(dst, src, count, res);
46
return res;
47
}
48
EXPORT_SYMBOL(__strncpy_from_user);
49
50
long
51
strncpy_from_user(char *dst, const char __user *src, long count)
52
{
53
long res = -EFAULT;
54
if (access_ok(VERIFY_READ, src, 1))
55
return __strncpy_from_user(dst, src, count);
56
return res;
57
}
58
EXPORT_SYMBOL(strncpy_from_user);
59
60
/*
61
* Zero Userspace
62
*/
63
64
unsigned long __clear_user(void __user *addr, unsigned long size)
65
{
66
long __d0;
67
might_fault();
68
/* no memory constraint because it doesn't change any memory gcc knows
69
about */
70
asm volatile(
71
" testq %[size8],%[size8]\n"
72
" jz 4f\n"
73
"0: movq %[zero],(%[dst])\n"
74
" addq %[eight],%[dst]\n"
75
" decl %%ecx ; jnz 0b\n"
76
"4: movq %[size1],%%rcx\n"
77
" testl %%ecx,%%ecx\n"
78
" jz 2f\n"
79
"1: movb %b[zero],(%[dst])\n"
80
" incq %[dst]\n"
81
" decl %%ecx ; jnz 1b\n"
82
"2:\n"
83
".section .fixup,\"ax\"\n"
84
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
85
" jmp 2b\n"
86
".previous\n"
87
_ASM_EXTABLE(0b,3b)
88
_ASM_EXTABLE(1b,2b)
89
: [size8] "=&c"(size), [dst] "=&D" (__d0)
90
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
91
[zero] "r" (0UL), [eight] "r" (8UL));
92
return size;
93
}
94
EXPORT_SYMBOL(__clear_user);
95
96
unsigned long clear_user(void __user *to, unsigned long n)
97
{
98
if (access_ok(VERIFY_WRITE, to, n))
99
return __clear_user(to, n);
100
return n;
101
}
102
EXPORT_SYMBOL(clear_user);
103
104
/*
105
* Return the size of a string (including the ending 0)
106
*
107
* Return 0 on exception, a value greater than N if too long
108
*/
109
110
long __strnlen_user(const char __user *s, long n)
111
{
112
long res = 0;
113
char c;
114
115
while (1) {
116
if (res>n)
117
return n+1;
118
if (__get_user(c, s))
119
return 0;
120
if (!c)
121
return res+1;
122
res++;
123
s++;
124
}
125
}
126
EXPORT_SYMBOL(__strnlen_user);
127
128
long strnlen_user(const char __user *s, long n)
129
{
130
if (!access_ok(VERIFY_READ, s, 1))
131
return 0;
132
return __strnlen_user(s, n);
133
}
134
EXPORT_SYMBOL(strnlen_user);
135
136
long strlen_user(const char __user *s)
137
{
138
long res = 0;
139
char c;
140
141
for (;;) {
142
if (get_user(c, s))
143
return 0;
144
if (!c)
145
return res+1;
146
res++;
147
s++;
148
}
149
}
150
EXPORT_SYMBOL(strlen_user);
151
152
unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
153
{
154
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
155
return copy_user_generic((__force void *)to, (__force void *)from, len);
156
}
157
return len;
158
}
159
EXPORT_SYMBOL(copy_in_user);
160
161
/*
162
* Try to copy last bytes and clear the rest if needed.
163
* Since protection fault in copy_from/to_user is not a normal situation,
164
* it is not necessary to optimize tail handling.
165
*/
166
unsigned long
167
copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
168
{
169
char c;
170
unsigned zero_len;
171
172
for (; len; --len) {
173
if (__get_user_nocheck(c, from++, sizeof(char)))
174
break;
175
if (__put_user_nocheck(c, to++, sizeof(char)))
176
break;
177
}
178
179
for (c = 0, zero_len = len; zerorest && zero_len; --zero_len)
180
if (__put_user_nocheck(c, to++, sizeof(char)))
181
break;
182
return len;
183
}
184
185