Implement user pointer checking for C strings

This commit is contained in:
2024-11-12 15:34:45 +00:00
parent 9a6abab95e
commit cf4bf90cbb

View File

@@ -14,6 +14,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <syscall-nr.h> #include <syscall-nr.h>
#define MAX_SYSCALL_ARGS 3
static struct lock filesys_lock; static struct lock filesys_lock;
static unsigned fd_counter = MIN_USER_FD; static unsigned fd_counter = MIN_USER_FD;
@@ -47,8 +49,9 @@ static unsigned syscall_tell (int fd);
static void syscall_close (int fd); static void syscall_close (int fd);
static struct open_file *fd_get_file (int fd); static struct open_file *fd_get_file (int fd);
static void *validate_user_pointer (const void *ptr, size_t size, static void validate_user_pointer (const void *ptr, size_t size,
bool check_write); bool check_write);
static void validate_user_string (const char *str, bool check_write);
static int get_user (const uint8_t *); static int get_user (const uint8_t *);
static bool put_user (uint8_t *, uint8_t); static bool put_user (uint8_t *, uint8_t);
@@ -100,8 +103,8 @@ static void
syscall_handler (struct intr_frame *f) syscall_handler (struct intr_frame *f)
{ {
/* First, read the system call number from the stack. */ /* First, read the system call number from the stack. */
validate_user_pointer (f->esp, 1, false); validate_user_pointer (f->esp, sizeof (uintptr_t), false);
unsigned syscall_number = *(int *)f->esp; uintptr_t syscall_number = *(int *)f->esp;
/* Ensures the number corresponds to a system call that can be handled. */ /* Ensures the number corresponds to a system call that can be handled. */
if (syscall_number >= LOOKUP_SIZE) if (syscall_number >= LOOKUP_SIZE)
@@ -112,8 +115,8 @@ syscall_handler (struct intr_frame *f)
/* Next, read and copy the arguments from the stack pointer. */ /* Next, read and copy the arguments from the stack pointer. */
validate_user_pointer (f->esp + sizeof (uintptr_t), validate_user_pointer (f->esp + sizeof (uintptr_t),
syscall.arity * sizeof (uintptr_t), false); syscall.arity * sizeof (uintptr_t), false);
uintptr_t args[3] = { 0 }; uintptr_t args[MAX_SYSCALL_ARGS] = { 0 };
for (int i = 0; i < syscall.arity; i++) for (int i = 0; i < syscall.arity && i < MAX_SYSCALL_ARGS; i++)
args[i] = *(uintptr_t *)(f->esp + sizeof (uintptr_t) * (i + 1)); args[i] = *(uintptr_t *)(f->esp + sizeof (uintptr_t) * (i + 1));
/* Call the function that handles this system call with the arguments. When /* Call the function that handles this system call with the arguments. When
@@ -145,7 +148,7 @@ syscall_exit (int status)
static pid_t static pid_t
syscall_exec (const char *cmd_line) syscall_exec (const char *cmd_line)
{ {
validate_user_pointer (cmd_line, 1, false); validate_user_string (cmd_line, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
pid_t pid = process_execute(cmd_line); pid_t pid = process_execute(cmd_line);
@@ -168,7 +171,7 @@ syscall_wait (pid_t pid)
static bool static bool
syscall_create (const char *file UNUSED, unsigned initial_size UNUSED) syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
{ {
validate_user_pointer (file, 1, false); validate_user_string (file, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_create (file, initial_size); bool status = filesys_create (file, initial_size);
@@ -183,7 +186,7 @@ syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
static bool static bool
syscall_remove (const char *file) syscall_remove (const char *file)
{ {
validate_user_pointer (file, 1, false); validate_user_string (file, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_remove (file); bool status = filesys_remove (file);
@@ -199,7 +202,7 @@ syscall_remove (const char *file)
static int static int
syscall_open (const char *file) syscall_open (const char *file)
{ {
validate_user_pointer (file, 1, false); validate_user_string (file, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
struct file *ptr = filesys_open (file); struct file *ptr = filesys_open (file);
@@ -405,26 +408,49 @@ fd_get_file (int fd)
} }
/* Validates if a block of memory starting at PTR and of size SIZE bytes is /* Validates if a block of memory starting at PTR and of size SIZE bytes is
fully contained within user virtual memory. Returns NULL if the memory fully contained within valid user virtual memory. thread_exit () if the
is invalid. Otherwise, returns the PTR given. memory is invalid.
If the size is 0, the function does no checks and returns PTR.*/ If the size is 0, the function does no checks and returns PTR. */
static void * static void
validate_user_pointer (const void *ptr, size_t size, bool check_write) validate_user_pointer (const void *ptr, size_t size, bool check_write)
{ {
if (size == 0) if (size == 0)
return ptr; return;
/* ptr < ptr + size - 1, so sufficient to check that (ptr + size -1) is a /* ptr < ptr + size - 1, so sufficient to check that (ptr + size -1) is a
valid user virtual memory address. */ valid user virtual memory address. */
if (!is_user_vaddr (ptr + size - 1)) void *last = ptr + size - 1;
if (!is_user_vaddr (last))
thread_exit (); thread_exit ();
/* Check read access to pointer. */ for (; ptr <= last; ptr++)
int result; {
if ((result = get_user (ptr)) == -1) int result;
thread_exit (); /* Check read access to pointer. */
/* Check write access to pointer (if required). */ if ((result = get_user (ptr)) == -1)
if (check_write && !put_user (ptr, result)) thread_exit ();
thread_exit (); /* Check write access to pointer (if required). */
return ptr; if (check_write && !put_user (ptr, result))
thread_exit ();
}
}
/* Validates of a C-string starting at ptr is fully contained within valid
user virtual memory. thread_exit () if the memory is invalid. */
static void
validate_user_string (const char *ptr, bool check_write)
{
while (true)
{
if (!is_user_vaddr (ptr))
thread_exit ();
int result;
if ((result = get_user ((const uint8_t *)ptr)) == -1)
thread_exit ();
if (check_write && !put_user ((uint8_t *)ptr, result))
thread_exit ();
if (*ptr == '\0')
return;
ptr++;
}
} }
/* PROVIDED BY SPEC. /* PROVIDED BY SPEC.