PERFORCE change 111036 for review

Todd Miller millert at FreeBSD.org
Mon Dec 4 10:05:40 PST 2006


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

Change 111036 by millert at millert_macbook on 2006/12/04 18:04:51

	Integrate Device Access Control changes.
	Support Array/Dictionary in OSModuleData.
	Move 'device_access' policy configuration to Info.plist.

Affected files ...

.. //depot/projects/trustedbsd/sedarwin8/darwin/build/mkPolicyInfoPlist.sh#3 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/drivers/DeviceAccessControl/DeviceAccessControlFireWire.h#3 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/drivers/DeviceAccessControl/DeviceAccessControlUSB.h#3 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/xnu/iokit/Kernel/IOCatalogue.cpp#4 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac.h#10 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_base.c#23 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_data.h#4 edit
.. //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_iokit.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/device_access/mac_device_access.c#5 edit

Differences ...

==== //depot/projects/trustedbsd/sedarwin8/darwin/build/mkPolicyInfoPlist.sh#3 (xtext) ====

@@ -28,6 +28,13 @@
 	<key>OSBundleCompatibleVersion</key>
 	<string>${POLICY_COMPVER}</string>
 
+__EOF__
+
+if [ -f Default.plist ] ; then
+	cat Default.plist
+fi
+
+cat << __EOF__
 	<key>OSBundleLibraries</key>
 	<dict>
 __EOF__

==== //depot/projects/trustedbsd/sedarwin8/darwin/drivers/DeviceAccessControl/DeviceAccessControlFireWire.h#3 (text+ko) ====

@@ -52,7 +52,7 @@
 extern "C" vm_map_t kernel_map;
 extern "C" void kmem_free(vm_map_t map, vm_offset_t addr, vm_size_t size);
 
-extern "C" int mac_iokit_check_device(int, struct mac_module_data *);
+extern "C" int mac_iokit_check_device(char *, struct mac_module_data *);
 
 // Uncomment to enable debug output
 #define DEVICEACCESSCONTROL_DEBUG 1

==== //depot/projects/trustedbsd/sedarwin8/darwin/drivers/DeviceAccessControl/DeviceAccessControlUSB.h#3 (text+ko) ====

@@ -51,7 +51,7 @@
 extern "C" vm_map_t kernel_map;
 extern "C" void kmem_free(vm_map_t map, vm_offset_t addr, vm_size_t size);
 
-extern "C" int mac_iokit_check_device(int, struct mac_module_data *);
+extern "C" int mac_iokit_check_device(char *, struct mac_module_data *);
 
 // Uncomment to enable debug output
 #define DEVICEACCESSCONTROL_DEBUG 1

==== //depot/projects/trustedbsd/sedarwin8/darwin/xnu/iokit/Kernel/IOCatalogue.cpp#4 (text+ko) ====

@@ -57,6 +57,17 @@
 
 #include <IOKit/assert.h>
 
