[Vm-dev] [OpenSmalltalk/opensmalltalk-vm] 28630b: The extra +1 in size parameter passed to mprotect(...

Ben Coman btc at openinworld.com
Sat Dec 24 04:03:19 UTC 2016


On Sat, Dec 24, 2016 at 2:33 AM, Holger Freyther <holger at freyther.de> wrote:
>
>
>
> > On 23 Dec 2016, at 01:46, Ben Coman <btc at openinworld.com> wrote:
> >
> > Just curious about the behaviour and performance of mprotect and VirtualProtect.  Would it be feasible to use on each FFI callout so that aberrant memory access from C code cannot corrupt the Smalltalk Image, but generate an exception that could be handled in-Image?
>
> Hi Ben,
>
> * syscall overhead (e.g. mprotect is not part of the VDSO)
> * lock/unlock of Page Table Entries (PTEs)
> * walking page table entries
> * modifying page table entries
> * merging/combining virtual memory areas now (allocation)
> * cache/tlb being invalidated
>
>
> E.g. for FreeBSD the chain is like this with a lot of details on the way
>
> * sys_mprotect[1] the syscall after the dispatch
> * vm_map_protect[2] for the VM subsystem
> * AMD64's pmap_protect[3] implementation various ways to invalidate the TLB in it
>
> holger
>
>
>
> [1] https://github.com/freebsd/freebsd/blob/releng/10.3/sys/vm/vm_mmap.c#L657
> [2] https://github.com/freebsd/freebsd/blob/releng/10.3/sys/vm/vm_map.c#L1924
> [3] https://github.com/freebsd/freebsd/blob/releng/10.3/sys/amd64/amd64/pmap.c#L3906


Thanks Holger.  A bit hard to soak up in a first sitting, but
interesting to get a feel for how it works under the covers.
I summarised the loops, so it seems it needs to modify every page table entry.

sys_mprotect()

   vm_map_protect()
      /* Make a first pass to check for protection violations.*/
      while ((current != &map->header) && (current->start < end))
      {... current = current->next; ...}

      /* Do an accounting pass for private read-only mappings that now
will do cow due to allowed write (e.g. debugger sets breakpoint on
text segment) */
     for (current = entry; (current != &map->header) &&
(current->start < end); current = current->next)
     {...}

     /* Go back and fix up protections. [Note that clipping is not
necessary the second time.] */
     current = entry;
     while ((current != &map->header) && (current->start < end))
     {
         ...
         pmap_protect()
              for (; sva < eva; sva = va_next) {
                 va_next = (sva + NBPDR) & ~PDRMASK;
                 for (pte = pmap_pde_to_pte(pde, sva); sva != va_next;
pte++,   sva += PAGE_SIZE)
                    {...flip page table bits...}
         current = current->next;
      }

The documentation of variables in the code there is not great.  I'm
guessing at variable purposes...
sva = start virtual address
eva = end virtual address
pte = page table entry
NBPDR=number bytes / page directory

So maybe useful for debugging, but not practical for every FFI call (??)
cheers -ben


More information about the Vm-dev mailing list