From 7c3323a25bc1d5844feb7f9ed241fdbdb4819739 Mon Sep 17 00:00:00 2001
From: Sergey Bugaev <bugaevc@gmail.com>
Date: Fri, 21 May 2021 13:21:15 +0300
Subject: tmpfs: Return read-only memory objects when appropriate

---
 tmpfs/node.c  | 37 +++++++++++++++++++++++++++++++------
 tmpfs/tmpfs.h |  2 +-
 2 files changed, 32 insertions(+), 7 deletions(-)

(limited to 'tmpfs')

diff --git a/tmpfs/node.c b/tmpfs/node.c
index 02d213ed..1a73a164 100644
--- a/tmpfs/node.c
+++ b/tmpfs/node.c
@@ -21,6 +21,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <mach/mach4.h>
 #include <hurd/hurd_types.h>
 #include <hurd/store.h>
 #include "default_pager_U.h"
@@ -72,9 +73,11 @@ diskfs_free_node (struct node *np, mode_t mode)
   switch (np->dn->type)
     {
     case DT_REG:
+      /* XXX GNU Mach will terminate the object, and thus existing mappings
+       * will get SIGBUS.  */
+      if (np->dn->u.reg.ro_memobj != MACH_PORT_NULL)
+        mach_port_deallocate (mach_task_self (), np->dn->u.reg.ro_memobj);
       if (np->dn->u.reg.memobj != MACH_PORT_NULL) {
-	/* XXX GNU Mach will terminate the object, and thus existing mappings
-	 * will get SIGBUS.  */
 	vm_deallocate (mach_task_self (), np->dn->u.reg.memref, 4096);
 	mach_port_deallocate (mach_task_self (), np->dn->u.reg.memobj);
       }	
@@ -520,6 +523,7 @@ mach_port_t
 diskfs_get_filemap (struct node *np, vm_prot_t prot)
 {
   error_t err;
+  mach_port_t right;
 
   if (np->dn->type != DT_REG)
     {
@@ -561,14 +565,35 @@ diskfs_get_filemap (struct node *np, vm_prot_t prot)
       assert_perror_backtrace (err);
     }
 
-  /* XXX always writable */
+  if (prot & VM_PROT_WRITE)
+    right = np->dn->u.reg.memobj;
+  else if (np->dn->u.reg.ro_memobj == MACH_PORT_NULL)
+    {
+      vm_offset_t offset = 0;
+      vm_offset_t start = 0;
+      vm_size_t len = ~0;
+      err = memory_object_create_proxy (mach_task_self (),
+                                        VM_PROT_READ | VM_PROT_EXECUTE,
+                                        &np->dn->u.reg.memobj, 1,
+                                        &offset, 1, &start, 1, &len, 1,
+                                        &np->dn->u.reg.ro_memobj);
+      if (err)
+        {
+          errno = err;
+          return MACH_PORT_NULL;
+        }
+
+      right = np->dn->u.reg.ro_memobj;
+    }
+  else
+      right = np->dn->u.reg.ro_memobj;
 
   /* Add a reference for each call, the caller will deallocate it.  */
-  err = mach_port_mod_refs (mach_task_self (), np->dn->u.reg.memobj,
-			    MACH_PORT_RIGHT_SEND, +1);
+  err = mach_port_mod_refs (mach_task_self (), right,
+                            MACH_PORT_RIGHT_SEND, +1);
   assert_perror_backtrace (err);
 
-  return np->dn->u.reg.memobj;
+  return right;
 }
 
 /* The user must define this function.  Return a `struct pager *' suitable
diff --git a/tmpfs/tmpfs.h b/tmpfs/tmpfs.h
index ad472009..40554557 100644
--- a/tmpfs/tmpfs.h
+++ b/tmpfs/tmpfs.h
@@ -46,7 +46,7 @@ struct disknode
     char *lnk;			/* malloc'd symlink target */
     struct
     {
-      mach_port_t memobj;
+      mach_port_t memobj, ro_memobj;
       vm_address_t memref;
       unsigned int allocpages;	/* largest size while memobj was live */
     } reg;
-- 
cgit v1.2.3