+/* 
+ * define IOC_DEBUG to display run-time debugging information
+ * #define IOC_DEBUG 1
+ */
+
+#ifdef IOC_DEBUG
+#define DPRINTF(x)	printf x
+#else
+#define IOC_DEBUG
+#define DPRINTF(x)
+#endif
 
 extern "C" {
 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
@@ -130,6 +141,86 @@
 extern "C" kern_return_t kmod_retain(kmod_t id);
 extern "C" kern_return_t kmod_release(kmod_t id);
 
+static bool
+primitive_type(OSObject *obj)
+{
+    const OSMetaClass *typeID;
+
+    typeID = OSTypeIDInst(obj);
+    if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
+        typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData))
+	return(true);
+    else
+	return(false);
+}
+
+static int
+primitive_type_length(OSObject *obj)
+{
+    const OSMetaClass *typeID;
+    int len;
+
+    typeID = OSTypeIDInst(obj);
+    if (typeID == OSTypeID(OSString)) {
+        OSString * stringObj = OSDynamicCast(OSString, obj);
+        len = stringObj->getLength() + 1;
+    }
+    else if (typeID == OSTypeID(OSNumber)) {
+        len = sizeof("4294967295");	/* UINT32_MAX */
+    }
+    else if (typeID == OSTypeID(OSBoolean)) {
+        OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
+        len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
+    }
+    else if (typeID == OSTypeID(OSData)) {
+        OSData * dataObj = OSDynamicCast(OSData, obj);
+        len = dataObj->getLength();
+    }
+    else {
+	len = 0;
+    }
+    return(len);
+}
+
+static void
+primitive_type_collect(struct mac_module_data_element *element, OSObject *value)
+{
+    const OSMetaClass *typeID;
+
+    typeID = OSTypeIDInst(value);
+    if (typeID == OSTypeID(OSString)) {
+        OSString *stringObj = OSDynamicCast(OSString, value);
+        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
+        element->value_size = stringObj->getLength() + 1;
+	DPRINTF(("osdict: string %s size %d\n", 
+	    stringObj->getCStringNoCopy(), element->value_size));
+        memcpy(element->value, stringObj->getCStringNoCopy(),
+            element->value_size);
+    } else if (typeID == OSTypeID(OSNumber)) {
+        OSNumber *numberObj = OSDynamicCast(OSNumber, value);
+        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
+        element->value_size = sprintf(element->value, "%u",
+	    numberObj->unsigned32BitValue()) + 1;
+    } else if (typeID == OSTypeID(OSBoolean)) {
+        OSBoolean *boolObj = OSDynamicCast(OSBoolean, value);
+        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
+        if (boolObj->isTrue()) {
+            strcpy(element->value, "true");
+            element->value_size = 5;
+        } else {
+            strcpy(element->value, "false");
+            element->value_size = 6;
+        }
+    } else if (typeID == OSTypeID(OSData)) {
+        OSData *dataObj = OSDynamicCast(OSData, value);
+        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
+        element->value_size = dataObj->getLength();
+ 	DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
+        memcpy(element->value, dataObj->getBytesNoCopy(),
+            element->value_size);
+    }
+}
+
 /*********************************************************************
 * This function takes an OSDictionary and returns a struct mac_module_data
 * list.
@@ -143,9 +234,13 @@
     struct mac_module_data * module_data = 0;
     struct mac_module_data_element * element;
     unsigned int strtabsize = 0;
+    unsigned int listtabsize = 0;
+    unsigned int dicttabsize = 0;
     unsigned int nkeys = 0;
     unsigned int datalen;
-    char * strtab = 0;
+    char *strtab = NULL;
+    char *listtab = NULL;
+    char *dicttab = NULL;
     vm_offset_t data_addr;
 
     keyIterator = OSCollectionIterator::withCollection(dict);
@@ -161,18 +256,69 @@
             continue;
 
 	typeID = OSTypeIDInst(value);
-	if (typeID == OSTypeID(OSString)) {
-	    OSString * stringObj = OSDynamicCast(OSString, value);
-	    strtabsize += stringObj->getLength() + 1;
-	} else if (typeID == OSTypeID(OSNumber)) {
-	    strtabsize += sizeof("4294967295");	/* UINT32_MAX */
-	} else if (typeID == OSTypeID(OSBoolean)) {
-	    OSBoolean * boolObj = OSDynamicCast(OSBoolean, value);
-	    strtabsize += boolObj->isTrue() ? sizeof("true") : sizeof("false");
-	} else if (typeID == OSTypeID(OSData)) {
-	    OSData * dataObj = OSDynamicCast(OSData, value);
-	    strtabsize += dataObj->getLength();
-	} else {
+	if (primitive_type(value)) {
+	    strtabsize += primitive_type_length(value);
+	}
+	else if (typeID == OSTypeID(OSArray)) {
+	    unsigned int k, cnt, nents;
+	    OSArray *arrayObj = OSDynamicCast(OSArray, value);
+
+	    nents = 0;
+	    cnt = arrayObj->getCount();
+	    for (k = 0; k < cnt; k++) {
+		value = arrayObj->getObject(k);
+		typeID = OSTypeIDInst(value);
+		if (primitive_type(value)) {
+		    listtabsize += primitive_type_length(value);
+		    nents++;
+		}
+		else if (typeID == OSTypeID(OSDictionary)) {
+		    unsigned int dents;
+		    OSDictionary *dictObj;
+		    OSString *dictkey;
+		    OSCollectionIterator *dictIterator;
+
+		    dents = 0;
+		    dictObj = OSDynamicCast(OSDictionary, value);
+		    dictIterator = OSCollectionIterator::withCollection(dictObj);
+		    if (!dictIterator)
+			goto finish;
+		    while ((dictkey = OSDynamicCast(OSString,
+			    		      dictIterator->getNextObject()))) {
+			OSObject *dictvalue;
+
+			dictvalue = dictObj->getObject(dictkey);
+			if (!dictvalue)
+			    continue;
+			if (primitive_type(dictvalue)) {
+			    strtabsize += primitive_type_length(dictvalue);
+			}
+			else {
+			    continue;	/* Only handle primitive types here.  */
+			}
+			/*
+			 * Allow for the "arraynnn/" prefix in the key length.
+			 */
+			strtabsize += dictkey->getLength() + 1;
+			dents++;
+		    }
+		    dictIterator->release();
+		    if (dents-- > 0) {
+			dicttabsize += sizeof(struct mac_module_data_list) +
+			    dents * sizeof(struct mac_module_data_element);
+			nents++;
+		    }
+		}
+		else {
+		    continue;		/* Skip everything else.              */
+		}
+	    }
+	    if (nents == 0)
+		continue;
+	    listtabsize += sizeof(struct mac_module_data_list) +
+		(nents - 1) * sizeof(struct mac_module_data_element);
+	}
+	else {
 	    continue;		/* skip anything else */
 	}
 	strtabsize += key->getLength() + 1;
@@ -185,16 +331,26 @@
      * Allocate and fill in the module data structures.
      */
     datalen = sizeof(struct mac_module_data) +
-	sizeof(mac_module_data_element) * (nkeys - 1) + strtabsize;
+	sizeof(mac_module_data_element) * (nkeys - 1) +
+        strtabsize + listtabsize + dicttabsize;
+    DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n", 
+	    datalen, strtabsize, listtabsize, dicttabsize));
     if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS)
 	goto finish;
     module_data = (mac_module_data *)data_addr;
