printk: check for user pointers in format string parameters
[akaros.git] / kern / src / umem.c
1 /* Copyright (c) 2009, 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * Andrew Waterman <waterman@cs.berkeley.edu>
4  * See LICENSE for details.
5  *
6  * Functions for working with userspace's address space.  The user_mem ones need
7  * to involve some form of pinning (TODO), and that global static needs to go. */
8
9 #include <ros/common.h>
10 #include <arch/uaccess.h>
11 #include <umem.h>
12 #include <process.h>
13 #include <error.h>
14 #include <kmalloc.h>
15 #include <assert.h>
16 #include <pmap.h>
17 #include <smp.h>
18
19 static int string_copy_from_user(char *dst, const char *src)
20 {
21         int error;
22         const char *top = src + valid_user_rbytes_from(src);
23
24         for (;; dst++, src++) {
25                 if (unlikely(src >= top))
26                         return -EFAULT;
27                 error = __get_user(dst, src, 1);
28                 if (unlikely(error))
29                         return error;
30                 if (unlikely(!*dst))
31                         break;
32         }
33
34         return 0;
35 }
36
37 static int string_copy_to_user(char *dst, const char *src)
38 {
39         int error;
40         char *top = dst + valid_user_rwbytes_from(dst);
41
42         for (;; dst++, src++) {
43                 if (unlikely(dst >= top))
44                         return -EFAULT;
45                 error = __put_user(dst, src, 1);
46                 if (unlikely(error))
47                         return error;
48                 if (unlikely(!*src))
49                         break;
50         }
51
52         return 0;
53 }
54
55 int strcpy_from_user(struct proc *p, char *dst, const char *src)
56 {
57         uintptr_t prev = switch_to(p);
58         int error = string_copy_from_user(dst, src);
59
60         switch_back(p, prev);
61
62         return error;
63 }
64
65 int strcpy_to_user(struct proc *p, char *dst, const char *src)
66 {
67         uintptr_t prev = switch_to(p);
68         int error = string_copy_to_user(dst, src);
69
70         switch_back(p, prev);
71
72         return error;
73 }
74
75 int memcpy_from_user(struct proc *p, void *dest, const void *va, size_t len)
76 {
77         uintptr_t prev = switch_to(p);
78         int error = copy_from_user(dest, va, len);
79
80         switch_back(p, prev);
81
82         return error;
83 }
84
85 int memcpy_to_user(struct proc *p, void *dest, const void *src, size_t len)
86 {
87         uintptr_t prev = switch_to(p);
88         int error = copy_to_user(dest, src, len);
89
90         switch_back(p, prev);
91
92         return error;
93 }
94
95 /* Same as above, but sets errno */
96 int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len)
97 {
98         int error = memcpy_from_user(p, dst, src, len);
99
100         if (unlikely(error < 0))
101                 set_errno(-error);
102
103         return error;
104 }
105
106 /* Same as above, but sets errno */
107 int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len)
108 {
109         int error = memcpy_to_user(p, dst, src, len);
110
111         if (unlikely(error < 0))
112                 set_errno(-error);
113
114         return error;
115 }
116
117 /* Helpers for FSs that don't care if they copy to the user or the kernel.
118  *
119  * TODO: (KFOP) Probably shouldn't do this.  Either memcpy directly, or split
120  * out the is_user_r(w)addr from copy_{to,from}_user().  Or throw from the fault
121  * handler.  Right now, we ignore the ret/errors completely. */
122 int memcpy_to_safe(void *dst, const void *src, size_t amt)
123 {
124         int error = 0;
125
126         if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
127                 error = memcpy_to_user(current, dst, src, amt);
128         else
129                 memcpy(dst, src, amt);
130         return error;
131 }
132
133 int memcpy_from_safe(void *dst, const void *src, size_t amt)
134 {
135         int error = 0;
136
137         if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
138                 error = memcpy_from_user(current, dst, src, amt);
139         else
140                 memcpy(dst, src, amt);
141         return error;
142 }
143
144 /* Creates a buffer (kmalloc) and safely copies into it from va.  Can return an
145  * error code.  Check its response with IS_ERR().  Must be paired with
146  * user_memdup_free() if this succeeded. */
147 void *user_memdup(struct proc *p, const void *va, int len)
148 {
149         void* kva = NULL;
150
151         if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
152                 return ERR_PTR(-ENOMEM);
153         if (memcpy_from_user(p, kva, va, len)) {
154                 kfree(kva);
155                 return ERR_PTR(-EFAULT);
156         }
157         return kva;
158 }
159
160 void *user_memdup_errno(struct proc *p, const void *va, int len)
161 {
162         void *kva = user_memdup(p, va, len);
163
164         if (IS_ERR(kva)) {
165                 set_errno(-PTR_ERR(kva));
166                 return NULL;
167         }
168         return kva;
169 }
170
171 void user_memdup_free(struct proc *p, void *va)
172 {
173         kfree(va);
174 }
175
176 /* Same as memdup, but just does strings, and needs to know the actual strlen.
177  * Still needs memdup_free()d.  This will enforce that the string is null
178  * terminated.  The parameter strlen does not include the \0, though it can if
179  * someone else is playing it safe.  Since strlen() doesn't count the \0, we'll
180  * play it safe here. */
181 char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
182 {
183         char *k_string = user_memdup(p, u_string, strlen + 1);
184
185         if (!IS_ERR(k_string))
186                 k_string[strlen] = '\0';
187         return k_string;
188 }
189
190 /* user_strdup, but this handles the errno.  0 on failure, ptr on success */
191 char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
192 {
193         void *k_string = user_strdup(p, u_string, strlen);
194         if (IS_ERR(k_string)) {
195                 set_errno(-PTR_ERR(k_string));
196                 return NULL;
197         }
198         return k_string;
199 }
200
201 void *kmalloc_errno(int len)
202 {
203         void *kva = NULL;
204
205         if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
206                 set_errno(ENOMEM);
207         return kva;
208 }
209
210 /* Returns true if uva and kva both resolve to the same phys addr.  If uva is
211  * unmapped, it will return FALSE.  This is probably what you want, since after
212  * all uva isn't kva. */
213 bool uva_is_kva(struct proc *p, void *uva, void *kva)
214 {
215         struct page *u_page;
216         assert(kva);                            /* catch bugs */
217
218         /* Check offsets first */
219         if (PGOFF(uva) != PGOFF(kva))
220                 return FALSE;
221         /* Check to see if it is the same physical page */
222         u_page = page_lookup(p->env_pgdir, uva, 0);
223         if (!u_page)
224                 return FALSE;
225         return (kva2page(kva) == u_page) ? TRUE : FALSE;
226 }
227
228 /* Given a proc and a user virtual address, gives us the KVA.  Useful for
229  * debugging.  Returns 0 if the page is unmapped (page lookup fails).  This
230  * doesn't play nice with Jumbo pages. */
231 uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot)
232 {
233         struct page *u_page;
234         uintptr_t offset = PGOFF(uva);
235
236         if (!p)
237                 return 0;
238         if (prot & PROT_WRITE) {
239                 if (!is_user_rwaddr(uva, len))
240                         return 0;
241         } else {
242                 if (!is_user_raddr(uva, len))
243                         return 0;
244         }
245         u_page = page_lookup(p->env_pgdir, uva, 0);
246         if (!u_page)
247                 return 0;
248         return (uintptr_t)page2kva(u_page) + offset;
249 }
250
251 /* Helper, copies a pathname from the process into the kernel.  Returns a string
252  * on success, which you must free with free_path.  Returns 0 on failure and
253  * sets errno. */
254 char *copy_in_path(struct proc *p, const char *path, size_t path_l)
255 {
256         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
257         char *t_path;
258
259         /* PATH_MAX includes the \0 */
260         if (path_l > PATH_MAX) {
261                 set_errno(ENAMETOOLONG);
262                 return 0;
263         }
264         t_path = user_strdup_errno(p, path, path_l);
265         if (!t_path)
266                 return 0;
267         return t_path;
268 }
269
270 /* Helper, frees a path that was allocated with copy_in_path. */
271 void free_path(struct proc *p, char *t_path)
272 {
273         user_memdup_free(p, t_path);
274 }