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