+    module_data->base_addr = data_addr;
     module_data->size = datalen;
     module_data->count = nkeys;
     strtab = (char *)&module_data->data[nkeys];
+    listtab = strtab + strtabsize;
+    dicttab = listtab + listtabsize;
+    DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n", 
+	    data_addr, strtab, listtab, dicttab, data_addr + datalen));
 
     keyIterator->reset();
+    nkeys = 0;
     element = &module_data->data[0];
+    DPRINTF(("osdict: element %p\n", element));
     while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
 
 	// Get the key's value and determine its type
@@ -203,43 +359,138 @@
             continue;
 
 	/* Store key */
+	DPRINTF(("osdict: element @%p\n", element));
 	element->key = strtab;
 	element->key_size = key->getLength() + 1;
+	DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(), element->key_size, strtab));
 	memcpy(element->key, key->getCStringNoCopy(), element->key_size);
 
-	/* Store value */
-	element->value = element->key + element->key_size;
 	typeID = OSTypeIDInst(value);
-	if (typeID == OSTypeID(OSString)) {
-	    OSString * stringObj = OSDynamicCast(OSString, value);
-	    element->value_size = stringObj->getLength() + 1;
-	    memcpy(element->value, stringObj->getCStringNoCopy(),
-		element->value_size);
-	} else if (typeID == OSTypeID(OSNumber)) {
-	    OSNumber * numberObj = OSDynamicCast(OSNumber, value);
-	    element->value_size = sprintf(element->value, "%u",
-		numberObj->unsigned32BitValue()) + 1;
-	} else if (typeID == OSTypeID(OSBoolean)) {
-	    OSBoolean * boolObj = OSDynamicCast(OSBoolean, value);
-	    if (boolObj->isTrue()) {
-		strcpy(element->value, "true");
-		element->value_size = 5;
-	    } else {
-		strcpy(element->value, "false");
-		element->value_size = 6;
+	if (primitive_type(value)) {
+	    /* Store value */
+	    element->value = element->key + element->key_size;
+	    DPRINTF(("osdict: primitive element value %p\n", element->value));
+	    primitive_type_collect(element, value);
+	    strtab += element->key_size + element->value_size;
+	    DPRINTF(("osdict: new strtab %p\n", strtab));
+	}
+	else if (typeID == OSTypeID(OSArray)) {
+	    unsigned int k, cnt, nents;
+	    char *astrtab;
+	    struct mac_module_data_list *arrayhd;
+	    struct mac_module_data_element *ele;
+	    OSArray *arrayObj = OSDynamicCast(OSArray, value);
+
+	    element->value = listtab;
+	    DPRINTF(("osdict: array element value %p\n", element->value));
+	    element->value_type = MAC_DATA_TYPE_ARRAY;
+	    arrayhd = (struct mac_module_data_list *)element->value;
+	    arrayhd->type = 0;
+	    DPRINTF(("osdict: arrayhd %p\n", arrayhd));
+	    nents = 0;
+	    astrtab = strtab + element->key_size;
+	    ele = &(arrayhd->list[0]);
+	    cnt = arrayObj->getCount();
+	    for (k = 0; k < cnt; k++) {
+		value = arrayObj->getObject(k);
+		DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
+		ele->key = NULL;
+		ele->key_size = 0;
+		typeID = OSTypeIDInst(value);
+		if (primitive_type(value)) {
+		    if (arrayhd->type != 0 &&
+			arrayhd->type != MAC_DATA_TYPE_PRIMITIVE)
+			continue;
+		    arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
+		    ele->value = astrtab;
+		    primitive_type_collect(ele, value);
+		    astrtab += ele->value_size;
+		    DPRINTF(("osdict: array new astrtab %p\n", astrtab));
+		}
+		else if (typeID == OSTypeID(OSDictionary)) {
+		    unsigned int dents;
+		    char *dstrtab;
+		    OSDictionary *dictObj;
+		    OSString *dictkey;
+		    OSCollectionIterator *dictIterator;
+		    struct mac_module_data_list *dicthd;
+		    struct mac_module_data_element *dele;
+
+		    if (arrayhd->type != 0 &&
+			arrayhd->type != MAC_DATA_TYPE_DICT)
+			continue;
+		    dictObj = OSDynamicCast(OSDictionary, value);
+		    dictIterator = OSCollectionIterator::withCollection(dictObj);
+		    if (!dictIterator)
+			goto finish;
+		    DPRINTF(("osdict: dict\n"));
+		    ele->value = dicttab;
+		    ele->value_type = MAC_DATA_TYPE_DICT;
+		    dicthd = (struct mac_module_data_list *)ele->value;
+		    DPRINTF(("osdict: dicthd %p\n", dicthd));
+		    dstrtab = astrtab;
+		    dents = 0;
+		    while ((dictkey = OSDynamicCast(OSString,
+			    		      dictIterator->getNextObject()))) {
+			OSObject *dictvalue;
+
+			dictvalue = dictObj->getObject(dictkey);
+			if (!dictvalue)
+			    continue;
+			dele = &(dicthd->list[dents]);
+			DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
+			if (primitive_type(dictvalue)) {
+			    dele->key = dstrtab;
+			    dele->key_size = dictkey->getLength() + 1;
+			    DPRINTF(("osdict: dictkey %s size %d @%p\n",
+				dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
+			    memcpy(dele->key, dictkey->getCStringNoCopy(),
+				dele->key_size);
+			    dele->value = dele->key + dele->key_size;
+			    primitive_type_collect(dele, dictvalue);
+			    dstrtab += dele->key_size + dele->value_size;
+			    DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
+			}
+			else {
+			    continue;	/* Only handle primitive types here.  */
+			}
+			dents++;
+		    }
+		    dictIterator->release();
+		    if (dents == 0)
+			continue;
+		    arrayhd->type = MAC_DATA_TYPE_DICT;
+		    ele->value_size = sizeof(struct mac_module_data_list) +
+			(dents - 1) * sizeof(struct mac_module_data_element);
+		    DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
+		    dicttab += ele->value_size;
+		    DPRINTF(("osdict: new dicttab %p\n", dicttab));
+		    dicthd->count = dents;
+		    astrtab = dstrtab;
+		}
+		else {
+		    continue;		/* Skip everything else.              */
+		}
+		nents++;
+		ele++;
 	    }
-	} else if (typeID == OSTypeID(OSData)) {
-	    OSData * dataObj = OSDynamicCast(OSData, value);
-	    element->value_size = dataObj->getLength();
-	    memcpy(element->value, dataObj->getBytesNoCopy(),
-		element->value_size);
-	} else {
+	    if (nents == 0)
+		continue;
+	    element->value_size = sizeof(struct mac_module_data_list) +
+		(nents - 1) * sizeof(struct mac_module_data_element);
+	    listtab += element->value_size;
+	    DPRINTF(("osdict: new listtab %p\n", listtab));
+	    arrayhd->count = nents;
+	    strtab = astrtab;
+	    DPRINTF(("osdict: new strtab %p\n", strtab));
+	}
+	else {
 	    continue;		/* skip anything else */
 	}
-
-	strtab += element->key_size + element->value_size;
 	element++;
     }
+    DPRINTF(("module_data list @%p, key %p value %p\n",
+	module_data, module_data->data[0].key, module_data->data[0].value));
 finish:
     if (keyIterator)
 	keyIterator->release();
@@ -273,7 +524,7 @@
      */
     vm_map_copyin(kernel_map, (vm_offset_t)module_data, *datalen, FALSE, &copy);
     kmem_free(kernel_map, (vm_offset_t)module_data, *datalen);
-
+    DPRINTF(("get_module_data: copy @ %p\n", copy));
 finish:
     return (kmod_args_t)copy;
 }

==== //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac.h#10 (text+ko) ====

@@ -70,8 +70,9 @@
 /*
  * Device types for mac_iokit_check_device()
  */
-#define MAC_DEVICE_USB		0
-#define MAC_DEVICE_FIREWIRE	1
+#define MAC_DEVICE_USB		"USB"
+#define MAC_DEVICE_FIREWIRE	"FireWire"
+#define MAC_DEVICE_TYPE_KEY	"DeviceType"
 
 #ifndef KERNEL
 /*
@@ -117,7 +118,7 @@
  * I/O Kit device access control.
  * Note that this routine is called from a C++ I/O Kit driver.
  */
-int	mac_iokit_check_device(int devtype, struct module_data *mdata);
+int	mac_iokit_check_device(char *devtype, struct module_data *mdata);
 __END_DECLS
 #endif
 

==== //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_base.c#23 (text+ko) ====

@@ -69,6 +69,18 @@
 #include <osfmk/kern/kalloc.h>
 #include <libsa/libsa/kext.h>
 
+/* 
+ * define MB_DEBUG to display run-time debugging information
+ * #define MB_DEBUG 1
+ */
+
+#ifdef MB_DEBUG
+#define DPRINTF(x)	printf x
+#else
+#define MB_DEBUG
+#define DPRINTF(x)
+#endif
+
 SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW, 0, 
     "Security Controls");
 SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
@@ -671,6 +683,44 @@
 	}
 }
 
