diff --git a/Makefile b/Makefile index 09d790cf63..ddc109de2b 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ endif # If the makefile can't find QEMU, specify its path here # QEMU = qemu-system-i386 - +QEMU = /usr/libexec/qemu-kvm # Try to infer the correct QEMU ifndef QEMU QEMU = $(shell if which qemu > /dev/null; \ @@ -146,14 +146,14 @@ vectors.S: vectors.pl ULIB = ulib.o usys.o printf.o umalloc.o _%: %.o $(ULIB) - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ + $(LD) $(LDFLAGS) -N -e main -Ttext 0x1000 -o $@ $^ $(OBJDUMP) -S $@ > $*.asm $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym _forktest: forktest.o $(ULIB) # forktest has less library code linked in - needs to be small # in order to be able to max out the proc table. - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o _forktest forktest.o ulib.o usys.o + $(LD) $(LDFLAGS) -N -e main -Ttext 0x1000 -o _forktest forktest.o ulib.o usys.o $(OBJDUMP) -S _forktest > forktest.asm mkfs: mkfs.c fs.h @@ -181,6 +181,8 @@ UPROGS=\ _usertests\ _wc\ _zombie\ + _testkaccess\ + _testnull\ fs.img: mkfs README $(UPROGS) ./mkfs fs.img README $(UPROGS) @@ -283,4 +285,4 @@ tar: cp dist/* dist/.gdbinit.tmpl /tmp/xv6 (cd /tmp; tar cf - xv6) | gzip >xv6-rev10.tar.gz # the next one will be 10 (9/17) -.PHONY: dist-test dist +.PHONY: dist-test dist \ No newline at end of file diff --git a/defs.h b/defs.h index 82fb982837..0f6e100f26 100644 --- a/defs.h +++ b/defs.h @@ -156,6 +156,10 @@ int fetchint(uint, int*); int fetchstr(uint, char**); void syscall(void); +// sysproc.c +int sys_mprotect(void); +int sys_munprotect(void); + // timer.c void timerinit(void); @@ -181,10 +185,13 @@ void freevm(pde_t*); void inituvm(pde_t*, char*, uint); int loaduvm(pde_t*, char*, struct inode*, uint, uint); pde_t* copyuvm(pde_t*, uint); +pde_t* walkpgdir(pde_t *pgdir, const void *va, int alloc); void switchuvm(struct proc*); void switchkvm(void); int copyout(pde_t*, uint, void*, uint); void clearpteu(pde_t *pgdir, char *uva); +int mprotectpages(void*, int); +int munprotectpages(void*, int); // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/exec.c b/exec.c index b40134f352..bd53656c86 100644 --- a/exec.c +++ b/exec.c @@ -39,7 +39,7 @@ exec(char *path, char **argv) goto bad; // Load program into memory. - sz = 0; + sz = PGSIZE; for(i=0, off=elf.phoff; i= curproc->sz || addr+4 > curproc->sz) + if(addr >= curproc->sz) + return -1; + if(addr + 4 > curproc->sz) return -1; + if(addr + 4 < addr) + return -1; + *ip = *(int*)(addr); return 0; } @@ -36,8 +41,10 @@ fetchstr(uint addr, char **pp) if(addr >= curproc->sz) return -1; + *pp = (char*)addr; ep = (char*)curproc->sz; + for(s = *pp; s < ep; s++){ if(*s == 0) return s - *pp; @@ -63,8 +70,19 @@ argptr(int n, char **pp, int size) if(argint(n, &i) < 0) return -1; - if(size < 0 || (uint)i >= curproc->sz || (uint)i+size > curproc->sz) + + if(size < 0) return -1; + + if((uint)i >= curproc->sz) + return -1; + + if((uint)i + size > curproc->sz) + return -1; + + if((uint)i + size < (uint)i) + return -1; + *pp = (char*)i; return 0; } @@ -103,6 +121,8 @@ extern int sys_unlink(void); extern int sys_wait(void); extern int sys_write(void); extern int sys_uptime(void); +extern int sys_mprotect(void); +extern int sys_munprotect(void); static int (*syscalls[])(void) = { [SYS_fork] sys_fork, @@ -126,6 +146,8 @@ static int (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_mprotect] sys_mprotect, +[SYS_munprotect] sys_munprotect, }; void @@ -142,4 +164,4 @@ syscall(void) curproc->pid, curproc->name, num); curproc->tf->eax = -1; } -} +} \ No newline at end of file diff --git a/syscall.h b/syscall.h index bc5f35651c..8bd91849f9 100644 --- a/syscall.h +++ b/syscall.h @@ -20,3 +20,5 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_mprotect 22 +#define SYS_munprotect 23 \ No newline at end of file diff --git a/sysproc.c b/sysproc.c index 0686d295b6..a01d9c9d39 100644 --- a/sysproc.c +++ b/sysproc.c @@ -89,3 +89,59 @@ sys_uptime(void) release(&tickslock); return xticks; } + +int +sys_mprotect(void) +{ + char *addr; + int len; + + if(argptr(0, &addr, sizeof(addr)) < 0) + return -1; + if(argint(1, &len) < 0) + return -1; + + if((uint)addr % PGSIZE != 0 || len <= 0) + return -1; + + struct proc *p = myproc(); + + for(int i = 0; i < len; i += PGSIZE) { + pte_t *pte = walkpgdir(p->pgdir, addr + i, 0); + if(!pte || !(*pte & PTE_P)) + return -1; + + *pte &= ~PTE_W; + } + + return 0; +} + +int +sys_munprotect(void) +{ + char *addr; + int len; + + if(argptr(0, &addr, sizeof(addr)) < 0) + return -1; + if(argint(1, &len) < 0) + return -1; + + if((uint)addr % PGSIZE != 0 || len <= 0) + return -1; + + struct proc *p = myproc(); + + for(int i = 0; i < len; i += PGSIZE) { + pte_t *pte = walkpgdir(p->pgdir, addr + i, 0); + if(!pte || !(*pte & PTE_P)) + return -1; + + *pte |= PTE_W; + } + + lcr3(V2P(p->pgdir)); + + return 0; +} \ No newline at end of file diff --git a/testkaccess.c b/testkaccess.c new file mode 100644 index 0000000000..5945e7b4d9 --- /dev/null +++ b/testkaccess.c @@ -0,0 +1,11 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +int main(void){ + printf(1, "testkaccess: illegal read attempt\n"); + volatile int *p = (int*)0xFFFF0000; + volatile int x = *p; + printf(1, "UNEXPECTED: read=%d\n", x); + exit(); +} diff --git a/testnull.c b/testnull.c new file mode 100644 index 0000000000..4e7e86d551 --- /dev/null +++ b/testnull.c @@ -0,0 +1,11 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +int main(void){ + printf(1, "testnull: about to dereference NULL\n"); + volatile int *p = (int*)0x0; + volatile int x = *p; + printf(1, "UNEXPECTED: read=%d\n", x); + exit(); +} diff --git a/trap.c b/trap.c index 41c66ebf9a..ac31d578ff 100644 --- a/trap.c +++ b/trap.c @@ -79,7 +79,7 @@ trap(struct trapframe *tf) break; //PAGEBREAK: 13 - default: + /*default: if(myproc() == 0 || (tf->cs&3) == 0){ // In kernel, it must be our mistake. cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n", @@ -92,6 +92,29 @@ trap(struct trapframe *tf) myproc()->pid, myproc()->name, tf->trapno, tf->err, cpuid(), tf->eip, rcr2()); myproc()->killed = 1; + }*/ + + default: + if(myproc() == 0 || (tf->cs&3) == 0){ + // Kernel mode → panic + cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n", + tf->trapno, cpuid(), tf->eip, rcr2()); + panic("trap"); + } + + // Special handling for page fault + if(tf->trapno == T_PGFLT){ + cprintf("pid %d %s: page fault at addr 0x%x, eip 0x%x\n", + myproc()->pid, myproc()->name, rcr2(), tf->eip); + } else { + cprintf("pid %d %s: trap %d err %d on cpu %d " + "eip 0x%x addr 0x%x--kill proc\n", + myproc()->pid, myproc()->name, tf->trapno, + tf->err, cpuid(), tf->eip, rcr2()); + } + + myproc()->killed = 1; + break; } // Force process exit if it has been killed and is in user space. @@ -109,4 +132,4 @@ trap(struct trapframe *tf) // Check if the process has been killed since we yielded if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER) exit(); -} +} \ No newline at end of file diff --git a/user.h b/user.h index 4f99c52ba6..2ec9b1286c 100644 --- a/user.h +++ b/user.h @@ -23,6 +23,8 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int mprotect(void*, int); +int munprotect(void*, int); // ulib.c int stat(const char*, struct stat*); @@ -36,4 +38,4 @@ uint strlen(const char*); void* memset(void*, int, uint); void* malloc(uint); void free(void*); -int atoi(const char*); +int atoi(const char*); \ No newline at end of file diff --git a/usys.S b/usys.S index 8bfd8a1bc4..65807235a4 100644 --- a/usys.S +++ b/usys.S @@ -29,3 +29,5 @@ SYSCALL(getpid) SYSCALL(sbrk) SYSCALL(sleep) SYSCALL(uptime) +SYSCALL(mprotect) +SYSCALL(munprotect) \ No newline at end of file diff --git a/vm.c b/vm.c index 7134cfffbe..b56c6ae8e5 100644 --- a/vm.c +++ b/vm.c @@ -32,7 +32,7 @@ seginit(void) // Return the address of the PTE in page table pgdir // that corresponds to virtual address va. If alloc!=0, // create any required page table pages. -static pte_t * +pte_t * walkpgdir(pde_t *pgdir, const void *va, int alloc) { pde_t *pde; @@ -323,10 +323,9 @@ copyuvm(pde_t *pgdir, uint sz) if((d = setupkvm()) == 0) return 0; for(i = 0; i < sz; i += PGSIZE){ - if((pte = walkpgdir(pgdir, (void *) i, 0)) == 0) - panic("copyuvm: pte should exist"); - if(!(*pte & PTE_P)) - panic("copyuvm: page not present"); + pte = walkpgdir(pgdir, (void*)i, 0); + if(pte == 0 || !(*pte & PTE_P)) + continue; pa = PTE_ADDR(*pte); flags = PTE_FLAGS(*pte); if((mem = kalloc()) == 0)