mlock & COW
Kip Macy
kip.macy at gmail.com
Sun Mar 9 22:36:10 UTC 2008
On Sun, Mar 9, 2008 at 2:24 PM, Jonathan Chen <jon at 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 at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"
>
More information about the freebsd-hackers
mailing list