1 /*
2 * Copyright (c) 2006-2023 Ali Mashtizadeh
3 * All rights reserved.
4 * Generic Copyin/Copyout routines
5 */
6
7 #include <stdbool.h>
8 #include <stdint.h>
9
10 #include <errno.h>
11
12 #include <sys/kassert.h>
13 #include <machine/pmap.h>
14
15 extern int copy_unsafe(void *to_addr, void *from_addr, uintptr_t len);
16 extern int copystr_unsafe(void *to_addr, void *from_addr, uintptr_t len);
17
18 /**
19 * Copy_In --
20 *
21 * Safely copy memory from userspace. Prevents userspace pointers from
22 * reading kernel memory.
23 *
24 * Side effects:
25 * Kernel page fault may have occurred.
26 *
27 * @param [in] fromuser User address to copy from.
28 * @param [in] tokernel Kernel address to copy to.
29 * @param [in] len Length of the data to copy.
30 *
31 * @retval EFAULT if the address is invalid or causes a fault.
32 */
33 int
Copy_In(uintptr_t fromuser,void * tokernel,uintptr_t len)34 Copy_In(uintptr_t fromuser, void *tokernel, uintptr_t len)
35 {
36 if (len == 0)
37 return 0;
38
39 // Kernel space
40 if (fromuser >= MEM_USERSPACE_TOP) {
41 kprintf("Copy_In: address exceeds userspace top\n");
42 return EFAULT;
43 }
44
45 // Wrap around
46 if (len > (MEM_USERSPACE_TOP - fromuser)) {
47 kprintf("Copy_In: length exceeds userspace top\n");
48 return EFAULT;
49 }
50
51 return copy_unsafe(tokernel, (void *)fromuser, len);
52 }
53
54 /**
55 * Copy_Out --
56 *
57 * Safely copy memory to userspace. Prevents userspace pointers from
58 * writing kernel memory.
59 *
60 * Side effects:
61 * Kernel page fault may have occurred.
62 *
63 * @param [in] fromkernel Kernel address to copy from.
64 * @param [in] touser User address to copy to.
65 * @param [in] len Length of the data to copy.
66 *
67 * @retval EFAULT if the address is invalid or causes a fault.
68 */
69 int
Copy_Out(void * fromkernel,uintptr_t touser,uintptr_t len)70 Copy_Out(void *fromkernel, uintptr_t touser, uintptr_t len)
71 {
72 if (len == 0)
73 return 0;
74
75 // Kernel space
76 if (touser >= MEM_USERSPACE_TOP) {
77 kprintf("Copy_Out: address exceeds userspace top\n");
78 return EFAULT;
79 }
80
81 // Wrap around
82 if (len > (MEM_USERSPACE_TOP - touser)) {
83 kprintf("Copy_Out: length exceeds userspace top\n");
84 return EFAULT;
85 }
86
87 return copy_unsafe((void *)touser, fromkernel, len);
88 }
89
90 /**
91 * Copy_StrIn --
92 *
93 * Safely copy a string from userspace. Prevents userspace pointers from
94 * reading kernel memory.
95 *
96 * Side effects:
97 * Kernel page fault may have occurred.
98 *
99 * @param [in] fromuser User address to copy from.
100 * @param [in] tokernel Kernel address to copy to.
101 * @param [in] len Maximum string length.
102 *
103 * @retval EFAULT if the address is invalid or causes a fault.
104 */
105 int
Copy_StrIn(uintptr_t fromuser,void * tokernel,uintptr_t len)106 Copy_StrIn(uintptr_t fromuser, void *tokernel, uintptr_t len)
107 {
108 if (len == 0)
109 return 0;
110
111 // Kernel space
112 if (fromuser >= MEM_USERSPACE_TOP) {
113 kprintf("Copy_StrIn: address exceeds userspace top\n");
114 return EFAULT;
115 }
116
117 // Wrap around
118 if (len > (MEM_USERSPACE_TOP - fromuser)) {
119 kprintf("Copy_StrIn: length exceeds userspace top\n");
120 return EFAULT;
121 }
122
123 return copystr_unsafe(tokernel, (void *)fromuser, len);
124 }
125
126 /**
127 * Copy_StrOut --
128 *
129 * Safely copy a string to userspace. Prevents userspace pointers from
130 * writing kernel memory.
131 *
132 * Side effects:
133 * Kernel page fault may have occurred.
134 *
135 * @param [in] fromkernel Kernel address to copy from.
136 * @param [in] touser User address to copy to.
137 * @param [in] len Maximum string length.
138 *
139 * @retval EFAULT if the address is invalid or causes a fault.
140 */
141 int
Copy_StrOut(void * fromkernel,uintptr_t touser,uintptr_t len)142 Copy_StrOut(void *fromkernel, uintptr_t touser, uintptr_t len)
143 {
144 if (len == 0)
145 return 0;
146
147 // Kernel space
148 if (touser >= MEM_USERSPACE_TOP) {
149 kprintf("Copy_StrOut: address exceeds userspace top\n");
150 return EFAULT;
151 }
152
153 // Wrap around
154 if (len > (MEM_USERSPACE_TOP - touser)) {
155 kprintf("Copy_StrOut: length exceeds userspace top\n");
156 return EFAULT;
157 }
158
159 return copystr_unsafe((void *)touser, fromkernel, len);
160 }
161
162