user_strdup() forces null termination
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Aug 2010 20:30:23 +0000 (13:30 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:50 +0000 (17:35 -0700)
The previous version checked for it and failed if it wasn't null
terminated.  This one just makes it null-terminated, and clarifies it's
usage.  Specifically, it is meant for when we know a string's length,
which will be the case for all syscalls eventually (patch pending).

kern/include/umem.h
kern/src/syscall.c
kern/src/umem.c

index 77396fc..f76172b 100644 (file)
@@ -34,6 +34,6 @@ void *user_memdup(struct proc *p, const void *va, int len);
 void *user_memdup_errno(struct proc *p, const void *va, int len);
 void user_memdup_free(struct proc *p, void *va);
 /* Same as memdup, but just does strings.  still needs memdup_freed */
-char *user_strdup(struct proc *p, const char *va0, int max);
-char *user_strdup_errno(struct proc *p, const char *va, int max);
+char *user_strdup(struct proc *p, const char *u_string, size_t strlen);
+char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen);
 void *kmalloc_errno(int len);
index 37b1be5..4cdd42d 100644 (file)
@@ -205,9 +205,9 @@ static int sys_proc_create(struct proc *p, char *path, size_t path_l,
        struct file *program;
        struct proc *new_p;
 
-       /* Copy in the path.  Consider putting an upper bound. */
+       /* Copy in the path.  Consider putting an upper bound on path_l. */
        t_path = user_strdup_errno(p, path, path_l);
-       if (IS_ERR(t_path))
+       if (!t_path)
                return -1;
        program = do_file_open(t_path, 0, 0);
        user_memdup_free(p, t_path);
@@ -396,9 +396,10 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        /* We probably want it to never be allowed to exec if it ever was _M */
        if(p->state != PROC_RUNNING_S)
                return -1;
-       /* Copy in the path.  Consider putting an upper bound. */
+
+       /* Copy in the path.  Consider putting an upper bound on path_l. */
        t_path = user_strdup_errno(p, path, path_l);
-       if (IS_ERR(t_path))
+       if (!t_path)
                return -1;
        program = do_file_open(t_path, 0, 0);
        user_memdup_free(p, t_path);
index 5263d15..a974328 100644 (file)
@@ -290,40 +290,28 @@ void user_memdup_free(struct proc *p, void *va)
        kfree(va);
 }
 
-/* Same as memdup, but just does strings.  still needs memdup_freed */
-char *user_strdup(struct proc *p, const char *va0, int max)
+/* Same as memdup, but just does strings, and needs to know the actual strlen.
+ * Still needs memdup_free()d.  This will enforce that the string is null
+ * terminated.  The parameter strlen does not include the \0, though it can if
+ * someone else is playing it safe.  Since strlen() doesn't count the \0, we'll
+ * play it safe here. */
+char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
 {
-       max++;
-       char* kbuf = (char*)kmalloc(PGSIZE, 0);
-       if (kbuf == NULL)
-               return ERR_PTR(-ENOMEM);
-       int pos = 0, len = 0;
-       const char* va = va0;
-       while (max > 0 && len == 0) {
-               int thislen = MIN(PGSIZE - (uintptr_t)va % PGSIZE, max);
-               if (memcpy_from_user(p, kbuf, va, thislen)) {
-                       kfree(kbuf);
-                       return ERR_PTR(-EINVAL);
-               }
-               const char *nullterm = memchr(kbuf, 0, thislen);
-               if (nullterm)
-                       len = pos + (nullterm - kbuf) + 1;
-               pos += thislen;
-               va += thislen;
-               max -= thislen;
-       }
-       kfree(kbuf);
-       return len ? user_memdup(p, va0, len) : ERR_PTR(-EINVAL);
+       char *k_string = user_memdup(p, u_string, strlen + 1);
+       if (!IS_ERR(k_string))
+               k_string[strlen] = '\0';
+       return k_string;
 }
 
-char *user_strdup_errno(struct proc *p, const char *va, int max)
+/* user_strdup, but this handles the errno.  0 on failure, ptr on success */
+char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
 {
-       void *kva = user_strdup(p, va, max);
-       if (IS_ERR(kva)) {
-               set_errno(current_tf, -PTR_ERR(kva));
+       void *k_string = user_strdup(p, u_string, strlen);
+       if (IS_ERR(k_string)) {
+               set_errno(current_tf, -PTR_ERR(k_string));
                return NULL;
        }
-       return kva;
+       return k_string;
 }
 
 void *kmalloc_errno(int len)