Sanitize vcoreid from untrusted sources
[akaros.git] / kern / src / umem.c
index 94753ba..5863ffe 100644 (file)
@@ -114,12 +114,40 @@ int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len)
        return error;
 }
 
+/* Helpers for FSs that don't care if they copy to the user or the kernel.
+ *
+ * TODO: (KFOP) Probably shouldn't do this.  Either memcpy directly, or split
+ * out the is_user_r(w)addr from copy_{to,from}_user().  Or throw from the fault
+ * handler.  Right now, we ignore the ret/errors completely. */
+int memcpy_to_safe(void *dst, const void *src, size_t amt)
+{
+       int error = 0;
+
+       if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
+               error = memcpy_to_user(current, dst, src, amt);
+       else
+               memcpy(dst, src, amt);
+       return error;
+}
+
+int memcpy_from_safe(void *dst, const void *src, size_t amt)
+{
+       int error = 0;
+
+       if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
+               error = memcpy_from_user(current, dst, src, amt);
+       else
+               memcpy(dst, src, amt);
+       return error;
+}
+
 /* Creates a buffer (kmalloc) and safely copies into it from va.  Can return an
  * error code.  Check its response with IS_ERR().  Must be paired with
  * user_memdup_free() if this succeeded. */
 void *user_memdup(struct proc *p, const void *va, int len)
 {
        void* kva = NULL;
+
        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
                return ERR_PTR(-ENOMEM);
        if (memcpy_from_user(p, kva, va, len)) {
@@ -132,6 +160,7 @@ void *user_memdup(struct proc *p, const void *va, int len)
 void *user_memdup_errno(struct proc *p, const void *va, int len)
 {
        void *kva = user_memdup(p, va, len);
+
        if (IS_ERR(kva)) {
                set_errno(-PTR_ERR(kva));
                return NULL;
@@ -152,6 +181,7 @@ void user_memdup_free(struct proc *p, void *va)
 char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
 {
        char *k_string = user_memdup(p, u_string, strlen + 1);
+
        if (!IS_ERR(k_string))
                k_string[strlen] = '\0';
        return k_string;
@@ -171,6 +201,7 @@ char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
 void *kmalloc_errno(int len)
 {
        void *kva = NULL;
+
        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
                set_errno(ENOMEM);
        return kva;
@@ -183,6 +214,7 @@ bool uva_is_kva(struct proc *p, void *uva, void *kva)
 {
        struct page *u_page;
        assert(kva);                            /* catch bugs */
+
        /* Check offsets first */
        if (PGOFF(uva) != PGOFF(kva))
                return FALSE;
@@ -194,15 +226,22 @@ bool uva_is_kva(struct proc *p, void *uva, void *kva)
 }
 
 /* Given a proc and a user virtual address, gives us the KVA.  Useful for
- * debugging.  Returns 0 if the page is unmapped (page lookup fails).  If you
- * give it a kva, it'll give you that same KVA, but this doesn't play nice with
- * Jumbo pages. */
-uintptr_t uva2kva(struct proc *p, void *uva)
+ * debugging.  Returns 0 if the page is unmapped (page lookup fails).  This
+ * doesn't play nice with Jumbo pages. */
+uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot)
 {
        struct page *u_page;
        uintptr_t offset = PGOFF(uva);
+
        if (!p)
                return 0;
+       if (prot & PROT_WRITE) {
+               if (!is_user_rwaddr(uva, len))
+                       return 0;
+       } else {
+               if (!is_user_raddr(uva, len))
+                       return 0;
+       }
        u_page = page_lookup(p->env_pgdir, uva, 0);
        if (!u_page)
                return 0;
@@ -211,12 +250,10 @@ uintptr_t uva2kva(struct proc *p, void *uva)
 
 /* Helper, copies a pathname from the process into the kernel.  Returns a string
  * on success, which you must free with free_path.  Returns 0 on failure and
- * sets errno.  On success, if you are tracing syscalls, it will store the
- * t_path in the trace data, clobbering whatever previously there. */
+ * sets errno. */
 char *copy_in_path(struct proc *p, const char *path, size_t path_l)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
-       struct systrace_record *t = pcpui->cur_kthread->trace;
        char *t_path;
 
        /* PATH_MAX includes the \0 */
@@ -227,10 +264,6 @@ char *copy_in_path(struct proc *p, const char *path, size_t path_l)
        t_path = user_strdup_errno(p, path, path_l);
        if (!t_path)
                return 0;
-       if (t) {
-               t->datalen = MIN(sizeof(t->data), path_l);
-               memcpy(t->data, t_path, t->datalen);
-       }
        return t_path;
 }