PERFORCE change 92921 for review

Todd Miller millert at FreeBSD.org
Tue Mar 7 08:47:10 PST 2006


http://perforce.freebsd.org/chv.cgi?CH=92921

Change 92921 by millert at millert_ibook on 2006/03/07 16:46:29

	Change how label handles are freed when their reference
	count reaches zero.  We no longer free label handle storage
	when the ref count == 0.  For kernel-allocated label handles,
	just deallocate the associated port.  The actual label
	handle storage is deallocated by labelh_destroy() which is
	called by ipc_kobject_destroy() after all port references
	are gone.  This fixes a race between a user program requesting
	(and accessing) the label of a labeled kernel object and
	the destruction of that object (task, port, etc).

Affected files ...

.. //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/ipc/ipc_labelh.c#8 edit
.. //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/ipc/ipc_labelh.h#9 edit
.. //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/kern/ipc_kobject.c#4 edit

Differences ...

==== //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/ipc/ipc_labelh.c#8 (text+ko) ====

@@ -47,7 +47,7 @@
 	if (space == IS_NULL || space->is_task == NULL)
 		return (KERN_INVALID_TASK);
 
-	/* XXX - perform entrypoint check here */
+	/* XXX - perform entrypoint check here? */
 
 	/*
 	 * Note: the calling task will have a receive right for the port.
@@ -75,7 +75,7 @@
 	lh->lh_port = port;
 	lh->lh_label = *inl;
 	lh->lh_type = LABELH_TYPE_USER;
-	lh->lh_references = 1;
+	lh->lh_references = 1;		/* unused for LABELH_TYPE_USER */
 
 	/* Must call ipc_kobject_set() with port unlocked. */
 	ip_unlock(lh->lh_port);
@@ -154,6 +154,11 @@
 {
 	ipc_labelh_t lh;
 
+	/*
+	 * A label handle may only have a single reference. 
+	 * If there are no other references this is a no-op.
+	 * Otherwise, make a copy we can write to and return it.
+	 */
 	if (old->lh_references == 1)
 		return (old);
 	lh = labelh_duplicate(old);
@@ -175,6 +180,9 @@
 	return (lh);
 }
 
+/*
+ * Release a reference on an (unlocked) label handle.
+ */
 void
 labelh_release(ipc_labelh_t lh)
 {
@@ -183,10 +191,18 @@
 	lh_check_unlock(lh);
 }
 
+/*
+ * Deallocate space associated with the label handle backed by the
+ * specified port.  For kernel-allocated label handles the
+ * label handle reference count should be 0.  For user-allocated
+ * handles the ref count is not used (it was initialized to 1).
+ */
 void
-lh_free(ipc_labelh_t lh)
+labelh_destroy(ipc_port_t port)
 {
-	ipc_object_release(&lh->lh_port->ip_object);
+	ipc_labelh_t lh = (ipc_labelh_t) port->ip_kobject;
+
+	ip_release(lh->lh_port);
 	mac_destroy_port_label(&lh->lh_label);
 	zfree(ipc_labelh_zone, (vm_offset_t)lh);
 }

==== //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/ipc/ipc_labelh.h#9 (text+ko) ====

@@ -47,19 +47,19 @@
 #define	LABELH_TYPE_KERN	0
 #define	LABELH_TYPE_USER	1
 
+void labelh_destroy(ipc_port_t port);
 ipc_labelh_t labelh_duplicate(ipc_labelh_t old);
 ipc_labelh_t labelh_modify(ipc_labelh_t old);
 ipc_labelh_t labelh_new(void);
 kern_return_t labelh_new_user(ipc_space_t, struct label *, mach_port_name_t *);
 void labelh_release(ipc_labelh_t lh);
 ipc_labelh_t labelh_reference(ipc_labelh_t lh);
-void lh_free(ipc_labelh_t lh);
 
 #define lh_reference(lh)	((lh)->lh_references++)
-#define lh_release(lh)					\
-MACRO_BEGIN						\
-  assert((lh)->lh_references > 0);			\
-	(lh)->lh_references--;				\
+#define lh_release(lh)						\
+MACRO_BEGIN							\
+	assert((lh)->lh_references > 0);			\
+	(lh)->lh_references--;					\
 MACRO_END
 
 extern zone_t ipc_labelh_zone;
@@ -67,13 +67,21 @@
 #define lh_lock io_lock
 #define lh_unlock io_unlock
 
-#define lh_check_unlock(lh) 		       			\
-MACRO_BEGIN				       			\
+/*
+ * Check the number of references the label handle a left.
+ * If there are 0 references and this is a kernel-allocated
+ * label handle, deallocate the associated port.  The
+ * storage space for the label handle will be deallocated
+ * as part of the port destruction.  User-allocated label
+ * handles are destroyed along with their ports.
+ */
+#define lh_check_unlock(lh)					\
+MACRO_BEGIN							\
 	_VOLATILE_ natural_t _refs = (lh)->lh_references;	\
-					       			\
-	lh_unlock(lh);			       			\
-	if (_refs == 0)			       			\
-		lh_free(lh);		      			\
+								\
+	lh_unlock(lh);						\
+	if (_refs == 0 && (lh)->lh_type == LABELH_TYPE_KERN)	\
+		ipc_port_dealloc_kernel((lh)->lh_port);		\
 MACRO_END
 
 #endif

==== //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/kern/ipc_kobject.c#4 (text+ko) ====

@@ -514,7 +514,7 @@
 		break;
 
 	case IKOT_LABELH:
-		labelh_release(port->ip_kobject);
+		labelh_destroy(port);
 		break;
 
 	default:


More information about the trustedbsd-cvs mailing list