+static __inline void
+mac_policy_fixup_mmd_list(struct mac_module_data *new)
+{
+	struct mac_module_data *old;
+	struct mac_module_data_element *ele, *aele, *dele;
+	struct mac_module_data_list *arr, *dict;
+	unsigned int i, j, k;
+
+	old = new->base_addr;
+	DPRINTF(("fixup_mmd: old %p new %p\n", old, new));
+	for (i = 0; i < new->count; i++) {
+		ele = &(new->data[i]);
+		DPRINTF(("fixup_mmd: ele %p\n", ele));
+		DPRINTF(("   key %p value %p\n", ele->key, ele->value));
+		mmd_fixup_ele(old, new, ele); /* Fix up key/value ptrs.       */
+		DPRINTF(("   key %p value %p\n", ele->key, ele->value));
+		if (ele->value_type == MAC_DATA_TYPE_ARRAY) {
+			arr = (struct mac_module_data_list *)ele->value;
+			DPRINTF(("fixup_mmd: array @%p\n", arr));
+			for (j = 0; j < arr->count; j++) {
+				aele = &(arr->list[j]);
+				DPRINTF(("fixup_mmd: aele %p\n", aele));
+				DPRINTF(("   key %p value %p\n", aele->key, aele->value));
+				mmd_fixup_ele(old, new, aele);
+				DPRINTF(("   key %p value %p\n", aele->key, aele->value));
+				if (arr->type == MAC_DATA_TYPE_DICT) {
+					dict = (struct mac_module_data_list *)aele->value;
+					DPRINTF(("fixup_mmd: dict @%p\n", dict));
+					for (k = 0; k < dict->count; k++)
+						mmd_fixup_ele(old, new,
+						    &(dict->list[k]));
+				}
+			}
+		}
+	}
+	new->base_addr = new;
+}
+
 int
 mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
     void *xd)
