mm: Enforce MAP_PRIVATE xor MAP_SHARED (XCC)

We're only supposed to accept PRIVATE xor SHARED, but we were allowing
neither, and possibly both.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/src/arsc.c b/kern/src/arsc.c
index d2f0b1c..c25db79 100644
--- a/kern/src/arsc.c
+++ b/kern/src/arsc.c
@@ -35,7 +35,7 @@
 	void * va;
 	// TODO: need to pin this page in the future when swapping happens
 	va = do_mmap(p,MMAP_LOWEST_VA, SYSCALLRINGSIZE, PROT_READ | PROT_WRITE,
-	             MAP_ANONYMOUS | MAP_POPULATE, NULL, 0);
+	             MAP_ANONYMOUS | MAP_POPULATE | MAP_PRIVATE, NULL, 0);
 	pte_t pte = pgdir_walk(p->env_pgdir, (void*)va, 0);
 	assert(pte_walk_okay(pte));
 	sring = (syscall_sring_t*) KADDR(pte_get_paddr(pte));
diff --git a/kern/src/elf.c b/kern/src/elf.c
index 18e3fbe..233b202 100644
--- a/kern/src/elf.c
+++ b/kern/src/elf.c
@@ -42,7 +42,7 @@
                                                 int auxc, elf_aux_t auxv[])
 {
 	/* Map in pages for p's stack. */
-	int flags = MAP_FIXED | MAP_ANONYMOUS;
+	int flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE;
 	uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
 	if (do_mmap(p, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
 	            flags, NULL, 0) == MAP_FAILED)
@@ -144,7 +144,7 @@
 	ei->highest_addr = 0;
 	off64_t f_off = 0;
 	void* phdrs = 0;
-	int mm_perms, mm_flags = MAP_FIXED;
+	int mm_perms, mm_flags;
 
 	/* When reading on behalf of the kernel, we need to switch to a ktask so
 	 * the VFS (and maybe other places) know. (TODO: KFOP) */
@@ -216,7 +216,8 @@
 		p_flags |= (writable ? ELF_PROT_WRITE : 0);
 		/* All mmaps need to be fixed to their VAs.  If the program wants it to
 		 * be a writable region, we also need the region to be private. */
-		mm_flags = MAP_FIXED | (p_flags & ELF_PROT_WRITE ? MAP_PRIVATE : 0);
+		mm_flags = MAP_FIXED |
+		           (p_flags & ELF_PROT_WRITE ? MAP_PRIVATE : MAP_SHARED);
 
 		if (p_type == ELF_PROG_PHDR)
 			ei->phdr = p_va;
@@ -288,6 +289,7 @@
 					/* Need our own populated, private copy of the page so that
 					 * we can zero the remainder - and not zero chunks of the
 					 * real file in the page cache. */
+					mm_flags &= ~MAP_SHARED;
 					mm_flags |= MAP_PRIVATE | MAP_POPULATE;
 
 					/* Map the final partial page. */
diff --git a/kern/src/mm.c b/kern/src/mm.c
index 351a8cc..91b3d76 100644
--- a/kern/src/mm.c
+++ b/kern/src/mm.c
@@ -328,6 +328,7 @@
 	int ret = 0;
 
 	if ((!vmr->vm_file) || (vmr->vm_flags & MAP_PRIVATE)) {
+		/* We don't support ANON + SHARED yet */
 		assert(!(vmr->vm_flags & MAP_SHARED));
 		ret = copy_pages(p, new_p, vmr->vm_base, vmr->vm_end);
 	} else {
@@ -422,6 +423,12 @@
 	spin_unlock(&p->vmr_lock);
 }
 
+static bool mmap_flags_priv_ok(int flags)
+{
+	return (flags & (MAP_PRIVATE | MAP_SHARED)) == MAP_PRIVATE ||
+	       (flags & (MAP_PRIVATE | MAP_SHARED)) == MAP_SHARED;
+}
+
 /* Error values aren't quite comprehensive - check man mmap() once we do better
  * with the FS.
  *
@@ -436,9 +443,14 @@
            int fd, size_t offset)
 {
 	struct file *file = NULL;
+
 	offset <<= PGSHIFT;
 	printd("mmap(addr %x, len %x, prot %x, flags %x, fd %x, off %x)\n", addr,
 	       len, prot, flags, fd, offset);
+	if (!mmap_flags_priv_ok(flags)) {
+		set_errno(EINVAL);
+		return MAP_FAILED;
+	}
 	if (fd >= 0 && (flags & MAP_ANON)) {
 		set_errno(EBADF);
 		return MAP_FAILED;
@@ -463,7 +475,7 @@
 	 * We could just have userspace handle this (in glibc's mmap), so we don't
 	 * need to know about BRK_END, but this will work for now (and may avoid
 	 * bugs).  Note that this limits mmap(0) a bit.  Keep this in sync with
-	 * __do_mmap()'s check.  (Both are necessary).  */
+	 * do_mmap()'s check.  (Both are necessary).  */
 	if (addr == 0)
 		addr = BRK_END;
 	/* Still need to enforce this: */
@@ -663,6 +675,7 @@
 	len = ROUNDUP(len, PGSIZE);
 	struct vm_region *vmr, *vmr_temp;
 
+	assert(mmap_flags_priv_ok(flags));
 	/* read/write vmr lock (will change the tree) */
 	spin_lock(&p->vmr_lock);
 	p->vmr_history++;
diff --git a/kern/src/ucq.c b/kern/src/ucq.c
index cabf077..fc456f4 100644
--- a/kern/src/ucq.c
+++ b/kern/src/ucq.c
@@ -69,7 +69,8 @@
 		 * the proc_lock, and potentially deadlock the system. */
 		new_page = (struct ucq_page*)do_mmap(p, 0, PGSIZE,
 		                                     PROT_READ | PROT_WRITE,
-		                                     MAP_ANON | MAP_POPULATE, 0, 0);
+		                                     MAP_ANONYMOUS | MAP_POPULATE |
+		                                     MAP_PRIVATE, NULL, 0);
 		assert(new_page);
 		assert(!PGOFF(new_page));
 	} else {
diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c
index 53f7242..584c95d 100644
--- a/tests/vmm/vmrunkernel.c
+++ b/tests/vmm/vmrunkernel.c
@@ -248,7 +248,7 @@
 	void *pages, *pir;
 
 	a_page = mmap((void *)APIC_GPA, PGSIZE, PROT_READ | PROT_WRITE,
-	              MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	              MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	fprintf(stderr, "a_page mmap pointer %p\n", a_page);
 
 	if (a_page != (void *)APIC_GPA) {
@@ -261,7 +261,7 @@
 
 	/* Allocate VAPIC and PIR pages. */
 	pages = mmap((void*)0, vm->nr_gpcs * 2 * PGSIZE, PROT_READ | PROT_WRITE,
-	             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	if (pages == MAP_FAILED) {
 		perror("Unable to map VAPIC and PIR pages.");
 		exit(1);
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/i386/tls.h b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/i386/tls.h
index 5d7000a..899f3eb 100644
--- a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/i386/tls.h
+++ b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/i386/tls.h
@@ -473,8 +473,8 @@
 	 * setting it up...) */
 	void *ldt = (void*)__ros_syscall_noerrno(SYS_mmap, 0, sz,
 	                                         PROT_READ | PROT_WRITE,
-	                                         MAP_ANONYMOUS | MAP_POPULATE,
-	                                         -1, 0);
+	                                         MAP_ANONYMOUS | MAP_POPULATE |
+	                                         MAP_PRIVATE, -1, 0);
     if (ldt == MAP_FAILED)
       return "tls couldn't allocate memory\n";
 
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c
index 4c6fbb6..dbc17d5 100644
--- a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c
+++ b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c
@@ -78,7 +78,7 @@
     if ((void*)__ros_syscall_noerrno(SYS_mmap, (long)real_brk,
 	                                 real_new_brk-real_brk,
 	                                 PROT_READ | PROT_WRITE | PROT_EXEC,
-	                                 MAP_FIXED | MAP_ANONYMOUS,
+	                                 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
 	                                 -1, 0) != (void*)real_brk)
       return -1;
   }
diff --git a/user/parlib/slab.c b/user/parlib/slab.c
index 936981f..7d31652 100644
--- a/user/parlib/slab.c
+++ b/user/parlib/slab.c
@@ -262,7 +262,7 @@
 	if (cp->obj_size <= SLAB_LARGE_CUTOFF) {
 		// Just get a single page for small slabs
 		a_page = mmap(0, PGSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
-		              MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+		              MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 		assert(a_page != MAP_FAILED);
 		// the slab struct is stored at the end of the page
 		a_slab = (struct kmem_slab*)(a_page + PGSIZE -
@@ -302,7 +302,7 @@
 		size_t nr_pgs = ROUNDUP(NUM_BUF_PER_SLAB * a_slab->obj_size, PGSIZE) /
 		                         PGSIZE;
 		void *buf = mmap(0, nr_pgs * PGSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
-		                 MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+		                 MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 		assert(buf != MAP_FAILED);
 		a_slab->num_busy_obj = 0;
 		a_slab->num_total_obj = nr_pgs * PGSIZE / a_slab->obj_size;
diff --git a/user/parlib/ucq.c b/user/parlib/ucq.c
index dd4328d..42628fb 100644
--- a/user/parlib/ucq.c
+++ b/user/parlib/ucq.c
@@ -45,7 +45,9 @@
 {
 	uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2,
 	                                      PROT_WRITE | PROT_READ,
-	                                      MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                                      MAP_POPULATE | MAP_ANONYMOUS |
+	                                      MAP_PRIVATE, -1, 0);
+
 	assert(two_pages);
 	ucq_init_raw(ucq, two_pages, two_pages + PGSIZE);
 }
diff --git a/user/parlib/vcore.c b/user/parlib/vcore.c
index d2d9ef4..ac0b480 100644
--- a/user/parlib/vcore.c
+++ b/user/parlib/vcore.c
@@ -103,8 +103,8 @@
 		return 0; // reuse old stack
 
 	void* stackbot = mmap(0, TRANSITION_STACK_SIZE,
-	                      PROT_READ|PROT_WRITE|PROT_EXEC,
-	                      MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
+	                      PROT_READ | PROT_WRITE | PROT_EXEC,
+	                      MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 
 	if(stackbot == MAP_FAILED)
 		return -1; // errno set by mmap
@@ -152,7 +152,8 @@
 
 	mmap_block = (uintptr_t)mmap(0, PGSIZE * 4,
 	                             PROT_WRITE | PROT_READ,
-	                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE,
+	                             -1, 0);
 	assert((void*)mmap_block != MAP_FAILED);
 	__prep_vcore(0, mmap_block);
 }
@@ -163,7 +164,8 @@
 
 	mmap_block = (uintptr_t)mmap(0, PGSIZE * 4 * (max_vcores() - 1),
 	                             PROT_WRITE | PROT_READ,
-	                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE,
+	                             -1, 0);
 	assert((void*)mmap_block != MAP_FAILED);
 	for (int i = 1; i < max_vcores(); i++)
 		__prep_vcore(i, mmap_block + 4 * (i - 1) * PGSIZE);
diff --git a/user/pthread/pthread.c b/user/pthread/pthread.c
index 7d9fdd8..79108d5 100644
--- a/user/pthread/pthread.c
+++ b/user/pthread/pthread.c
@@ -444,8 +444,8 @@
 	int force_a_page_fault;
 	assert(pt->stacksize);
 	void* stackbot = mmap(0, pt->stacksize,
-	                      PROT_READ|PROT_WRITE|PROT_EXEC,
-	                      MAP_ANONYMOUS, -1, 0);
+	                      PROT_READ | PROT_WRITE | PROT_EXEC,
+	                      MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	if (stackbot == MAP_FAILED)
 		return -1; // errno set by mmap
 	pt->stacktop = stackbot + pt->stacksize;
@@ -547,7 +547,8 @@
 	/* Get a block of pages for our per-vcore (but non-VCPD) ev_qs */
 	mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
 	                             PROT_WRITE | PROT_READ,
-	                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE,
+	                             -1, 0);
 	assert(mmap_block);
 	/* Could be smarter and do this on demand (in case we don't actually want
 	 * max_vcores()). */
@@ -568,7 +569,8 @@
 #if 0   /* One global ev_mbox, separate ev_q per vcore */
 	struct event_mbox *sysc_mbox = malloc(sizeof(struct event_mbox));
 	uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2, PROT_WRITE | PROT_READ,
-	                                      MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                                      MAP_POPULATE | MAP_ANONYMOUS |
+	                                      MAP_PRIVATE, -1, 0);
 	printd("Global ucq: %08p\n", &sysc_mbox->ev_msgs);
 	assert(sysc_mbox);
 	assert(two_pages);
diff --git a/user/vmm/biostables.c b/user/vmm/biostables.c
index 6855b65..1ed67da 100644
--- a/user/vmm/biostables.c
+++ b/user/vmm/biostables.c
@@ -202,7 +202,7 @@
 	// And, sorry, due to the STUPID format of the RSDP for now we need the low
 	// 1M.
 	low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
-	             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	if (low1m != (void *)4096) {
 		perror("Unable to mmap low 1m");
 		exit(1);
diff --git a/user/vmm/memory.c b/user/vmm/memory.c
index ebfae19..7469c98 100644
--- a/user/vmm/memory.c
+++ b/user/vmm/memory.c
@@ -127,7 +127,7 @@
 		r1size = memstart < RESERVED ? RESERVED - memstart : 0;
 		r2 = mmap((void *)r2start, memsize - r1size,
 		          PROT_READ | PROT_WRITE | PROT_EXEC,
-		          MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+		          MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 		if (r2 != (void *)r2start) {
 			fprintf(stderr,
 			        "High region: Could not mmap 0x%lx bytes at 0x%lx\n",
@@ -140,7 +140,7 @@
 
 	r1 = mmap((void *)memstart, r1size,
 	              PROT_READ | PROT_WRITE | PROT_EXEC,
-	              MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	              MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	if (r1 != (void *)memstart) {
 		fprintf(stderr, "Low region: Could not mmap 0x%lx bytes at 0x%lx\n",
 		        memsize, memstart);
diff --git a/user/vmm/pagetables.c b/user/vmm/pagetables.c
index 2d20ca6..f7da0c5 100644
--- a/user/vmm/pagetables.c
+++ b/user/vmm/pagetables.c
@@ -50,7 +50,7 @@
 	 * used to use posix_memalign but that puts them
 	 * outside EPT-accessible space on some CPUs. */
 	p512 = mmap((void *)memstart + memsize, nptp * 4096, PROT_READ | PROT_WRITE,
-	             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 	if (p512 == MAP_FAILED) {
 		perror("page table page alloc");
 		exit(1);
diff --git a/user/vmm/sched.c b/user/vmm/sched.c
index f93b20f..b44c44f 100644
--- a/user/vmm/sched.c
+++ b/user/vmm/sched.c
@@ -107,7 +107,8 @@
 
 	mmap_block = (uintptr_t)mmap(0, PGSIZE * 2,
 	                             PROT_WRITE | PROT_READ,
-	                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+	                             MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE,
+	                             -1, 0);
 	evq = get_eventq_raw();
 	assert(mmap_block && evq);
 	evq->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR | EVENT_WAKEUP;
@@ -637,7 +638,7 @@
 	int force_a_page_fault;
 	void *stacktop;
 	void *stackbot = mmap(0, stacksize, PROT_READ | PROT_WRITE | PROT_EXEC,
-	                      MAP_ANONYMOUS, -1, 0);
+	                      MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 
 	if (stackbot == MAP_FAILED)
 		return 0;
diff --git a/user/vmm/vthread.c b/user/vmm/vthread.c
index 5ef8d4c..105e32d 100644
--- a/user/vmm/vthread.c
+++ b/user/vmm/vthread.c
@@ -16,7 +16,7 @@
 static void *page(void *addr, int count)
 {
 	void *v;
-	unsigned long flags = MAP_POPULATE | MAP_ANONYMOUS;
+	unsigned long flags = MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE;
 
 	if (addr)
 		flags |= MAP_FIXED;