Source-Changes-HG archive

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

[src/trunk]: src/sys Implement an aggressive psref leak detector



details:   https://anonhg.NetBSD.org/src/rev/576e6e7c7ac5
branches:  trunk
changeset: 451342:576e6e7c7ac5
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Fri May 17 03:34:26 2019 +0000

description:
Implement an aggressive psref leak detector

It is yet another psref leak detector that enables to tell where a leak occurs
while a simpler version that is already committed just tells an occurrence of a
leak.

Investigating of psref leaks is hard because once a leak occurs a percpu list of
psref that tracks references can be corrupted.  A reference to a tracking object
is memorized in the list via an intermediate object (struct psref) that is
normally allocated on a stack of a thread.  Thus, the intermediate object can be
overwritten on a leak resulting in corruption of the list.

The tracker makes a shadow entry to an intermediate object and stores some hints
into it (currently it's a caller address of psref_acquire).  We can detect a
leak by checking the entries on certain points where any references should be
released such as the return point of syscalls and the end of each softint
handler.

The feature is expensive and enabled only if the kernel is built with
PSREF_DEBUG.

Proposed on tech-kern

diffstat:

 sys/conf/files                           |    3 +-
 sys/kern/init_main.c                     |    8 +-
 sys/kern/kern_exit.c                     |    5 +-
 sys/kern/kern_lwp.c                      |    6 +-
 sys/kern/kern_softint.c                  |    6 +-
 sys/kern/subr_lwp_specificdata.c         |   12 ++-
 sys/kern/subr_psref.c                    |  142 +++++++++++++++++++++++++++++-
 sys/net/if.c                             |   10 +-
 sys/net/route.c                          |    6 +-
 sys/rump/kern/lib/libsysproxy/sysproxy.c |    6 +-
 sys/rump/librump/rumpkern/lwproc.c       |    6 +-
 sys/rump/librump/rumpkern/rump.c         |    8 +-
 sys/sys/lwp.h                            |    3 +-
 sys/sys/psref.h                          |   37 +++++++-
 sys/sys/userret.h                        |    4 +-
 15 files changed, 229 insertions(+), 33 deletions(-)

diffs (truncated from 659 to 300 lines):

diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/conf/files
--- a/sys/conf/files    Thu May 16 23:42:23 2019 +0000
+++ b/sys/conf/files    Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.1235 2019/04/26 10:11:03 jmcneill Exp $
+#      $NetBSD: files,v 1.1236 2019/05/17 03:34:26 ozaki-r Exp $
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
 version        20171118
@@ -315,6 +315,7 @@
 defflag                                LOCKDEBUG
 defflag                                SYSCALL_DEBUG
 defflag        opt_kstack.h            KSTACK_CHECK_MAGIC
+defflag                                PSREF_DEBUG
 
 # memory (ram) disk options
 #
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/init_main.c
--- a/sys/kern/init_main.c      Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/init_main.c      Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: init_main.c,v 1.503 2019/02/20 10:07:27 hannken Exp $  */
+/*     $NetBSD: init_main.c,v 1.504 2019/05/17 03:34:26 ozaki-r Exp $  */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.503 2019/02/20 10:07:27 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.504 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include "opt_ddb.h"
 #include "opt_inet.h"
@@ -195,6 +195,7 @@
 #include <sys/kauth.h>
 #include <net80211/ieee80211_netbsd.h>
 #include <sys/cprng.h>
+#include <sys/psref.h>
 
 #include <sys/syscall.h>
 #include <sys/syscallargs.h>
@@ -393,6 +394,9 @@
        procinit();
        lwpinit();
 
+       /* Must be called after lwpinit (lwpinit_specificdata) */
+       psref_init();
+
        /* Initialize signal-related data structures. */
        signal_init();
 
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c      Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/kern_exit.c      Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_exit.c,v 1.274 2019/03/01 09:02:03 hannken Exp $  */
+/*     $NetBSD: kern_exit.c,v 1.275 2019/05/17 03:34:26 ozaki-r Exp $  */
 
 /*-
  * Copyright (c) 1998, 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.274 2019/03/01 09:02:03 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.275 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_dtrace.h"
@@ -105,6 +105,7 @@
 #include <sys/lwpctl.h>
 #include <sys/atomic.h>
 #include <sys/sdt.h>
+#include <sys/psref.h>
 
 #include <uvm/uvm_extern.h>
 
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/kern_lwp.c
--- a/sys/kern/kern_lwp.c       Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/kern_lwp.c       Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_lwp.c,v 1.200 2019/05/03 22:34:21 kamil Exp $     */
+/*     $NetBSD: kern_lwp.c,v 1.201 2019/05/17 03:34:26 ozaki-r Exp $   */
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -211,7 +211,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.200 2019/05/03 22:34:21 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.201 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -242,6 +242,7 @@
 #include <sys/xcall.h>
 #include <sys/uidinfo.h>
 #include <sys/sysctl.h>
+#include <sys/psref.h>
 
 #include <uvm/uvm_extern.h>
 #include <uvm/uvm_object.h>
@@ -878,6 +879,7 @@
        cv_init(&l2->l_sigcv, "sigwait");
        cv_init(&l2->l_waitcv, "vfork");
        l2->l_syncobj = &sched_syncobj;
+       PSREF_DEBUG_INIT_LWP(l2);
 
        if (rnewlwpp != NULL)
                *rnewlwpp = l2;
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/kern_softint.c
--- a/sys/kern/kern_softint.c   Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/kern_softint.c   Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_softint.c,v 1.46 2019/04/19 01:52:55 ozaki-r Exp $        */
+/*     $NetBSD: kern_softint.c,v 1.47 2019/05/17 03:34:26 ozaki-r Exp $        */
 
 /*-
  * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
@@ -170,7 +170,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.46 2019/04/19 01:52:55 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.47 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -604,6 +604,8 @@
                sh->sh_flags ^= SOFTINT_ACTIVE;
        }
 
+       PSREF_DEBUG_BARRIER();
+
        if (havelock) {
                KERNEL_UNLOCK_ONE(l);
        }
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/subr_lwp_specificdata.c
--- a/sys/kern/subr_lwp_specificdata.c  Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/subr_lwp_specificdata.c  Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_lwp_specificdata.c,v 1.3 2013/10/25 16:17:35 martin Exp $ */
+/*     $NetBSD: subr_lwp_specificdata.c,v 1.4 2019/05/17 03:34:26 ozaki-r Exp $        */
 
 /*-
  * Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
 #define _LWP_API_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_lwp_specificdata.c,v 1.3 2013/10/25 16:17:35 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_lwp_specificdata.c,v 1.4 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/lwp.h>
@@ -129,3 +129,11 @@
        specificdata_setspecific(lwp_specificdata_domain,
                                 &curlwp->l_specdataref, key, data);
 }
+
+void
+lwp_setspecific_by_lwp(struct lwp *l, specificdata_key_t key, void *data)
+{
+
+       specificdata_setspecific(lwp_specificdata_domain,
+                                &l->l_specdataref, key, data);
+}
diff -r bd5d1e0dd104 -r 576e6e7c7ac5 sys/kern/subr_psref.c
--- a/sys/kern/subr_psref.c     Thu May 16 23:42:23 2019 +0000
+++ b/sys/kern/subr_psref.c     Fri May 17 03:34:26 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_psref.c,v 1.12 2019/04/19 01:52:55 ozaki-r Exp $  */
+/*     $NetBSD: subr_psref.c,v 1.13 2019/05/17 03:34:26 ozaki-r Exp $  */
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.12 2019/04/19 01:52:55 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.13 2019/05/17 03:34:26 ozaki-r Exp $");
 
 #include <sys/types.h>
 #include <sys/condvar.h>
@@ -77,6 +77,7 @@
 #include <sys/psref.h>
 #include <sys/queue.h>
 #include <sys/xcall.h>
+#include <sys/lwp.h>
 
 SLIST_HEAD(psref_head, psref);
 
@@ -108,6 +109,44 @@
 };
 
 /*
+ * Data structures and functions for debugging.
+ */
+#ifndef PSREF_DEBUG_NITEMS
+#define PSREF_DEBUG_NITEMS 16
+#endif
+
+struct psref_debug_item {
+       void                    *prdi_caller;
+       struct psref            *prdi_psref;
+};
+
+struct psref_debug {
+       int                     prd_refs_peek;
+       struct psref_debug_item prd_items[PSREF_DEBUG_NITEMS];
+};
+
+#ifdef PSREF_DEBUG
+static void psref_debug_acquire(struct psref *);
+static void psref_debug_release(struct psref *);
+
+static void psref_debug_lwp_free(void *);
+
+static specificdata_key_t psref_debug_lwp_key;
+#endif
+
+/*
+ * psref_init()
+ */
+void
+psref_init(void)
+{
+
+#ifdef PSREF_DEBUG
+       lwp_specific_key_create(&psref_debug_lwp_key, psref_debug_lwp_free);
+#endif
+}
+
+/*
  * psref_class_create(name, ipl)
  *
  *     Create a new passive reference class, with the given wchan name
@@ -279,9 +318,12 @@
        percpu_putref(class->prc_percpu);
        splx(s);
 
-#ifdef DIAGNOSTIC
+#if defined(DIAGNOSTIC) || defined(PSREF_DEBUG)
        curlwp->l_psrefs++;
 #endif
+#ifdef PSREF_DEBUG
+       psref_debug_acquire(psref);
+#endif
 }
 
 /*
@@ -336,10 +378,13 @@
        percpu_putref(class->prc_percpu);
        splx(s);
 
-#ifdef DIAGNOSTIC
+#if defined(DIAGNOSTIC) || defined(PSREF_DEBUG)
        KASSERT(curlwp->l_psrefs > 0);
        curlwp->l_psrefs--;
 #endif
+#ifdef PSREF_DEBUG
+       psref_debug_release(psref);
+#endif
 
        /* If someone is waiting for users to drain, notify 'em.  */
        if (__predict_false(target->prt_draining))
@@ -398,7 +443,7 @@
        percpu_putref(class->prc_percpu);
        splx(s);
 
-#ifdef DIAGNOSTIC
+#if defined(DIAGNOSTIC) || defined(PSREF_DEBUG)
        curlwp->l_psrefs++;
 #endif
 }
@@ -565,3 +610,90 @@
 
        return _psref_held(target, class, false);
 }
+
+#ifdef PSREF_DEBUG
+void
+psref_debug_init_lwp(struct lwp *l)
+{
+       struct psref_debug *prd;
+
+       prd = kmem_zalloc(sizeof(*prd), KM_SLEEP);
+       lwp_setspecific_by_lwp(l, psref_debug_lwp_key, prd);
+}
+
+static void
+psref_debug_lwp_free(void *arg)
+{
+       struct psref_debug *prd = arg;
+
+       kmem_free(prd, sizeof(*prd));



Home | Main Index | Thread Index | Old Index