@@ -766,22 +816,14 @@
 
 	if (xd) {
 		struct mac_module_data *mmd = xd; /* module data from plist */
-		char *strtab;
 
 		/* Make a copy of the data. */
 		mpc->mpc_data = (void *)kalloc(mmd->size);
 		if (mpc->mpc_data != NULL) {
 			memcpy(mpc->mpc_data, mmd, mmd->size);
-			mmd = mpc->mpc_data;
 
-			/* Fix up pointers into string table after copy. */
-			strtab = (char *)&mmd->data[mmd->count];
-			for (i = 0; i < mmd->count; i++) {
-				mmd->data[i].key = strtab;
-				strtab += mmd->data[i].key_size;
-				mmd->data[i].value = strtab;
-				strtab += mmd->data[i].value_size;
-			}
+			/* Fix up pointers after copy. */
+			mac_policy_fixup_mmd_list(mpc->mpc_data);
 		}
 	}
 

==== //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_data.h#4 (text+ko) ====

@@ -33,7 +33,11 @@
   This structure specifies module data that is passed in to the
   TrustedBSD MAC policy module by the kernel module loader.  The
   data is made of up key/value pairs where the key is always a
-  string and the value is either a string or binary data.
+  string and the value is a string, binary data or array.  An array
+  may be a list of values (actually a similar set of key/value pairs,
+  but in this case the keys are always null), and may also consist of
+  a set of dictionaries, which in turn are made up of a list of key/value
+  pairs.
 
   Module data may be specified in the MAC policy module's
   Info.plist file as part of the OSModuleData dictionary.
