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);