Subject: mmap interface inside the kernel
To: None <tech-kern@netbsd.org>
From: Darren Reed <avalon@caligula.anu.edu.au>
List: tech-kern
Date: 05/18/2004 22:18:11
Is there some reason why sys_mmap() forces maxprot to include
VM_PROT_EXEC if prot doesn't include it ?

/sys/uvm/uvm_mmap.c, ~ line 440:

                /*
                 * now check protection
                 */     
                            
                maxprot = VM_PROT_EXECUTE;

Why is is not this ?
                maxprot = VM_PROT_EXECUTE & prot;

At least to me, if I do mmap(..., PROT_READ, ...) I don't expect
something to, behind the scenes, also be including execute.

Furthermore, the lack of the flag PROT_WRITE is similarly ignored.
Why ?

Is it so the user can change their mind, later, with mprotect ?

Why shouldn't a device be able to enforce "prot == X" for whatever
value of X it deems necessary for a particular region of memory ?

The patch below (tabless) extends a current hack to try doing the
mmap without the write bit set, if it isn't set in prot.  However,
this then doesn't cater for regions that want to be READ|EXEC only
or EXEC only or ...

Is it worth doing something here to iterate through all of the
possible combinations, from most bits turned on until just one
bit turned on ?

Darren

# diff -u /sys/uvm/uvm_mmap.c.orig /sys/uvm/uvm_mmap.c
--- /sys/uvm/uvm_mmap.c.orig    2004-01-22 17:51:35.000000000 +0000
+++ /sys/uvm/uvm_mmap.c 2004-05-18 04:48:21.000000000 +0000
@@ -1153,8 +1153,8 @@
                            (maxprot & ~VM_PROT_WRITE), foff, size);
                        /*
                         * XXX Some devices don't like to be mapped with
-                        * XXX PROT_EXEC, but we don't really have a
-                        * XXX better way of handling this, right now
+                        * XXX PROT_EXEC or PROT_WRITE, but we don't really
+                        * XXX have a better way of handling this, right now
                         */
                        if (uobj == NULL && (prot & PROT_EXEC) == 0) {
                                maxprot &= ~VM_PROT_EXECUTE;
@@ -1162,6 +1162,12 @@
                                    (flags & MAP_SHARED) ? maxprot :
                                    (maxprot & ~VM_PROT_WRITE), foff, size);
                        }
+                       if (uobj == NULL && (prot & PROT_WRITE) == 0) {
+                               maxprot &= ~VM_PROT_WRITE;
+                               uobj = udv_attach((void *)&vp->v_rdev,
+                                   (flags & MAP_SHARED) ? maxprot :
+                                   (maxprot & ~VM_PROT_WRITE), foff, size);
+                       }
                        advice = UVM_ADV_RANDOM;
                }
                if (uobj == NULL)