@@ -41,30 +45,74 @@
   E.g.
 
   <key>OSModuleData</key>
+  <dict>
+	<key>foo</key>
+	<string>bar</string>
+	<key>Beers</key>
+	<array>
 	<dict>
-		<key>foo</key>
-		<string>bar</string>
+		<key>type</key>
+		<string>lager</string>
+		<key>Name</key>
+		<string>Anchor Steam</string>
+	</dict>
+	<dict>
+		<key>type</key>
+		<string>ale</string>
+		<key>Name</key>
+		<string>Sierra Nevada Pale Ale</string>
 	</dict>
+	</array>
+  </dict>
 
 */
 struct mac_module_data_element {
 	unsigned int key_size;
 	unsigned int value_size;
+	unsigned int value_type;
 	char *key;
 	char *value;
 };
+struct mac_module_data_list {
+	unsigned int count;
+	unsigned int type;
+	struct mac_module_data_element list[1];
+};
 struct mac_module_data {
+	void *base_addr;		/* Orig base address, for ptr fixup.  */
 	unsigned int size;
 	unsigned int count;
 	struct mac_module_data_element data[1];	/* actually bigger */
 };
 
+#define MAC_DATA_TYPE_PRIMITIVE	0	/* Primitive type (int, string, etc.) */
+#define MAC_DATA_TYPE_ARRAY	1	/* Array type.                        */
+#define MAC_DATA_TYPE_DICT	2	/* Dictionary type.                   */
+
 #ifdef _SECURITY_MAC_POLICY_H_
 /* XXX mac_policy_handle_t is defined in mac_policy.h, move prototype there? */
 int mac_find_policy_data(const mac_policy_handle_t, const char *key,
     void **valp, size_t *sizep);
 int mac_find_module_data(struct mac_module_data *mmd, const char *key,
     void **valp, size_t *sizep);
+
+/*
+ * This is a routine to fix up pointers in a mac_module_data_element when the
+ * mac_module_data has been copied to a new area.  It depends on the pointers
+ * all being offset from base_addr.
+ */
+static __inline void
+mmd_fixup_ele(struct mac_module_data *oldbase,
+    struct mac_module_data *newbase, struct mac_module_data_element *ele)
+{
+	if (ele->key != NULL) {		/* Array elements have no keys.       */
+		ele->key -= (unsigned int)oldbase;
+		ele->key += (unsigned int)newbase;
+	}
+	ele->value -= (unsigned int)oldbase;
+	ele->value += (unsigned int)newbase;
+}
+
 #endif
 
 #endif /* !_SECURITY_MAC_DATA_H_ */

==== //depot/projects/trustedbsd/sedarwin8/darwin/xnu/security/mac_iokit.c#2 (text+ko) ====

@@ -37,7 +37,7 @@
 #include <kern/kalloc.h>
 
 int
