Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 Mar 2008 15:12:07 -0700
From:      "Kip Macy" <kip.macy@gmail.com>
To:        "Jonathan Chen" <jon@freebsd.org>
Cc:        hackers@freebsd.org
Subject:   Re: mlock & COW
Message-ID:  <b1fa29170803091512v6e0b9ab6v24f3ce3659a714f8@mail.gmail.com>
In-Reply-To: <20080309212441.GA56523@porthos.spock.org>
References:  <20080309212441.GA56523@porthos.spock.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, Mar 9, 2008 at 2:24 PM, Jonathan Chen <jon@freebsd.org> wrote:
> I've been battling with a bug related to mlock and COW pages.  Since I'm
>  basically clueless when it comes to the VM subsystem, I was hoping someone
>  with more clue can look at my fix and let me know if I'm doing the right
>  thing here.
>
>  The problem: User programs will crash (SEGV/BUS) if COW pages become
>  writable after the pages are mlocked.  This happens if shared libraries is
>  loaded in a program after a call to mlockall(MCL_FUTURE), and can be seen
>  with amd and ntpd when nss_ldap is used in the system.  Included at the end
>  of this message is a sample program that demonstrates the problem.

I think the problem is mlock wires the pages that are backing those
mappings. So you're writing to a page that you don't have write access
to. You're best off ensuring that you have a private copy of all those
pages before mlocking().


>
>  The "solution": Forcibly wire the page via vm_fault_wire() when the page
>  protection bits are changed.  This seems to make the problem disappear, but
>  I'm not sure if causing a fault on vm_map_protect() is a good thing to do.

Uhm no. Don't do that.

>  Am I correct in thinking vm_fault_wire() will cause the COW page to be
>  copied immediately?  I think this is the right thing to do, given the page
>  is supposed to be wired, but I'm not sure if somewhere in the vm fault
>  routines might be a better place to put the fix.  I'm also not sure what
>  the last argument to vm_fault_wire() (fictitious) means, I just copied the
>  argument from another invocation.  My patch (against 7-STABLE) is included
>  below.


I'm not certain what the correct semantics are. You're patch *may* be OK.
 -Kip



>
>  I'll commit this if someone blesses the fix as the right thing.
>
>
>  Index: sys/vm/vm_map.c
>  ===================================================================
>  RCS file: /home/ncvs/src/sys/vm/vm_map.c,v
>  retrieving revision 1.388.2.3
>  diff -u -p -r1.388.2.3 vm_map.c
>  --- sys/vm/vm_map.c     18 Jan 2008 10:02:53 -0000      1.388.2.3
>  +++ sys/vm/vm_map.c     9 Mar 2008 20:55:50 -0000
>  @@ -1621,6 +1621,15 @@ vm_map_protect(vm_map_t map, vm_offset_t
>                             current->end,
>                             current->protection & MASK(current));
>   #undef MASK
>  +                       if ((entry->eflags &
>  +                           (MAP_ENTRY_USER_WIRED|MAP_ENTRY_COW)) ==
>  +                           (MAP_ENTRY_USER_WIRED|MAP_ENTRY_COW)) {
>  +                               vm_fault_wire(map, current->start,
>  +                                   current->end, TRUE,
>  +                                   entry->object.vm_object != NULL &&
>  +                                   entry->object.vm_object->type ==
>  +                                   OBJT_DEVICE);
>  +                       }
>                 }
>                 vm_map_simplify_entry(map, current);
>                 current = current->next;
>
>
>
>
>  bug demonstration code
>  ===================================================================
>
>  #include <unistd.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <strings.h>
>  #include <fcntl.h>
>  #include <sys/mman.h>
>
>  char *b;
>
>  int main() {
>     int fd = open("/usr/lib/libc.a", O_RDONLY);
>     if (fd < 0) {
>         perror("open");
>         exit(1);
>     }
>     b = mmap(0, 1024, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
>     if (b == MAP_FAILED) {
>         perror("mmap");
>         exit(0);
>     }
>     if (mlock(b, 1024) != 0) {
>         perror("mlock");
>     }
>     if (mprotect(b, 1024, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
>         perror("mprotect");
>     }
>     printf("memset crash now\n");
>     memset(b, 1, 1024);
>     printf("still alive\n");
>  }
>
>  -Jon
>  _______________________________________________
>  freebsd-hackers@freebsd.org mailing list
>  http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
>  To unsubscribe, send any mail to "freebsd-hackers-unsubscribe@freebsd.org"
>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b1fa29170803091512v6e0b9ab6v24f3ce3659a714f8>