Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Feb 2010 00:05:53 +0000 (UTC)
From:      Lawrence Stewart <lstewart@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r203939 - projects/tcp_cc_head/sys/netinet
Message-ID:  <201002160005.o1G05rG9054401@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: lstewart
Date: Tue Feb 16 00:05:53 2010
New Revision: 203939
URL: http://svn.freebsd.org/changeset/base/203939

Log:
  Add a simple refcount to helpers to resolve the possibility of use-after-free on
  unload of a module that still had data blocks in active use. Something better
  should probably be devised eventually.

Modified:
  projects/tcp_cc_head/sys/netinet/helper.c
  projects/tcp_cc_head/sys/netinet/helper.h

Modified: projects/tcp_cc_head/sys/netinet/helper.c
==============================================================================
--- projects/tcp_cc_head/sys/netinet/helper.c	Mon Feb 15 23:44:48 2010	(r203938)
+++ projects/tcp_cc_head/sys/netinet/helper.c	Tue Feb 16 00:05:53 2010	(r203939)
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/queue.h>
+#include <sys/refcount.h>
 #include <sys/rwlock.h>
 #include <sys/systm.h>
 
@@ -81,11 +82,12 @@ init_helper_dblocks(struct helper_dblock
 	    M_NOWAIT | M_ZERO);
 
 	if (hdbs->blocks != NULL) {
-		printf("Malloced ptr %p for %d data blocks\n", hdbs->blocks,
-		    num_dblocks);
+		/*printf("Malloced ptr %p for %d data blocks\n", hdbs->blocks,
+		    num_dblocks);*/
 		STAILQ_FOREACH(h, &helpers, h_next) {
 			if (h->h_flags & HELPER_NEEDS_DBLOCK) {
 				dblock = hdbs->blocks+i;
+				/*printf("Current dblock ptr: %p\n", dblock);*/
 				dblock->hd_block = uma_zalloc(h->h_zone,
 				    M_NOWAIT);
 				/*
@@ -96,9 +98,10 @@ init_helper_dblocks(struct helper_dblock
 				}
 				*/
 				dblock->hd_id = h->h_id;
-				printf("dblock[%d]: id=%d, block=%p\n", i,
-				dblock->hd_id, dblock->hd_block);
+				/*printf("dblock[%d]: id=%d, block=%p\n", i,
+				    dblock->hd_id, dblock->hd_block);*/
 				i++;
+				refcount_acquire(&h->h_refcount);
 			}
 		}
 		hdbs->nblocks = i;
@@ -118,8 +121,12 @@ destroy_helper_dblocks(struct helper_dbl
 	HELPER_LIST_WLOCK();
 
 	for (nblocks--; nblocks >= 0; nblocks--) {
-		if ((h = get_helper(hdbs->blocks[nblocks].hd_id)) != NULL)
+		if ((h = get_helper(hdbs->blocks[nblocks].hd_id)) != NULL) {
+			refcount_release(&h->h_refcount);
+			/*printf("destroy() freeing hdbs->blocks[%d] with ptr %p\n",
+			    nblocks, hdbs->blocks[nblocks].hd_block);*/
 			uma_zfree(h->h_zone, hdbs->blocks[nblocks].hd_block);
+		}
 	}
 
 	HELPER_LIST_WUNLOCK();
@@ -130,23 +137,22 @@ destroy_helper_dblocks(struct helper_dbl
 int
 register_helper(struct helper *h)
 {
-	printf("Register helper %p\n", h);
-
 	HELPER_LIST_WLOCK();
-
 	if (h->h_flags | HELPER_NEEDS_DBLOCK)
 		num_dblocks++;
 
+	refcount_init(&h->h_refcount, 0);
 	h->h_id = helper_id++;
 	STAILQ_INSERT_TAIL(&helpers, h, h_next);
 	HELPER_LIST_WUNLOCK();
+	printf("Registered \"%s\" helper (mem %p)\n", h->h_name, h);
 	return (0);
 }
 
 int
 deregister_helper(struct helper *h)
 {
-	printf("Deregister helper %p\n", h);
+	int error = 0;
 
 	/*
 	HHOOK_WLOCK
@@ -155,11 +161,17 @@ deregister_helper(struct helper *h)
 	*/
 
 	HELPER_LIST_WLOCK();
-	STAILQ_REMOVE(&helpers, h, helper, h_next);
-	if (h->h_flags | HELPER_NEEDS_DBLOCK)
-		num_dblocks--;
+	if (h->h_refcount > 0)
+		error = EBUSY;
+	
+	if (!error) {
+		STAILQ_REMOVE(&helpers, h, helper, h_next);
+		if (h->h_flags | HELPER_NEEDS_DBLOCK)
+			num_dblocks--;
+		printf("Deregistered \"%s\" helper (mem %p)\n", h->h_name, h);
+	}
 	HELPER_LIST_WUNLOCK();
-	return (0);
+	return (error);
 }
 
 int32_t
@@ -244,9 +256,12 @@ helper_modevent(module_t mod, int event_
 
 		case MOD_QUIESCE:
 			error = deregister_helper(hmd->helper);
-			uma_zdestroy(hmd->helper->h_zone);
-			if (!error && hmd->helper->mod_destroy != NULL)
-				hmd->helper->mod_destroy();
+			if (!error) {
+				uma_zdestroy(hmd->helper->h_zone);
+				if (hmd->helper->mod_destroy != NULL)
+					hmd->helper->mod_destroy();
+			} else
+				printf("Helper's refcount != 0, can't unload\n");
 			break;
 
 		case MOD_SHUTDOWN:
@@ -254,7 +269,7 @@ helper_modevent(module_t mod, int event_
 			break;
 
 		default:
-			return EINVAL;
+			error = EINVAL;
 			break;
 	}
 

Modified: projects/tcp_cc_head/sys/netinet/helper.h
==============================================================================
--- projects/tcp_cc_head/sys/netinet/helper.h	Mon Feb 15 23:44:48 2010	(r203938)
+++ projects/tcp_cc_head/sys/netinet/helper.h	Tue Feb 16 00:05:53 2010	(r203939)
@@ -54,6 +54,7 @@ struct helper {
 	uint16_t	h_flags;
 	uint32_t	h_class;
 	int32_t		h_id;
+	volatile uint32_t	h_refcount;
 	STAILQ_ENTRY(helper) h_next;
 };
 



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