Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/vm/copyinout.c
2092 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <types.h>
31
#include <kern/errno.h>
32
#include <lib.h>
33
#include <setjmp.h>
34
#include <thread.h>
35
#include <current.h>
36
#include <vm.h>
37
#include <copyinout.h>
38
39
/*
40
* User/kernel memory copying functions.
41
*
42
* These are arranged to prevent fatal kernel memory faults if invalid
43
* addresses are supplied by user-level code. This code is itself
44
* machine-independent; it uses the machine-dependent C setjmp/longjmp
45
* facility to perform recovery.
46
*
47
* However, it assumes things about the memory subsystem that may not
48
* be true on all platforms.
49
*
50
* (1) It assumes that user memory is mapped into the current address
51
* space while running in the kernel, and can be accessed by just
52
* dereferencing a pointer in the ordinary way. (And not, for example,
53
* with special instructions or via special segment registers.)
54
*
55
* (2) It assumes that the user-space region of memory is contiguous
56
* and extends from 0 to some virtual address USERSPACETOP, and so if
57
* a user process passes a kernel address the logic in copycheck()
58
* will trap it.
59
*
60
* (3) It assumes that access to user memory from the kernel behaves
61
* the same way as access to user memory from user space: for
62
* instance, that the processor honors read-only bits on memory pages
63
* when in kernel mode.
64
*
65
* (4) It assumes that if a proper user-space address that is valid
66
* but not present, or not valid at all, is touched from the kernel,
67
* that the correct faults will occur and the VM system will load the
68
* necessary pages and whatnot.
69
*
70
* (5) It assumes that the machine-dependent trap logic provides and
71
* honors a tm_badfaultfunc field in the thread_machdep structure.
72
* This feature works as follows: if an otherwise fatal fault occurs
73
* in kernel mode, and tm_badfaultfunc is set, execution resumes in
74
* the function pointed to by tm_badfaultfunc.
75
*
76
* This code works by setting tm_badfaultfunc and then copying memory
77
* in an ordinary fashion. If these five assumptions are satisfied,
78
* which is the case for many ordinary CPU types, this code should
79
* function correctly. If the assumptions are not satisfied on some
80
* platform (for instance, certain old 80386 processors violate
81
* assumption 3), this code cannot be used, and cpu- or platform-
82
* specific code must be written.
83
*
84
* To make use of this code, in addition to tm_badfaultfunc the
85
* thread_machdep structure should contain a jmp_buf called
86
* "tm_copyjmp".
87
*/
88
89
/*
90
* Recovery function. If a fatal fault occurs during copyin, copyout,
91
* copyinstr, or copyoutstr, execution resumes here. (This behavior is
92
* caused by setting t_machdep.tm_badfaultfunc and is implemented in
93
* machine-dependent code.)
94
*
95
* We use the C standard function longjmp() to teleport up the call
96
* stack to where setjmp() was called. At that point we return EFAULT.
97
*/
98
static
99
void
100
copyfail(void)
101
{
102
longjmp(curthread->t_machdep.tm_copyjmp, 1);
103
}
104
105
/*
106
* Memory region check function. This checks to make sure the block of
107
* user memory provided (an address and a length) falls within the
108
* proper userspace region. If it does not, EFAULT is returned.
109
*
110
* stoplen is set to the actual maximum length that can be copied.
111
* This differs from len if and only if the region partially overlaps
112
* the kernel.
113
*
114
* Assumes userspace runs from 0 through USERSPACETOP-1.
115
*/
116
static
117
int
118
copycheck(const_userptr_t userptr, size_t len, size_t *stoplen)
119
{
120
vaddr_t bot, top;
121
122
*stoplen = len;
123
124
bot = (vaddr_t) userptr;
125
top = bot+len-1;
126
127
if (top < bot) {
128
/* addresses wrapped around */
129
return EFAULT;
130
}
131
132
if (bot >= USERSPACETOP) {
133
/* region is within the kernel */
134
return EFAULT;
135
}
136
137
if (top >= USERSPACETOP) {
138
/* region overlaps the kernel. adjust the max length. */
139
*stoplen = USERSPACETOP - bot;
140
}
141
142
return 0;
143
}
144
145
/*
146
* copyin
147
*
148
* Copy a block of memory of length LEN from user-level address USERSRC
149
* to kernel address DEST. We can use memcpy because it's protected by
150
* the tm_badfaultfunc/copyfail logic.
151
*/
152
int
153
copyin(const_userptr_t usersrc, void *dest, size_t len)
154
{
155
int result;
156
size_t stoplen;
157
158
result = copycheck(usersrc, len, &stoplen);
159
if (result) {
160
return result;
161
}
162
if (stoplen != len) {
163
/* Single block, can't legally truncate it. */
164
return EFAULT;
165
}
166
167
curthread->t_machdep.tm_badfaultfunc = copyfail;
168
169
result = setjmp(curthread->t_machdep.tm_copyjmp);
170
if (result) {
171
curthread->t_machdep.tm_badfaultfunc = NULL;
172
return EFAULT;
173
}
174
175
memcpy(dest, (const void *)usersrc, len);
176
177
curthread->t_machdep.tm_badfaultfunc = NULL;
178
return 0;
179
}
180
181
/*
182
* copyout
183
*
184
* Copy a block of memory of length LEN from kernel address SRC to
185
* user-level address USERDEST. We can use memcpy because it's
186
* protected by the tm_badfaultfunc/copyfail logic.
187
*/
188
int
189
copyout(const void *src, userptr_t userdest, size_t len)
190
{
191
int result;
192
size_t stoplen;
193
194
result = copycheck(userdest, len, &stoplen);
195
if (result) {
196
return result;
197
}
198
if (stoplen != len) {
199
/* Single block, can't legally truncate it. */
200
return EFAULT;
201
}
202
203
curthread->t_machdep.tm_badfaultfunc = copyfail;
204
205
result = setjmp(curthread->t_machdep.tm_copyjmp);
206
if (result) {
207
curthread->t_machdep.tm_badfaultfunc = NULL;
208
return EFAULT;
209
}
210
211
memcpy((void *)userdest, src, len);
212
213
curthread->t_machdep.tm_badfaultfunc = NULL;
214
return 0;
215
}
216
217
/*
218
* Common string copying function that behaves the way that's desired
219
* for copyinstr and copyoutstr.
220
*
221
* Copies a null-terminated string of maximum length MAXLEN from SRC
222
* to DEST. If GOTLEN is not null, store the actual length found
223
* there. Both lengths include the null-terminator. If the string
224
* exceeds the available length, the call fails and returns
225
* ENAMETOOLONG.
226
*
227
* STOPLEN is like MAXLEN but is assumed to have come from copycheck.
228
* If we hit MAXLEN it's because the string is too long to fit; if we
229
* hit STOPLEN it's because the string has run into the end of
230
* userspace. Thus in the latter case we return EFAULT, not
231
* ENAMETOOLONG.
232
*/
233
static
234
int
235
copystr(char *dest, const char *src, size_t maxlen, size_t stoplen,
236
size_t *gotlen)
237
{
238
size_t i;
239
240
for (i=0; i<maxlen && i<stoplen; i++) {
241
dest[i] = src[i];
242
if (src[i] == 0) {
243
if (gotlen != NULL) {
244
*gotlen = i+1;
245
}
246
return 0;
247
}
248
}
249
if (stoplen < maxlen) {
250
/* ran into user-kernel boundary */
251
return EFAULT;
252
}
253
/* otherwise just ran out of space */
254
return ENAMETOOLONG;
255
}
256
257
/*
258
* copyinstr
259
*
260
* Copy a string from user-level address USERSRC to kernel address
261
* DEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
262
* logic to protect against invalid addresses supplied by a user
263
* process.
264
*/
265
int
266
copyinstr(const_userptr_t usersrc, char *dest, size_t len, size_t *actual)
267
{
268
int result;
269
size_t stoplen;
270
271
result = copycheck(usersrc, len, &stoplen);
272
if (result) {
273
return result;
274
}
275
276
curthread->t_machdep.tm_badfaultfunc = copyfail;
277
278
result = setjmp(curthread->t_machdep.tm_copyjmp);
279
if (result) {
280
curthread->t_machdep.tm_badfaultfunc = NULL;
281
return EFAULT;
282
}
283
284
result = copystr(dest, (const char *)usersrc, len, stoplen, actual);
285
286
curthread->t_machdep.tm_badfaultfunc = NULL;
287
return result;
288
}
289
290
/*
291
* copyoutstr
292
*
293
* Copy a string from kernel address SRC to user-level address
294
* USERDEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
295
* logic to protect against invalid addresses supplied by a user
296
* process.
297
*/
298
int
299
copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *actual)
300
{
301
int result;
302
size_t stoplen;
303
304
result = copycheck(userdest, len, &stoplen);
305
if (result) {
306
return result;
307
}
308
309
curthread->t_machdep.tm_badfaultfunc = copyfail;
310
311
result = setjmp(curthread->t_machdep.tm_copyjmp);
312
if (result) {
313
curthread->t_machdep.tm_badfaultfunc = NULL;
314
return EFAULT;
315
}
316
317
result = copystr((char *)userdest, src, len, stoplen, actual);
318
319
curthread->t_machdep.tm_badfaultfunc = NULL;
320
return result;
321
}
322
323