kernel - Add sysref assertions
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Aug 2010 04:11:20 +0000 (21:11 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Aug 2010 04:11:20 +0000 (21:11 -0700)
* Add checks in the sysref code to detect use-after-free situations.

sys/kern/kern_sysref.c
sys/sys/sysref.h

index f9250ec..96b748e 100644 (file)
@@ -153,6 +153,8 @@ sysref_alloc(struct sysref_class *srclass)
         */
        data = objcache_get(srclass->oc, M_WAITOK);
        sr = (struct sysref *)(data + srclass->offset);
+       KKASSERT(sr->flags & SRF_PUTAWAY);
+       sr->flags &= ~SRF_PUTAWAY;
 
        /*
         * Refcnt isn't touched while it is zero.  The objcache ctor
@@ -216,7 +218,7 @@ sysref_ctor(void *data, void *privdata, int ocflags)
        sr->sysid = gd->gd_sysid_alloc;
        KKASSERT(((int)sr->sysid & ncpus_fit_mask) == gd->gd_cpuid);
        /* sr->refcnt= 0; already zero */
-       sr->flags = SRF_ALLOCATED;
+       sr->flags = SRF_ALLOCATED | SRF_PUTAWAY;
        sr->srclass = srclass;
 
        sa = &sysref_array[gd->gd_cpuid];
@@ -299,6 +301,8 @@ _sysref_put(struct sysref *sr)
        int count;
        void *data;
 
+       KKASSERT((sr->flags & SRF_PUTAWAY) == 0);
+
        for (;;) {
                count = sr->refcnt;
                if (count > 1) {
@@ -341,6 +345,7 @@ _sysref_put(struct sysref *sr)
                        KKASSERT(count == -0x40000000);
                        if (atomic_cmpset_int(&sr->refcnt, count, 0)) {
                                KKASSERT(sr->flags & SRF_ALLOCATED);
+                               sr->flags |= SRF_PUTAWAY;
                                data = (char *)sr - sr->srclass->offset;
                                if (sr->flags & SRF_SYSIDUSED)
                                        objcache_dtor(sr->srclass->oc, data);
index a496d77..7afc2dc 100644 (file)
@@ -116,6 +116,7 @@ struct sysref {
 
 #define SRF_SYSIDUSED  0x0001          /* sysid was used for access */
 #define SRF_ALLOCATED  0x0002          /* sysref_alloc used to allocate */
+#define SRF_PUTAWAY    0x0004          /* in objcache */
 
 RB_HEAD(sysref_rb_tree, sysref);
 RB_PROTOTYPE2(sysref_rb_tree, sysref, rbnode, rb_sysref_compare, sysid_t);