static bool validate (void *uptr, void *esp) { #ifdef VM //Check if uptr already has a valid entry in the supplemental page table. struct supp_page *spe = supp_page_lookup (thread_current ()->spt, uptr); if (spe != NULL) { if (spe->fte->paddr == NULL) supp_page_alloc (spe); return true; } /* Otherwise, address is valid only if it is stack growth / first access. To do so, address must be above the bottom of the stack, a valid address (in particular, below PHYS_BASE, and either above or exactly 4 /32 bytes below the passed in esp. */ else if (esp >= STACK_BOUND && ((uptr >= esp && is_user_vaddr (uptr)) || (char *)uptr == (char *)esp - 4 || (char *)uptr == (char *)esp - 32)) { spe = supp_page_insert (thread_current ()->spt, uptr, FRAME_ZERO, NULL, false); supp_page_alloc (spe); return true; } else return is_user_vaddr (uptr); #else return is_user_vaddr (uptr); #endif }
/* Write to a file. */ static int sys_write (int fd, const void *buffer, unsigned size) { struct user_file *f; int ret = -1; #if PRINT_DEBUG printf ("[SYSCALL] SYS_WRITE: fd: %d, buffer: %p, size: %u\n", fd, buffer, size); #endif if (fd == STDIN_FILENO) ret = -1; else if (fd == STDOUT_FILENO) { putbuf (buffer, size); ret = size; } else if (!is_user_vaddr (buffer) || !is_user_vaddr (buffer + size)) sys_exit (-1); else { f = file_by_fid (fd); if (f == NULL) ret = -1; else { lock_acquire (&file_lock); ret = file_write (f->file, buffer, size); lock_release (&file_lock); } } return ret; }
/* Open a file. */ static int sys_open (const char *file) { struct file *sys_f; struct user_file *f; #if PRINT_DEBUG printf ("[SYSCALL] SYS_OPEN: file: %s\n", file); #endif if (file == NULL || !is_user_vaddr (file)) sys_exit (-1); lock_acquire (&file_lock); sys_f = filesys_open (file); lock_release (&file_lock); if (sys_f == NULL) return -1; f = (struct user_file *) malloc (sizeof (struct user_file)); if (f == NULL) { lock_acquire (&file_lock); file_close (sys_f); lock_release (&file_lock); return -1; } f->file = sys_f; f->fid = allocate_fid (); list_push_back (&thread_current ()->files, &f->thread_elem); return f->fid; }
/* Validates a user-provided pointer. Checks that it's in the required * range, and that it correpsonds to a page directory entry */ bool valid_user_pointer(const void *ptr) { uint32_t *pd, *pde; struct list_elem *e; struct vm_area_struct *iter; struct thread *t = thread_current(); void *esp = t->esp; /* Check if page in supplemental page table */ if (spt_present(t, pg_round_down(ptr))) { return true; } /* Special case for esp, must be in pagedir */ pd = active_pd(); pde = pd + pd_no(esp); /* If we have messed up esp */ if (*pde == 0) { return false; } /* If the pointer is above esp (but in user_vaddr), it may correspond to * a part of the stack that would be later loaded lazily on a pagefault. * So this should be considered a good pointer. */ if (is_user_vaddr(ptr) && ptr >= esp) { return true; } /* If we're here, this isn't a valid address */ return false; }
void validate_byte(void *ptr) { if(!is_user_vaddr(ptr) || pagedir_get_page(thread_current()->pagedir, ptr) == NULL)//FIXME make sure the end of the pointer isn't over a page boundery process_terminate(); }
static int read_handler (int fd, void *buffer, unsigned size) { // Verifies that the buffer is a user virtual address as well as verifies it is mapped to kernel virtual memory if (!is_user_vaddr(buffer + size) || pagedir_get_page(thread_current()->pagedir, buffer) == NULL) { exit_handler(-1); } int num_bytes_read = 0; if (fd == STDIN_FILENO) { // Special case reading from STDIN char * buffy = (char *) buffer; while (num_bytes_read < (int) size) { char chary = input_getc(); buffy[num_bytes_read] = chary; num_bytes_read++; } } else if (fd == STDOUT_FILENO) { // Can not read from STDOUT, so gracefully exit program exit_handler(-1); } else { // Should be dealing with a normal file, if so use given functions struct file_struct * file_reading = get_file(fd); if (file_reading != NULL && file_reading->sys_file != NULL) { num_bytes_read = file_read(file_reading->sys_file, buffer, size); } else { // Was not able to read from file so return -1 num_bytes_read = -1; } } return num_bytes_read; }
/* Returns the address of the page table entry for virtual address VADDR in page directory PD. If PD does not have a page table for VADDR, behavior depends on CREATE. If CREATE is true, then a new page table is created and a pointer into it is returned. Otherwise, a null pointer is returned. */ uint32_t * lookup_page (uint32_t *pd, const void *vaddr, bool create) { uint32_t *pt, *pde; ASSERT (pd != NULL); /* Shouldn't create new kernel virtual mappings. */ ASSERT (!create || is_user_vaddr (vaddr)); /* Check for a page table for VADDR. If one is missing, create one if requested. */ pde = pd + pd_no (vaddr); if (*pde == 0) { if (create) { pt = palloc_get_page (PAL_ZERO); if (pt == NULL) return NULL; *pde = pde_create (pt); } else return NULL; } /* Return the page table entry. */ pt = pde_get_pt (*pde); return &pt[pt_no (vaddr)]; }
/* Validates a single byte. If the byte isn't a valid virtual memory location, the program will be terminated an with exit status of -1. This function shouldn't be called directly but instead one should use the other validate functions (which in turn call this function). */ static void validate_byte(void *ptr) { if(!is_user_vaddr(ptr) || pagedir_get_page(thread_current()->pagedir, ptr) == NULL){ if(lock_held_by_current_thread(&offset_lock)) lock_release(&offset_lock); thread_exit(); } }
void check_valid_pointer(const void *vaddr) { if (!is_user_vaddr(vaddr) || !pagedir_get_page(thread_current()->pagedir, vaddr) ) { //printf("BAD!\n\n"); exit(-1); } }
static int check_ptr(void* ptr) { void *valid; if(ptr == NULL) return 0; if(!is_user_vaddr(ptr)) return 0; valid = pagedir_get_page(thread_current()->pagedir, (const void*)ptr); if(valid==NULL) return 0; return 1; }
//Get unmapped. Fail if unavailable void* kptr (const void* addr) { if (!is_user_vaddr((const void*)addr)) exit(-1); void* kptr = pagedir_get_page(thread_current()->pagedir, addr); if (!kptr) exit(-1); return kptr; }
void test_bad_address (const void* addr) { //Validate user address if (!is_user_vaddr(addr)) exit(-1); //Validate unmapped kptr(addr); }
/* * gets argument address, increases address by 1 byte, checks following vaddrs for * validity, exits if one is not valid */ void syscall_check_arg_buffer_or_exit (const void* vaddr, unsigned size) { char *addr = (char *) vaddr; unsigned i = 0; for(; i<size; i++, addr++) if (!(is_user_vaddr( (const void*)addr) && (((const void*)addr)<PHYS_BASE))) syscall_exit_thread (-1); }
void check_ptr(const void *ptr) { if (ptr == NULL || !is_user_vaddr(ptr) || pagedir_get_page(thread_current()->pagedir, ptr) == NULL) { exit(-1); } }
static void valid_address(void *addr) { if(!is_user_vaddr(addr) || addr<0x8048000) sys_exit(-1); /* else if( pagedir_get_page( thread_current()->pagedir , addr) == NULL ) { sys_exit(-1); }*/ }
void mmap (struct intr_frame *f) { int fd = *value_stack_int(f->esp,4); //void * addr = *(void **)value_stack(f->esp,8); void * addr = *(void **)(f->esp + 8); if (!is_user_vaddr(addr) ) exit_mythread(-1); //fd 0 and 1 are not allowed ... MISSING PAGE ALIGN if(fd == 1 || fd == 0 || addr == 0 || (unsigned int)addr % PGSIZE != 0 ) { f->eax = -1; return ; } struct filed * file = find_file(fd); if ( file == NULL ) { exit_mythread(-1); } struct file * mfile = file_reopen(file->file); //get the file from the threads file table if ( mfile == NULL ) { exit_mythread(-1); } int size = file_length(mfile); //get the number of pages we need for the file int numberpages = size/PGSIZE; if (file_length(mfile) % PGSIZE != 0) numberpages += 1; //check if the virtual memory pages are free int i; for (i = 0; i < numberpages;i++) { if (page_lookup(addr + i*PGSIZE, thread_current()) != NULL) { file_close(mfile); f->eax=-1; return ; } } //add to filetable fd = add_filemmap(mfile,addr); off_t length = 0; //add the pages to the supplemental page table for (i = 0; i < numberpages; i++) { if (size >= PGSIZE) length = PGSIZE; else length = size; page_add_mmap (addr + i*PGSIZE, (off_t *) (i*PGSIZE),true,fd,length,i*PGSIZE); size -= length; } f->eax = fd; }
static int check_file_ptr(const char* file) { void *valid; if(file == NULL) return 0; if(file == "") return 0; if(!is_user_vaddr(file)) return 0; valid = pagedir_get_page(thread_current()->pagedir, (const void*)file); if(valid == NULL) syscall_exit(-1); return 1; }
static void check_str(const char *s) { if (s == NULL) CRASH; do { if (!is_user_vaddr(s)) CRASH; if (pagedir_get_page(thread_current()->pagedir, s) == NULL) CRASH; ++s; } while(*s); }
/**Validates if the ptr is valid in the user address space and whether the address is mapped in the kernel. Invokes sys_exit with -1 status code if both these conditions fail. Else, it returns the kernel virtual address. **/ static const void* address_chk (const void *ptr) { if ( ptr==NULL || !is_user_vaddr (ptr) || pagedir_get_page (thread_current()->pagedir, ptr) == NULL ) { sys_exit (SYS_ERROR); } return pagedir_get_page (thread_current()->pagedir, ptr); }
/* Checks whether PHDR describes a valid, loadable segment in FILE and returns true if so, false otherwise. */ static bool validate_segment (const struct Elf32_Phdr *phdr, struct file *file) { /* p_offset and p_vaddr must have the same page offset. */ if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK)) return false; /* p_offset must point within FILE. */ if (phdr->p_offset > (Elf32_Off) file_length (file)) return false; /* p_memsz must be at least as big as p_filesz. */ if (phdr->p_memsz < phdr->p_filesz) return false; /* The segment must not be empty. */ if (phdr->p_memsz == 0) return false; /* The virtual memory region must both start and end within the user address space range. */ if (!is_user_vaddr ((void *) phdr->p_vaddr)) return false; if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz))) return false; /* The region cannot "wrap around" across the kernel virtual address space. */ if (phdr->p_vaddr + phdr->p_memsz < phdr->p_vaddr) return false; /* Disallow mapping page 0. Not only is it a bad idea to map page 0, but if we allowed it then user code that passed a null pointer to system calls could quite likely panic the kernel by way of null pointer assertions in memcpy(), etc. */ if (phdr->p_vaddr < PGSIZE) return false; /* It's okay. */ return true; }
/* this function reads out a value from esp +offset and checks if it is a valid pointer */ int * value_stack_int (void * esp, int offset) { void * ptr = (void *)(esp + offset); void * result; if (is_user_vaddr((int *)ptr) && (int *)ptr != NULL ) { result = page_lookup((int *)ptr, thread_current()); if (result != NULL) return (int *) ptr; } exit_mythread(-1); return NULL; }
static void check_ptr(const char *p, size_t size) { if (p == NULL) CRASH; while(size > 0) { if (!is_user_vaddr(p)) CRASH; if (pagedir_get_page(thread_current()->pagedir, p) == NULL) CRASH; ++p; --size; } }
/* Looks up the physical address that corresponds to user virtual address UADDR in PD. Returns the kernel virtual address corresponding to that physical address, or a null pointer if UADDR is unmapped. */ void * pagedir_get_page (uint32_t *pd, const void *uaddr) { uint32_t *pte; ASSERT (is_user_vaddr (uaddr)); pte = lookup_page (pd, uaddr, false); if (pte != NULL && (*pte & PTE_P) != 0) return pte_get_page (*pte) + pg_ofs (uaddr); else return NULL; }
bool isStackGrowth(const void *vaddr, const void *esp) { if(!is_user_vaddr(vaddr)) return false; if(PHYS_BASE - 0x00800000 < vaddr && ((esp - 32) == vaddr || (esp - 4) == vaddr)){ return true; } return false; }
/* * get the kernel virtual address using the user virtual address * and the current threads page */ int syscall_user_to_kernel_vaddr (const void* vaddr) { if (!(is_user_vaddr(vaddr) && vaddr<PHYS_BASE)) { syscall_exit_thread (-1); } void *kernel_vaddr = pagedir_get_page ( thread_current ()->pagedir, vaddr); if (kernel_vaddr==NULL) { syscall_exit_thread (-1); } return (int)kernel_vaddr; }
bool byte_access_ok(void* p){ void *ptr = p; /* * There is no ctx switching in this kind of interrupts, * thread_current is current process, not main! */ uint32_t *pd = thread_current ()-> pagedir; if(p==NULL || !is_user_vaddr(ptr) || pagedir_get_page(pd,ptr) == NULL){ /*kill illegal process/thread, shall never return*/ //printf("Address access invalid, kill..."); exit_handler(-1); NOT_REACHED (); } return true; }
/* Start another new process. */ static pid_t sys_exec (const char *file) { #if PRINT_DEBUG printf ("[SYSCALL] SYS_EXEC file: %s\n", file); #endif if (!is_user_vaddr (file)) sys_exit (-1); lock_acquire (&file_lock); int ret = process_execute (file); lock_release (&file_lock); return ret; }
/* Read from a file. */ static int sys_read (int fd, void *buffer, unsigned size) { struct user_file *f; int ret = -1; #if PRINT_DEBUG printf ("[SYSCALL] SYS_READ: fd: %d, buffer: %p, size: %u\n", fd, buffer, size); #endif if (fd == STDIN_FILENO) { unsigned i; for (i = 0; i < size; ++i) *(uint8_t *)(buffer + i) = input_getc (); ret = size; } else if (fd == STDOUT_FILENO) ret = -1; else if (!is_user_vaddr (buffer) || !is_user_vaddr (buffer + size)) sys_exit (-1); else { f = file_by_fid (fd); if (f == NULL) ret = -1; else { lock_acquire (&file_lock); ret = file_read (f->file, buffer, size); lock_release (&file_lock); } } return ret; }
/* * gets arguments from thread stack pointer */ void syscall_get_args (struct intr_frame *f, int *arg, const int n) { int *vaddr; int i = 0; for(;i<n;i++) { vaddr = (int *) f->esp+i+1; const void *address = (const void *) vaddr; if (!(is_user_vaddr(address) && address < PHYS_BASE)) { syscall_exit_thread (-1); } arg[i]=*vaddr; } }
/* Determine whether user process pointer is valid; Otherwise, return false*/ static bool check_uptr (const void* uptr) { if(uptr != NULL) { if(is_user_vaddr(uptr)) { void* kptr = pagedir_get_page(thread_current()->pagedir, uptr); if(kptr != NULL) { return true; } } } return false; }