Compare commits

..

9 Commits

Author SHA1 Message Date
59e7a64f8e Only check user pages rather than all bytes in-between, for known-size pointers 2024-11-12 15:48:22 +00:00
cf4bf90cbb Implement user pointer checking for C strings 2024-11-12 15:34:45 +00:00
9a6abab95e Check access to user memory using page fault method (via get_user and put_user). 2024-11-12 15:00:16 +00:00
44f6a85163 Add get_user and put_user provided by spec. 2024-11-12 14:50:53 +00:00
83e044cf68 Let kernel handle its own page faults 2024-11-12 14:50:53 +00:00
Demetriades, Themis
7d9900c6d8 Merge branch 'exec-missing-validation' into 'master'
Add validation to check for missing files in exec() args

See merge request lab2425_autumn/pintos_22!36
2024-11-11 23:25:26 +00:00
EDiasAlberto
72afecfbda Add validation to check for missing files in exec() args 2024-11-11 23:10:02 +00:00
Demetriades, Themis
9e692ced9e Merge branch 'userprog-merge' into 'master'
Update variable references between conflicting merges to refer to the same...

See merge request lab2425_autumn/pintos_22!35
2024-11-11 22:59:45 +00:00
Demetriades, Themis
f194fa1fa8 Merge branch 'userprog-merge' into 'master'
Implement complete stack initialization, process_wait, and all system calls correctly except exec

See merge request lab2425_autumn/pintos_22!34
2024-11-11 22:56:28 +00:00
3 changed files with 101 additions and 24 deletions

View File

@@ -145,6 +145,14 @@ page_fault (struct intr_frame *f)
write = (f->error_code & PF_W) != 0; write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0; user = (f->error_code & PF_U) != 0;
/* Kernel page fault is further handled by the kernel itself. */
if (!user)
{
f->eip = (void *)f->eax;
f->eax = 0xffffffff;
return;
}
/* To implement virtual memory, delete the rest of the function /* To implement virtual memory, delete the rest of the function
body, and replace it with code that brings in the page to body, and replace it with code that brings in the page to
which fault_addr refers. */ which fault_addr refers. */

View File

@@ -81,6 +81,10 @@ process_execute (const char *cmd)
of the process. */ of the process. */
char *file_name = strtok_r (cmd_copy, " ", &data->cmd_saveptr); char *file_name = strtok_r (cmd_copy, " ", &data->cmd_saveptr);
/* Validates that the current file to be executed is a valid file */
if (filesys_open (file_name) == NULL)
return TID_ERROR;
/* Create a new thread to execute the command, by initializing /* Create a new thread to execute the command, by initializing
it running the function 'start_process' with the appropriate it running the function 'start_process' with the appropriate
arguments. For details of arguments, see 'start_process'. */ arguments. For details of arguments, see 'start_process'. */

View File

@@ -11,8 +11,11 @@
#include "userprog/process.h" #include "userprog/process.h"
#include "userprog/pagedir.h" #include "userprog/pagedir.h"
#include <stdio.h> #include <stdio.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;
@@ -46,7 +49,11 @@ 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 void validate_user_string (const char *str, bool check_write);
static int get_user (const uint8_t *);
static bool put_user (uint8_t *, uint8_t);
/* A struct defining a syscall_function pointer along with its arity. */ /* A struct defining a syscall_function pointer along with its arity. */
typedef struct typedef struct
@@ -96,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); 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)
@@ -107,10 +114,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[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
there is a return value it is stored in f->eax. */ there is a return value it is stored in f->eax. */
@@ -141,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); 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);
@@ -164,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); 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);
@@ -179,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); validate_user_string (file, false);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_remove (file); bool status = filesys_remove (file);
@@ -195,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); 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);
@@ -250,7 +257,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)
{ {
@@ -287,7 +294,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)
{ {
@@ -401,17 +408,75 @@ 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 valid user virtual memory. thread_exit () if the
thread_exit) if the memory 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) 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;
!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. */
void *last = ptr + size - 1;
if (!is_user_vaddr (last))
thread_exit (); thread_exit ();
ptr = pg_round_down (ptr);
return (void *) ptr; while (ptr <= last)
{
int result;
/* Check read access to pointer. */
if ((result = get_user (ptr)) == -1)
thread_exit ();
/* Check write access to pointer (if required). */
if (check_write && !put_user (ptr, result))
thread_exit ();
ptr += PGSIZE;
}
} }
/* 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.
Reads a byte at user virtual address UADDR.
UADDR must be below PHYS_BASE.
Returns the byte value if successful, -1 if a segfault occurred. */
static int
get_user (const uint8_t *uaddr)
{
int result;
asm ("movl $1f, %0; movzbl %1, %0; 1:" : "=&a"(result) : "m"(*uaddr));
return result;
}
/* PROVIDED BY SPEC.
Writes BYTE to user address UDST.
UDST must be below PHYS_BASE.
Returns true if successful, false if a segfault occurred. */
static bool
put_user (uint8_t *udst, uint8_t byte)
{
int error_code;
asm ("movl $1f, %0; movb %b2, %1; 1:"
: "=&a"(error_code), "=m"(*udst)
: "q"(byte));
return error_code != -1;
}