diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index 9ddd6e9..d60214d 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -46,6 +46,7 @@ static void syscall_close (int fd); static struct open_file *fd_get_file (int fd); static void validate_user_pointer (const void *start, size_t size); +static void validate_user_string (const char *str); /* A struct defining a syscall_function pointer along with its arity. */ typedef struct @@ -140,7 +141,7 @@ syscall_exit (int status) static pid_t syscall_exec (const char *cmd_line) { - validate_user_pointer (cmd_line, 1); + validate_user_string (cmd_line); pid_t pid = process_execute(cmd_line); @@ -159,9 +160,9 @@ syscall_wait (pid_t pid) pointer. Acquires the file system lock to prevent synchronisation issues, and then uses FILESYS_CREATE to create the file, returning the same status */ static bool -syscall_create (const char *file UNUSED, unsigned initial_size UNUSED) +syscall_create (const char *file, unsigned initial_size) { - validate_user_pointer (file, 1); + validate_user_string (file); lock_acquire (&filesys_lock); bool status = filesys_create (file, initial_size); @@ -176,7 +177,7 @@ syscall_create (const char *file UNUSED, unsigned initial_size UNUSED) static bool syscall_remove (const char *file) { - validate_user_pointer (file, 1); + validate_user_string (file); lock_acquire (&filesys_lock); bool status = filesys_remove (file); @@ -192,7 +193,7 @@ syscall_remove (const char *file) static int syscall_open (const char *file) { - validate_user_pointer (file, 1); + validate_user_string (file); lock_acquire (&filesys_lock); struct file *ptr = filesys_open (file); @@ -418,3 +419,37 @@ validate_user_pointer (const void *start, size_t size) if (pagedir_get_page (thread_current ()->pagedir, ptr) == NULL) thread_exit (); } + +/* Validates if a string is fully contained within user virtual memory. Kills + the thread (by calling thread_exit) if the memory is invalid. Otherwise, + returns (nothing) normally. */ +static void +validate_user_string (const char *str) +{ + if (str == NULL || !is_user_vaddr (str)) + thread_exit (); + + size_t length = 0; + size_t offset = (uintptr_t) str % PGSIZE; + + /* We move page by page, checking if the page is mapped to physical memory. */ + for (;;) + { + void *page = pg_round_down (str + length); + + if (!is_user_vaddr(page) || + pagedir_get_page (thread_current ()->pagedir, page) == NULL) + thread_exit (); + + while (offset < PGSIZE) + { + if (*str == '\0') + return; /* We reached the end of the string without issues. */ + + str++; + offset++; + } + + offset = 0; /* Next page will start at the beginning. */ + } +}