DragonFlyBSD Kernel Audit
DF-2922 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/vfs_quota.c b/sys/kern/vfs_quota.c
index 70103ed..146bbd8 100644
--- a/sys/kern/vfs_quota.c
+++ b/sys/kern/vfs_quota.c
@@ -218,6 +218,15 @@ cmd_get_usage_all(struct mount *mp, prop_array_t dict_out)
 static int
 cmd_set_usage_all(struct mount *mp, prop_array_t args)
 {
+	/*
+	 * DF-2922: "arguments" comes straight from userspace via
+	 * prop_dictionary_copyin() and can be ANY proplib object type.
+	 * prop_array_iterator() locks the object at the pa_rwlock offset
+	 * as if it were an array BEFORE type-checking it, corrupting
+	 * memory / panicking / livelocking for non-array objects.
+	 */
+	if (args == NULL || prop_object_type(args) != PROP_TYPE_ARRAY)
+		return (EINVAL);
 	struct ac_unode ufind, *unp;
 	struct ac_gnode gfind, *gnp;
 	prop_dictionary_t item;
@@ -246,6 +255,11 @@ cmd_set_usage_all(struct mount *mp, prop_array_t args)
 		return 1;
 	}
 	while ((item = prop_object_iterator_next(iter)) != NULL) {
+		/* DF-2922: elements can be any type.
+		 * DF-2925: never store uninitialized stack values */
+		space = 0;
+		if (item == NULL || prop_object_type(item) != PROP_TYPE_DICTIONARY)
+			continue;
 		prop_dictionary_get_uint64(item, "space used", &space);
 		if (prop_dictionary_get_uint32(item, "uid", &id)) {
 			ufind.left_bits = (id >> ACCT_CHUNK_BITS);
@@ -274,6 +288,10 @@ cmd_set_limit(struct mount *mp, prop_dictionary_t args)
 {
 	uint64_t limit;
 
+	/* DF-2922 / DF-2925: validate type; never store stack garbage */
+	if (args == NULL || prop_object_type(args) != PROP_TYPE_DICTIONARY)
+		return (EINVAL);
+	limit = 0;
 	prop_dictionary_get_uint64(args, "limit", &limit);
 
 	spin_lock(&mp->mnt_acct.ac_spin);
@@ -290,6 +308,10 @@ cmd_set_limit_uid(struct mount *mp, prop_dictionary_t args)
 	uid_t uid;
 	struct ac_unode ufind, *unp;
 
+	/* DF-2922 / DF-2925: validate type; never store stack garbage */
+	if (args == NULL || prop_object_type(args) != PROP_TYPE_DICTIONARY)
+		return (EINVAL);
+	limit = 0;
 	prop_dictionary_get_uint32(args, "uid", &uid);
 	prop_dictionary_get_uint64(args, "limit", &limit);
 
@@ -311,6 +333,10 @@ cmd_set_limit_gid(struct mount *mp, prop_dictionary_t args)
 	gid_t gid;
 	struct ac_gnode gfind, *gnp;
 
+	/* DF-2922 / DF-2925: validate type; never store stack garbage */
+	if (args == NULL || prop_object_type(args) != PROP_TYPE_DICTIONARY)
+		return (EINVAL);
+	limit = 0;
 	prop_dictionary_get_uint32(args, "gid", &gid);
 	prop_dictionary_get_uint64(args, "limit", &limit);