Check access to user memory using page fault method (via get_user and put_user).

This commit is contained in:
2024-11-08 01:23:45 +00:00
parent 44f6a85163
commit 9a6abab95e

View File

@@ -47,7 +47,8 @@ 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);
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);
@@ -99,8 +100,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); validate_user_pointer (f->esp, 1, false);
unsigned syscall_number = *(int *) f->esp; unsigned 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)
@@ -110,10 +111,10 @@ 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)); syscall.arity * sizeof (uintptr_t), false);
uintptr_t args[3] = {0}; uintptr_t args[3] = { 0 };
for (int i=0; i < syscall.arity; i++) for (int i = 0; i < syscall.arity; 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
there is a return value it is stored in f->eax. */ there is a return value it is stored in f->eax. */
@@ -144,7 +145,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); validate_user_pointer (cmd_line, 1, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
pid_t pid = process_execute(cmd_line); pid_t pid = process_execute(cmd_line);
@@ -167,7 +168,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); validate_user_pointer (file, 1, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_create (file, initial_size); bool status = filesys_create (file, initial_size);
@@ -182,7 +183,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); validate_user_pointer (file, 1, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_remove (file); bool status = filesys_remove (file);
@@ -198,7 +199,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); validate_user_pointer (file, 1, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
struct file *ptr = filesys_open (file); struct file *ptr = filesys_open (file);
@@ -253,7 +254,7 @@ syscall_read (int fd, void *buffer, unsigned size)
if (fd < 0 || fd == STDOUT_FILENO) if (fd < 0 || fd == STDOUT_FILENO)
return -1; return -1;
validate_user_pointer (buffer, size); validate_user_pointer (buffer, size, true);
if (fd == STDIN_FILENO) if (fd == STDIN_FILENO)
{ {
@@ -290,7 +291,7 @@ syscall_write (int fd, const void *buffer, unsigned size)
if (fd <= 0) if (fd <= 0)
return 0; return 0;
validate_user_pointer (buffer, size); validate_user_pointer (buffer, size, false);
if (fd == STDOUT_FILENO) if (fd == STDOUT_FILENO)
{ {
@@ -404,19 +405,26 @@ 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. Kills the thread (by calling fully contained within user virtual memory. Returns NULL if the memory
thread_exit) if the memory is invalid. Otherwise, returns the PTR given. is invalid. Otherwise, returns the PTR given.
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) validate_user_pointer (const void *ptr, size_t size, bool check_write)
{ {
if (size > 0 && (ptr == NULL || if (size == 0)
!is_user_vaddr (ptr) || return ptr;
!is_user_vaddr (ptr + size - 1) || /* ptr < ptr + size - 1, so sufficient to check that (ptr + size -1) is a
pagedir_get_page (thread_current()->pagedir, ptr) == NULL)) valid user virtual memory address. */
if (!is_user_vaddr (ptr + size - 1))
thread_exit (); thread_exit ();
/* Check read access to pointer. */
return (void *) ptr; int result;
if ((result = get_user (ptr)) == -1)
thread_exit ();
/* Check write access to pointer (if required). */
if (check_write && !put_user (ptr, result))
thread_exit ();
return ptr;
} }
/* PROVIDED BY SPEC. /* PROVIDED BY SPEC.