From d2b2dff7490f2c4b8e91f79940fc46f0361c216c Mon Sep 17 00:00:00 2001
From: Robert Morris <rtm@csail.mit.edu>
Date: Tue, 4 Oct 2022 11:52:57 -0400
Subject: [PATCH] fix copyout() to refuse to write a read-only page

---
 kernel/trampoline.S |  2 +-
 kernel/vm.c         |  9 +++++++--
 user/usertests.c    | 18 ++++++++++--------
 3 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/kernel/trampoline.S b/kernel/trampoline.S
index d7308cc..693f8a1 100644
--- a/kernel/trampoline.S
+++ b/kernel/trampoline.S
@@ -15,6 +15,7 @@
 
 .section trampsec
 .globl trampoline
+.globl usertrap
 trampoline:
 .align 4
 .globl uservec
@@ -80,7 +81,6 @@ uservec:
         # load the address of usertrap(), from p->trapframe->kernel_trap
         ld t0, 16(a0)
 
-
         # fetch the kernel page table address, from p->trapframe->kernel_satp.
         ld t1, 0(a0)
 
diff --git a/kernel/vm.c b/kernel/vm.c
index 9f69783..486945e 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -352,12 +352,17 @@ int
 copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
 {
   uint64 n, va0, pa0;
+  pte_t *pte;
 
   while(len > 0){
     va0 = PGROUNDDOWN(dstva);
-    pa0 = walkaddr(pagetable, va0);
-    if(pa0 == 0)
+    if(va0 >= MAXVA)
       return -1;
+    pte = walk(pagetable, va0, 0);
+    if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||
+       (*pte & PTE_W) == 0)
+      return -1;
+    pa0 = PTE2PA(*pte);
     n = PGSIZE - (dstva - va0);
     if(n > len)
       n = len;
diff --git a/user/usertests.c b/user/usertests.c
index 7d3e9bc..7f35c38 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -76,7 +76,7 @@ copyin(char *s)
 void
 copyout(char *s)
 {
-  uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff };
+  uint64 addrs[] = { 0LL, 0x80000000LL, 0xffffffffffffffff };
 
   for(int ai = 0; ai < 2; ai++){
     uint64 addr = addrs[ai];
@@ -2821,7 +2821,7 @@ diskfull(char *s)
 
   unlink("diskfulldir");
   
-  for(fi = 0; done == 0; fi++){
+  for(fi = 0; done == 0 && '0' + fi < 0177; fi++){
     char name[32];
     name[0] = 'b';
     name[1] = 'i';
@@ -2882,7 +2882,7 @@ diskfull(char *s)
     unlink(name);
   }
 
-  for(int i = 0; i < fi; i++){
+  for(int i = 0; '0' + i < 0177; i++){
     char name[32];
     name[0] = 'b';
     name[1] = 'i';
@@ -2965,12 +2965,14 @@ run(void f(char *), char *s) {
 }
 
 int
-runtests(struct test *tests, char *justone) {
+runtests(struct test *tests, char *justone, int continuous) {
   for (struct test *t = tests; t->s != 0; t++) {
     if((justone == 0) || strcmp(t->s, justone) == 0) {
       if(!run(t->f, t->s)){
-        printf("SOME TESTS FAILED\n");
-        return 1;
+        if(continuous != 2){
+          printf("SOME TESTS FAILED\n");
+          return 1;
+        }
       }
     }
   }
@@ -3050,7 +3052,7 @@ drivetests(int quick, int continuous, char *justone) {
     printf("usertests starting\n");
     int free0 = countfree();
     int free1 = 0;
-    if (runtests(quicktests, justone)) {
+    if (runtests(quicktests, justone, continuous)) {
       if(continuous != 2) {
         return 1;
       }
@@ -3058,7 +3060,7 @@ drivetests(int quick, int continuous, char *justone) {
     if(!quick) {
       if (justone == 0)
         printf("usertests slow tests starting\n");
-      if (runtests(slowtests, justone)) {
+      if (runtests(slowtests, justone, continuous)) {
         if(continuous != 2) {
           return 1;
         }