DF-2449 / fix.diff
diff --git a/sys/dev/disk/dm/dm_ioctl.c b/sys/dev/disk/dm/dm_ioctl.c --- a/sys/dev/disk/dm/dm_ioctl.c +++ b/sys/dev/disk/dm/dm_ioctl.c @@ -741,16 +741,31 @@ return ENOENT; } if ((table_en = kmalloc(sizeof(dm_table_entry_t), - M_DM, M_WAITOK)) == NULL) { + M_DM, M_WAITOK | M_ZERO)) == NULL) { dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); dm_dev_unbusy(dmv); dm_target_unbusy(target); return ENOMEM; } - prop_dictionary_get_uint64(target_dict, DM_TABLE_START, - &table_en->start); - prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, - &table_en->length); + /* + * Require start/length to be present in the per-table-entry dict. + * prop_dictionary_get_uint64() returns false without writing *valp + * when the key is absent, which would otherwise leave the field at + * whatever stale slab bytes kmalloc returned (the M_DM kmalloc above + * is not M_ZERO before this change). M_ZERO on the kmalloc also + * guarantees the whole struct starts zeroed for any future field + * whose initialization is missed here. DF-2449. + */ + if (!prop_dictionary_get_uint64(target_dict, DM_TABLE_START, + &table_en->start) || + !prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, + &table_en->length)) { + kfree(table_en, M_DM); + dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); + dm_dev_unbusy(dmv); + dm_target_unbusy(target); + return EINVAL; + } dmdebug("table_en->start = %ju, table_en->length = %ju\n", (uintmax_t)table_en->start, |