diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/mem/virt.h | 13 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 12 | ||||
-rw-r--r-- | src/kernel/tests/vfs.c | 6 | ||||
-rw-r--r-- | src/kernel/vfs/path.c | 27 |
4 files changed, 34 insertions, 24 deletions
diff --git a/src/kernel/mem/virt.h b/src/kernel/mem/virt.h index 3a42e9e..b858bdd 100644 --- a/src/kernel/mem/virt.h +++ b/src/kernel/mem/virt.h @@ -1,5 +1,6 @@ /* contains utilities for interacting with virtual memory */ #pragma once +#include <kernel/mem/alloc.h> #include <shared/types.h> #include <stdbool.h> #include <stddef.h> @@ -38,3 +39,15 @@ static inline bool virt_cpy_from(struct pagedir *src_pages, // virtual -> physic void *dest, const void __user *src, size_t length) { return virt_cpy(NULL, (userptr_t)dest, src_pages, src, length); } + +/** Copies a chunk of virtual memory to a newly kmalloc'd buffer. */ +static inline void *virt_cpy2kmalloc(struct pagedir *src_pages, + const void __user *src, size_t length) { + void *buf = kmalloc(length); + if (virt_cpy_from(src_pages, buf, src, length)) { + return buf; + } else { + kfree(buf); + return NULL; + } +} diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 5cee090..9a9b5d6 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -49,10 +49,8 @@ handle_t _syscall_open(const char __user *path, int len) { if (process_find_handle(process_current) < 0) return -1; - // copy the path to the kernel, simplify it - path_buf = kmalloc(len); // gets freed in vfs_request_finish - if (!virt_cpy_from(process_current->pages, path_buf, path, len)) - goto fail; + path_buf = virt_cpy2kmalloc(process_current->pages, path, len); + if (!path_buf) goto fail; len = path_simplify(path_buf, path_buf, len); if (len < 0) goto fail; @@ -90,9 +88,9 @@ int _syscall_mount(handle_t handle, const char __user *path, int len) { if (PATH_MAX < len) return -1; // copy the path to the kernel to simplify it - path_buf = kmalloc(len); - if (!virt_cpy_from(process_current->pages, path_buf, path, len)) - goto fail; + path_buf = virt_cpy2kmalloc(process_current->pages, path, len); + if (!path_buf) goto fail; + len = path_simplify(path_buf, path_buf, len); if (len < 0) goto fail; diff --git a/src/kernel/tests/vfs.c b/src/kernel/tests/vfs.c index 8b450e5..339c6bd 100644 --- a/src/kernel/tests/vfs.c +++ b/src/kernel/tests/vfs.c @@ -38,6 +38,12 @@ TEST(path_simplify) { TEST_WRAPPER("/asdf/.", "/asdf/"); TEST_WRAPPER("/asdf//.", "/asdf/"); + TEST_WRAPPER("/foo/bar/..", "/foo/"); + TEST_WRAPPER("/foo/bar/../bar", "/foo/bar"); + TEST_WRAPPER("/foo/bar/../bar/", "/foo/bar/"); + TEST_WRAPPER("/foo/bar/xyz/..", "/foo/bar/"); + TEST_WRAPPER("/foo/bar/xyz/../", "/foo/bar/"); + // going under the root or close to it TEST_WRAPPER("/..", NULL); TEST_WRAPPER("/../asdf", NULL); diff --git a/src/kernel/vfs/path.c b/src/kernel/vfs/path.c index 00af95c..096d3fe 100644 --- a/src/kernel/vfs/path.c +++ b/src/kernel/vfs/path.c @@ -5,7 +5,6 @@ int path_simplify(const char *in, char *out, size_t len) { if (len == 0) return -1; // empty paths are invalid if (in[0] != '/') return -1; // so are relative paths - int depth = 0; // shouldn't be needed! int seg_len; // the length of the current path segment int out_pos = 0; bool directory = 0; @@ -33,32 +32,26 @@ int path_simplify(const char *in, char *out, size_t len) { * (segment starts at i+1) */ if (seg_len == 0 || (seg_len == 1 && in[i + 1] == '.')) { - // the segment is // or /./ + /* // or /./ */ directory = true; } else if (seg_len == 2 && in[i + 1] == '.' && in[i + 2] == '.') { - // the segment is /../ - if (--depth < 0) - return -1; - // backtrack to last slash - while (out[--out_pos] != '/'); + /* /../ */ + directory = true; + + /* try to backtrack to the last slash */ + while (--out_pos >= 0 && out[out_pos] != '/'); + if (out_pos < 0) return -1; } else { - // normal segment + /* a normal segment, e.g. /asdf/ */ out[out_pos] = '/'; memcpy(&out[out_pos + 1], &in[i + 1], seg_len); out_pos += seg_len + 1; - depth++; } } - /* if we were backtracking, out_pos can become 0. i don't like this, - * it feels sloppy. this algorithm should be implemented differently. TODO? */ - if (out_pos == 0) - out[out_pos++] = '/'; - - if (directory) // if the path refers to a directory, append a trailing slash - if (out[out_pos-1] != '/') // unless it's already there - out[out_pos++] = '/'; + /* paths to directories should have a trailing slash */ + if (directory) out[out_pos++] = '/'; return out_pos; } |