-mac_iokit_check_device(int devtype, struct module_data *mdata)
+mac_iokit_check_device(char *devtype, struct module_data *mdata)
 {
 	int error;
 

==== //depot/projects/trustedbsd/sedarwin8/policies/device_access/mac_device_access.c#5 (text+ko) ====

@@ -36,7 +36,6 @@
  * define DA_DEBUG to display run-time debugging information
  * #define DA_DEBUG 1
  */
-#define DA_DEBUG 1
 
 #ifdef DA_DEBUG
 #define DA_TRACE printf("In %s\n", __FUNCTION__)
@@ -48,85 +47,7 @@
 
 #define MAC_DEVACCESS_POLICY_NAME		"device_access"
 
-struct keyvals {
-	unsigned int	ksize;
-	const char	*k;
-	unsigned int	vsize;
-	const char	*v;
-};
-struct allowed_devs {
-	int		type;		/* Device type.                       */
-	unsigned int	nprops;		/* Number of properties.              */
-	struct keyvals	props[2];
-};
-static struct allowed_devs devlist[] = {
-	{ MAC_DEVICE_USB, 2, {		/* Apple Extended USB Keyboard        */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "516" }		/* 0x0204 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Extended USB Keyboard        */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "517" }		/* 0x0205 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Extended USB Keyboard        */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "523" }		/* 0x020b */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Extended USB Keyboard        */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "524" }		/* 0x020c */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Optical USB Mouse            */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "770" }		/* 0x0302 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Optical USB Mouse            */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "772" }		/* 0x0304 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Apple Optical USB Mouse            */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 4, "774" }		/* 0x0306 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* OHCI Root Hub Simulation           */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 6, "32773" }	/* 0x8005 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Hub in Apple Extended USB Keyboard */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 5, "4098" }	/* 0x1002 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Hub in Apple Extended USB Keyboard */
-		{ 9, "VendorID", 5, "1452" },		/* 0x05ac */
-		{ 12, "ModelNumber", 5, "4099" }	/* 0x1003 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* Texas Instruments Hub              */
-		{ 9, "VendorID", 5, "1105" },		/* 0x0451 */
-		{ 12, "ModelNumber", 5, "8262" }	/* 0x2046 */
-		}
-	},
-	{ MAC_DEVICE_USB, 2, {		/* MachKey Intl USB KVM Switch        */
-		{ 9, "VendorID", 5, "1778" },		/* 0x06f2 */
-		{ 12, "ModelNumber", 4, "123" }		/* 0x007b */
-		}
-	},
-	{ MAC_DEVICE_FIREWIRE, 2, {	/* Apple laptop.                      */
-		{ 9, "VendorID", 5, "2599" },
-		{ 12, "ModelNumber", 3, "10" }
-		}
-	}
-};
-static unsigned int devlist_ents = sizeof(devlist) / sizeof(struct allowed_devs);
+static struct mac_module_data *device_access_list = NULL;
 
 /*
  * SYSCTL entry points
@@ -145,8 +66,15 @@
 device_access_policy_init(struct mac_policy_conf *mpc) 
 {
 	DA_TRACE;
+	if (device_access_list == NULL && mpc->mpc_data != NULL) {
+		device_access_list = mpc->mpc_data;
+		DPRINTF(("device_access list @%p, key %p value %p\n",
+			device_access_list, device_access_list->data[0].key,
+			device_access_list->data[0].value));
+	}
 	printf("MAC Device Access policy is initialized\n");
-	DPRINTF(("	%sabled\n", mac_device_access_enabled ? "En" : "Dis"));
+	DPRINTF(("	%sabled, device_access_list @%p\n",
+	    mac_device_access_enabled ? "En" : "Dis", device_access_list));
 }
 
 static void
@@ -160,49 +88,102 @@
 device_access_policy_initbsd(struct mac_policy_conf *mpc) 
 {
 	DA_TRACE;
+	if (device_access_list == NULL && mpc->mpc_data != NULL)
+		device_access_list = mpc->mpc_data;
 	sysctl_register_oid(&sysctl__security_mac_device_access);
 	sysctl_register_oid(&sysctl__security_mac_device_access_enabled);
 }
 
+/*
+ * Compare a device access dictionary entry against the device properties.
+ * Return true if a matching key exists in the properties with a matching
+ * value.
+ */
 static int
