Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src - In uvm_voaddr_acquire(), take an extra hold on the anon lo...



details:   https://anonhg.NetBSD.org/src/rev/78966b4f7de3
branches:  trunk
changeset: 971631:78966b4f7de3
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Thu Apr 30 04:18:07 2020 +0000

description:
- In uvm_voaddr_acquire(), take an extra hold on the anon lock obj.
- In uvm_voaddr_release(), if the anon ref count drops to 0, call
  uvm_anfree() rather than uvm_anon_release().  Unconditionally drop
  the anon lock, and release the extra hold on the anon lock obj.

Fixes a panic that occurs if the backing store for a futex backed by
an anon memory location is unmapped while a thread is waiting in the
futex.

Add a test case that reproduced the panic to verify that it's fixed.

diffstat:

 sys/uvm/uvm_map.c                |  17 ++++----
 tests/lib/libc/sys/t_futex_ops.c |  78 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 10 deletions(-)

diffs (175 lines):

diff -r 0a3269acfcd9 -r 78966b4f7de3 sys/uvm/uvm_map.c
--- a/sys/uvm/uvm_map.c Thu Apr 30 03:42:23 2020 +0000
+++ b/sys/uvm/uvm_map.c Thu Apr 30 04:18:07 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uvm_map.c,v 1.381 2020/04/19 08:59:53 skrll Exp $      */
+/*     $NetBSD: uvm_map.c,v 1.382 2020/04/30 04:18:07 thorpej Exp $    */
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.381 2020/04/19 08:59:53 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.382 2020/04/30 04:18:07 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_pax.h"
@@ -4934,6 +4934,7 @@
                if (anon) {
  found_anon:           KASSERT(anon->an_lock == entry->aref.ar_amap->am_lock);
                        anon->an_ref++;
+                       rw_obj_hold(anon->an_lock);
                        KASSERT(anon->an_ref != 0);
                        voaddr->type = UVM_VOADDR_TYPE_ANON;
                        voaddr->anon = anon;
@@ -4987,16 +4988,16 @@
            }
        case UVM_VOADDR_TYPE_ANON: {
                struct vm_anon * const anon = voaddr->anon;
+               krwlock_t *lock;
 
                KASSERT(anon != NULL);
-               rw_enter(anon->an_lock, RW_WRITER);
+               rw_enter((lock = anon->an_lock), RW_WRITER);
                KASSERT(anon->an_ref > 0);
-               anon->an_ref--;
-               if (anon->an_ref == 0) {
-                       uvm_anon_release(anon);
-               } else {
-                       rw_exit(anon->an_lock);
+               if (--anon->an_ref == 0) {
+                       uvm_anfree(anon);
                }
+               rw_exit(lock);
+               rw_obj_free(lock);
                break;
            }
        default:
diff -r 0a3269acfcd9 -r 78966b4f7de3 tests/lib/libc/sys/t_futex_ops.c
--- a/tests/lib/libc/sys/t_futex_ops.c  Thu Apr 30 03:42:23 2020 +0000
+++ b/tests/lib/libc/sys/t_futex_ops.c  Thu Apr 30 04:18:07 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_futex_ops.c,v 1.2 2020/04/28 17:27:03 riastradh Exp $ */
+/* $NetBSD: t_futex_ops.c,v 1.3 2020/04/30 04:18:07 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
 #include <sys/cdefs.h>
 __COPYRIGHT("@(#) Copyright (c) 2019, 2020\
  The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_futex_ops.c,v 1.2 2020/04/28 17:27:03 riastradh Exp $");
+__RCSID("$NetBSD: t_futex_ops.c,v 1.3 2020/04/30 04:18:07 thorpej Exp $");
 
 #include <sys/fcntl.h>
 #include <sys/mman.h>
@@ -39,6 +39,7 @@
 #include <lwp.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <signal.h>
 #include <time.h>
 #include <limits.h>
 #include <unistd.h>
@@ -166,12 +167,15 @@
 
        d->threadid = _lwp_self();
 
+       membar_producer();
        atomic_inc_uint(&nlwps_running);
        membar_sync();
 
        if (__futex(d->futex_ptr, d->wait_op | d->op_flags,
                    d->block_val, NULL, NULL, 0, d->bitset) == -1) {
                d->futex_error = errno;
+               membar_sync();
+               atomic_dec_uint(&nlwps_running);
                _lwp_exit();
        } else {
                d->futex_error = 0;
@@ -1262,6 +1266,74 @@
 
 /*****************************************************************************/
 
+static void
+sig_noop(int sig __unused)
+{
+}
+
+static void (*old_act)(int) = SIG_DFL;
+
+static void
+do_futex_wait_evil_unmapped(int map_flags)
+{
+       int i;
+
+       create_bs(map_flags);
+
+       old_act = signal(SIGUSR1, sig_noop);
+       ATF_REQUIRE(old_act != SIG_ERR);
+
+       setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp);
+       lwp_data[0].op_flags = 0;
+       lwp_data[0].futex_error = -1;
+       lwp_data[0].futex_ptr = &bs_addr[0];
+       lwp_data[0].block_val = 0;
+       lwp_data[0].bitset = 0;
+       lwp_data[0].wait_op = FUTEX_WAIT;
+       ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0,
+                               &lwp_data[0].lwpid) == 0);
+
+       for (i = 0; i < 5; i++) {
+               membar_sync();
+               if (nlwps_running == 1)
+                       break;
+               sleep(1);
+       }
+       membar_sync();
+       ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "waiters failed to start");
+
+       /* Ensure it's blocked. */
+       ATF_REQUIRE(lwp_data[0].futex_error == -1);
+
+       /* Rudely unmap the backing store. */
+       cleanup_bs();
+
+       /* Signal the waiter so that it leaves the futex. */
+       ATF_REQUIRE(_lwp_kill(lwp_data[0].threadid, SIGUSR1) == 0);
+
+       /* Yay! No panic! */
+
+       reap_lwp_waiter(&lwp_data[0]);
+}
+
+ATF_TC_WITH_CLEANUP(futex_wait_evil_unmapped_anon);
+ATF_TC_HEAD(futex_wait_evil_unmapped_anon, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "tests futex WAIT while futex is unmapped - anon memory");
+}
+ATF_TC_BODY(futex_wait_evil_unmapped_anon, tc)
+{
+       do_futex_wait_evil_unmapped(MAP_ANON);
+}
+ATF_TC_CLEANUP(futex_wait_evil_unmapped_anon, tc)
+{
+       signal(SIGUSR1, old_act);
+       do_cleanup();
+}
+
+/*****************************************************************************/
+
 ATF_TP_ADD_TCS(tp)
 {
        ATF_TP_ADD_TC(tp, futex_basic_wait_wake_private);
@@ -1284,6 +1356,8 @@
        ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline);
        ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline_rt);
 
+       ATF_TP_ADD_TC(tp, futex_wait_evil_unmapped_anon);
+
        ATF_TP_ADD_TC(tp, futex_requeue);
        ATF_TP_ADD_TC(tp, futex_cmp_requeue);
 



Home | Main Index | Thread Index | Old Index