-dev_match(struct mac_module_data *mdata, struct keyvals *props)
+dev_match(struct mac_module_data *props, struct mac_module_data_element *ele)
 {
 	unsigned int k;
 	int kmatch = 0;
 
-	for (k = 0; k < mdata->count; k++) {
-		if (mdata->data[k].key_size != props->ksize)
+	for (k = 0; k < props->count; k++) {
+		if (props->data[k].key_size != ele->key_size)
 			continue;
-		if (!strncmp(mdata->data[k].key, props->k, props->ksize) &&
-		    !bcmp(mdata->data[k].value, props->v, props->vsize))
+		if (!strncmp(props->data[k].key, ele->key, ele->key_size) &&
+		    props->data[k].value_size == ele->value_size &&
+		    !bcmp(props->data[k].value, ele->value, ele->value_size))
 			kmatch++;
 	}
 	return(kmatch);
 }
 
 static int
-device_access_iokit_check_device(int devtype, struct mac_module_data *mdata)
+device_access_iokit_check_device(char *devtype, struct mac_module_data *mdata)
 {
+	struct mac_module_data_list *dict, *list;
 	unsigned int matches;
 	unsigned int i, j;
 
 	DA_TRACE;
-	if (!mac_device_access_enabled)
+	if (!mac_device_access_enabled || device_access_list == NULL)
+		return(0);
+	/*
+	 * The module data should have one entry, an array of dicts.  Each
+	 * dict is itself an array of key/value pairs that describe an
+	 * allowed device.
+	 */
+	if (device_access_list->data[0].value_type != MAC_DATA_TYPE_ARRAY)
+		return(0);
+	list = (struct mac_module_data_list *)device_access_list->data[0].value;
+	/*
+	 * If it's not an array of <dict>, somebody messed up and it's
+	 * unusable.
+	 */
+	if (list->type != MAC_DATA_TYPE_DICT)
 		return(0);
 	/*
-	 * Go through our list of allowed devices.  If all the properties of
-	 * one of our listed devices match corresponding properties in the
-	 * passed device properties, the device is allowed.
+	 * Go through the list of dictionaries and compare each one to the
+	 * passed device property list.  If all the entries of a dictionary
+	 * match corresponding properties in the passed property list, the
+	 * device is allowed.
 	 */
-	for (i = 0; i < devlist_ents; i++) {
-		if (devlist[i].type != devtype) /* Skip if the wrong type.    */
-			continue;
-		matches = 0;
-		for (j = 0; j < devlist[i].nprops; j++) {
-			if (dev_match(mdata, &(devlist[i].props[j])) > 0)
-				matches++; /* Key matched.                    */
+	for (i = 0; i < list->count; i++) {
+		dict = (struct mac_module_data_list *)list->list[i].value;
+		/*
+		 * If this dictionary doesn't match the device type, skip it.
+		 */
+		for (j = 0; j < dict->count; j++) {
+			unsigned int keylen, vallen;
+
+			keylen = strlen(MAC_DEVICE_TYPE_KEY) + 1;
+			vallen = strlen(devtype) + 1;
+			if (dict->list[j].key_size != keylen ||
+			    strncmp(dict->list[j].key, MAC_DEVICE_TYPE_KEY, keylen))
+				continue; /* Key mismatch, next key.          */
+			if (vallen == dict->list[j].value_size &&
+			    !bcmp(devtype, dict->list[j].value, vallen))
+				break;	/* Match.                             */
+		}
+		if (j == dict->count)	/* Key found and matched?             */
+			continue;	/* No, go to next dictionary.         */
+		/*
+		 * Compare all the dictionary entries against the device
+		 * property list.  If they all match, the device is allowed.
+		 */
+		matches = 1;		/* We've already matched devtype.     */
+		for (j = 0; j < dict->count; j++) {
+			/*
+			 * If there's a "Name" entry in the dict, it always
+			 * matches.
+			 */
+			if (dict->list[j].key_size == strlen("Name")+1 &&
+			    !strncmp(dict->list[j].key, "Name", strlen("Name"))) {
+				matches++;
+				continue;
+			}
+			if (dev_match(mdata, &(dict->list[j])) > 0)
+				matches++; /* Entry matched.                  */
 		}
-		if (matches == devlist[i].nprops)
+		if (matches == dict->count)
 			return(0);
 	}
 	return(EPERM);


More information about the p4-projects mailing list