* character, so that they don't interfere with the construction of key-value pairs,
* and clients can split the key1=val1,key2=val2,key3=val3; pairs properly.
*/
-static void fix_separator_chars(char **buf)
+static void fix_separator_chars(char *buf)
{
- int l = strlen(*buf);
+ int l = strlen(buf);
int i, j, sp = 0;
for (i = 0; i < l; i++)
- if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=' || (*buf)[i] == ',')
+ if (buf[i] == '\\' || buf[i] == ';' || buf[i] == '=' || buf[i] == ',')
sp++;
if (!sp)
return;
+ buf[l + sp] = '\0';
for (i = l-1, j = i+sp; i >= 0; i--) {
- (*buf)[j--] = (*buf)[i];
- if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=' || (*buf)[i] == ',')
- (*buf)[j--] = '\\';
+ buf[j--] = buf[i];
+ if (buf[i] == '\\' || buf[i] == ';' || buf[i] == '=' || buf[i] == ',')
+ buf[j--] = '\\';
}
}
+static void fix_context_strings(struct dm_ima_context *context)
+{
+ fix_separator_chars(context->dev_name);
+ fix_separator_chars(context->dev_uuid);
+}
+
/*
* Internal function to allocate memory for IMA measurements.
*/
return ptr;
}
+void dm_ima_init(struct mapped_device *md)
+{
+ md->ima.update_idx = 0;
+ md->ima.measure_idx = 0;
+ init_waitqueue_head(&md->ima.ima_wq);
+ spin_lock_init(&md->ima.ima_lock);
+}
+
+void dm_ima_alloc_context(struct dm_ima_context **context, bool noio)
+{
+ *context = dm_ima_alloc(sizeof(struct dm_ima_context), noio);
+}
+
+void dm_ima_free_context(struct dm_ima_context *context)
+{
+ if (likely(context)) {
+ kfree(context->table.device_metadata);
+ kfree(context->table.hash);
+ kfree(context);
+ }
+}
+
+static void wait_to_measure(struct dm_ima_measurements *ima,
+ unsigned int update_idx)
+{
+ spin_lock_irq(&ima->ima_lock);
+ wait_event_lock_irq(ima->ima_wq,
+ ima->measure_idx == update_idx,
+ ima->ima_lock);
+ spin_unlock_irq(&ima->ima_lock);
+}
+
+static void wake_next_measure(struct dm_ima_measurements *ima)
+{
+ spin_lock_irq(&ima->ima_lock);
+ ima->measure_idx++;
+ spin_unlock_irq(&ima->ima_lock);
+ wake_up_all(&ima->ima_wq);
+}
+
/*
- * Internal function to allocate and copy name and uuid for IMA measurements.
+ * Helper function for swapping the table, to make sure that the
+ * correct table metadata is saved and restored.
*/
-static int dm_ima_alloc_and_copy_name_uuid(struct mapped_device *md, char **dev_name,
- char **dev_uuid, bool noio)
+void dm_ima_context_table_op(struct mapped_device *md,
+ struct dm_ima_context *context,
+ enum dm_ima_table_op op)
{
- int r;
- *dev_name = dm_ima_alloc(DM_NAME_LEN*2, noio);
- if (!(*dev_name)) {
- r = -ENOMEM;
- goto error;
- }
+ struct dm_ima_measurements *ima = &md->ima;
- *dev_uuid = dm_ima_alloc(DM_UUID_LEN*2, noio);
- if (!(*dev_uuid)) {
- r = -ENOMEM;
- goto error;
- }
+ if (unlikely(!context))
+ return;
- r = dm_copy_name_and_uuid(md, *dev_name, *dev_uuid);
- if (r)
- goto error;
+ wait_to_measure(ima, context->update_idx);
- fix_separator_chars(dev_name);
- fix_separator_chars(dev_uuid);
+ if (op == DM_IMA_TABLE_SAVE) {
+ context->table = ima->inactive_table;
+ memset(&ima->inactive_table, 0, sizeof(ima->inactive_table));
+ } else {
+ ima->inactive_table = context->table;
+ memset(&context->table, 0, sizeof(context->table));
+ }
- return 0;
-error:
- kfree(*dev_name);
- kfree(*dev_uuid);
- *dev_name = NULL;
- *dev_uuid = NULL;
- return r;
+ wake_next_measure(ima);
}
/*
* Internal function to allocate and copy device data for IMA measurements.
*/
static int dm_ima_alloc_and_copy_device_data(struct mapped_device *md, char **device_data,
+ struct dm_ima_context *context,
unsigned int num_targets, bool noio)
{
- char *dev_name = NULL, *dev_uuid = NULL;
- int r;
-
- r = dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio);
- if (r)
- return r;
-
*device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
- if (!(*device_data)) {
- r = -ENOMEM;
- goto error;
- }
+ if (!(*device_data))
+ return -ENOMEM;
scnprintf(*device_data, DM_IMA_DEVICE_BUF_LEN,
"name=%s,uuid=%s,major=%d,minor=%d,minor_count=%d,num_targets=%u;",
- dev_name, dev_uuid, md->disk->major, md->disk->first_minor,
- md->disk->minors, num_targets);
-error:
- kfree(dev_name);
- kfree(dev_uuid);
- return r;
+ context->dev_name, context->dev_uuid, md->disk->major,
+ md->disk->first_minor, md->disk->minors, num_targets);
+
+ return 0;
}
/*
/*
* Build up the IMA data for each target, and finally measure.
*/
-void dm_ima_measure_on_table_load(struct dm_table *table)
+void dm_ima_measure_on_table_load(struct dm_table *table,
+ struct dm_ima_context *context)
{
size_t device_data_buf_len, target_metadata_buf_len, target_data_buf_len, l = 0;
char *target_metadata_buf = NULL, *target_data_buf = NULL, *digest_buf = NULL;
bool noio = false;
char table_load_event_name[] = "dm_table_load";
+ if (unlikely(!context))
+ return;
+
+ wait_to_measure(&table->md->ima, context->update_idx);
+
ima_buf = dm_ima_alloc(DM_IMA_MEASUREMENT_BUF_LEN, noio);
if (!ima_buf)
- return;
+ goto error;
target_metadata_buf = dm_ima_alloc(DM_IMA_TARGET_METADATA_BUF_LEN, noio);
if (!target_metadata_buf)
num_targets = table->num_targets;
- if (dm_ima_alloc_and_copy_device_data(table->md, &device_data_buf, num_targets, noio))
+ fix_context_strings(context);
+ if (dm_ima_alloc_and_copy_device_data(table->md, &device_data_buf,
+ context, num_targets, noio))
goto error;
sha256_init(&hash_ctx);
kfree(ima_buf);
kfree(target_metadata_buf);
kfree(target_data_buf);
+
+ wake_next_measure(&table->md->ima);
}
/*
* Measure IMA data on device resume.
*/
-void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
+void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
+ struct dm_ima_context *context)
{
- char *device_table_data, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL;
+ char *device_table_data = NULL, *capacity_str = NULL;
char active[] = "active_table_hash=";
unsigned int active_len = strlen(active);
unsigned int l = 0;
bool nodata = true;
int capacity_len;
+ if (unlikely(!context))
+ return;
+
+ wait_to_measure(&md->ima, context->update_idx);
+
device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
if (!device_table_data)
- return;
+ goto error;
capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
if (capacity_len < 0)
if (swap) {
kfree(md->ima.active_table.hash);
kfree(md->ima.active_table.device_metadata);
- memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
-
- if (md->ima.inactive_table.hash) {
- md->ima.active_table.hash = md->ima.inactive_table.hash;
- md->ima.active_table.hash_len = md->ima.inactive_table.hash_len;
- md->ima.inactive_table.hash = NULL;
- md->ima.inactive_table.hash_len = 0;
- }
-
- if (md->ima.inactive_table.device_metadata) {
- md->ima.active_table.device_metadata =
- md->ima.inactive_table.device_metadata;
- md->ima.active_table.device_metadata_len =
- md->ima.inactive_table.device_metadata_len;
- md->ima.active_table.num_targets = md->ima.inactive_table.num_targets;
- md->ima.inactive_table.device_metadata = NULL;
- md->ima.inactive_table.device_metadata_len = 0;
- md->ima.inactive_table.num_targets = 0;
- }
+ md->ima.active_table = context->table;
+ memset(&context->table, 0, sizeof(context->table));
}
if (md->ima.active_table.device_metadata) {
}
if (nodata) {
- if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio))
- goto error;
-
+ fix_context_strings(context);
l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
"%sname=%s,uuid=%s;device_resume=no_data;",
- DM_IMA_VERSION_STR, dev_name, dev_uuid);
+ DM_IMA_VERSION_STR, context->dev_name,
+ context->dev_uuid);
}
memcpy(device_table_data + l, capacity_str, capacity_len);
dm_ima_measure_data("dm_device_resume", device_table_data, l, noio);
- kfree(dev_name);
- kfree(dev_uuid);
error:
kfree(capacity_str);
kfree(device_table_data);
+
+ wake_next_measure(&md->ima);
}
/*
* Measure IMA data on remove.
*/
-void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all)
+void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
+ struct dm_ima_context *context,
+ unsigned int idx)
{
- char *device_table_data, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL;
+ char *device_table_data, *capacity_str = NULL;
char active_table_str[] = "active_table_hash=";
char inactive_table_str[] = "inactive_table_hash=";
char device_active_str[] = "device_active_metadata=";
bool nodata = true;
int capacity_len;
+ wait_to_measure(&md->ima, idx);
+
+ if (unlikely(!context))
+ goto exit;
+
device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN*2, noio);
if (!device_table_data)
goto exit;
* in IMA measurements.
*/
if (nodata) {
- if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio))
- goto error;
-
+ fix_context_strings(context);
l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
"%sname=%s,uuid=%s;device_remove=no_data;",
- DM_IMA_VERSION_STR, dev_name, dev_uuid);
+ DM_IMA_VERSION_STR, context->dev_name,
+ context->dev_uuid);
}
memcpy(device_table_data + l, remove_all_str, remove_all_len);
dm_ima_measure_data("dm_device_remove", device_table_data, l, noio);
-error:
kfree(device_table_data);
kfree(capacity_str);
exit:
memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
- kfree(dev_name);
- kfree(dev_uuid);
+ wake_next_measure(&md->ima);
}
/*
* Measure ima data on table clear.
*/
-void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map)
+void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map,
+ struct dm_ima_context *context)
{
unsigned int l = 0;
- char *device_table_data = NULL, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL;
+ char *device_table_data = NULL, *capacity_str = NULL;
char inactive_str[] = "inactive_table_hash=";
unsigned int inactive_len = strlen(inactive_str);
bool noio = true;
bool nodata = true;
int capacity_len;
+ if (unlikely(!context))
+ return;
+
+ wait_to_measure(&md->ima, context->update_idx);
+
device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
if (!device_table_data)
- return;
+ goto error;
capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
if (capacity_len < 0)
- goto error1;
+ goto error;
memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
l += strlen(DM_IMA_VERSION_STR);
}
if (nodata) {
- if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio))
- goto error2;
-
+ fix_context_strings(context);
l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
"%sname=%s,uuid=%s;table_clear=no_data;",
- DM_IMA_VERSION_STR, dev_name, dev_uuid);
+ DM_IMA_VERSION_STR, context->dev_name,
+ context->dev_uuid);
}
memcpy(device_table_data + l, capacity_str, capacity_len);
memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
}
- kfree(dev_name);
- kfree(dev_uuid);
-error2:
+error:
kfree(capacity_str);
-error1:
kfree(device_table_data);
+
+ wake_next_measure(&md->ima);
}
/*
* Measure IMA data on device rename.
*/
-void dm_ima_measure_on_device_rename(struct mapped_device *md)
+void dm_ima_measure_on_device_rename(struct mapped_device *md,
+ struct dm_ima_context *context)
{
- char *old_device_data = NULL, *new_device_data = NULL, *combined_device_data = NULL;
- char *new_dev_name = NULL, *new_dev_uuid = NULL, *capacity_str = NULL;
+ char *old_device_data = NULL, *new_device_data = NULL;
+ char *combined_device_data = NULL, *capacity_str = NULL;
bool noio = true;
int len;
- if (dm_ima_alloc_and_copy_device_data(md, &new_device_data,
- md->ima.active_table.num_targets, noio))
+ if (unlikely(!context))
return;
- if (dm_ima_alloc_and_copy_name_uuid(md, &new_dev_name, &new_dev_uuid, noio))
+ wait_to_measure(&md->ima, context->update_idx);
+
+ fix_context_strings(context);
+ if (dm_ima_alloc_and_copy_device_data(md, &new_device_data, context,
+ md->ima.active_table.num_targets,
+ noio))
goto error;
combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, noio);
len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2,
"%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data,
- new_dev_name, new_dev_uuid, capacity_str);
+ context->dev_name, context->dev_uuid, capacity_str);
dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
kfree(capacity_str);
kfree(combined_device_data);
kfree(old_device_data);
- kfree(new_dev_name);
- kfree(new_dev_uuid);
+
+ wake_next_measure(&md->ima);
}
__dm_ima_str(DM_VERSION_MINOR) "." \
__dm_ima_str(DM_VERSION_PATCHLEVEL) ";"
+enum dm_ima_table_op {
+ DM_IMA_TABLE_SAVE,
+ DM_IMA_TABLE_RESTORE,
+};
+
#ifdef CONFIG_IMA
struct dm_ima_device_table_metadata {
unsigned int hash_len;
};
+struct dm_ima_context {
+ struct dm_ima_device_table_metadata table;
+ unsigned int update_idx;
+ char dev_name[DM_NAME_LEN*2];
+ char dev_uuid[DM_UUID_LEN*2];
+};
+
/*
* This structure contains device metadata, and table hash for
* active and inactive tables for ima measurements.
*/
struct dm_ima_measurements {
+ unsigned int update_idx;
+ unsigned int measure_idx;
+ struct wait_queue_head ima_wq;
+ spinlock_t ima_lock;
struct dm_ima_device_table_metadata active_table;
struct dm_ima_device_table_metadata inactive_table;
};
-void dm_ima_measure_on_table_load(struct dm_table *table);
-void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap);
-void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all);
-void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map);
-void dm_ima_measure_on_device_rename(struct mapped_device *md);
+void dm_ima_init(struct mapped_device *md);
+void dm_ima_alloc_context(struct dm_ima_context **context, bool noio);
+void dm_ima_free_context(struct dm_ima_context *context);
+void dm_ima_context_table_op(struct mapped_device *md,
+ struct dm_ima_context *context,
+ enum dm_ima_table_op op);
+void dm_ima_measure_on_table_load(struct dm_table *table,
+ struct dm_ima_context *context);
+void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
+ struct dm_ima_context *context);
+void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
+ struct dm_ima_context *context,
+ unsigned int idx);
+void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map,
+ struct dm_ima_context *context);
+void dm_ima_measure_on_device_rename(struct mapped_device *md,
+ struct dm_ima_context *context);
#else
-static inline void dm_ima_measure_on_table_load(struct dm_table *table) {}
-static inline void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) {}
-static inline void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) {}
-static inline void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) {}
-static inline void dm_ima_measure_on_device_rename(struct mapped_device *md) {}
+struct dm_ima_context;
+
+static inline void dm_ima_init(struct mapped_device *md) {}
+static inline void dm_ima_alloc_context(struct dm_ima_context **context, bool noio) {}
+static inline void dm_ima_free_context(struct dm_ima_context *context) {}
+static inline void dm_ima_context_table_op(struct mapped_device *md,
+ struct dm_ima_context *context,
+ enum dm_ima_table_op op) {}
+static inline void dm_ima_measure_on_table_load(struct dm_table *table,
+ struct dm_ima_context *context) {}
+static inline void dm_ima_measure_on_device_resume(struct mapped_device *md,
+ bool swap,
+ struct dm_ima_context *context) {}
+static inline void dm_ima_measure_on_device_remove(struct mapped_device *md,
+ bool remove_all,
+ struct dm_ima_context *context,
+ unsigned int idx) {}
+static inline void dm_ima_measure_on_table_clear(struct mapped_device *md,
+ bool new_map,
+ struct dm_ima_context *context) {}
+static inline void dm_ima_measure_on_device_rename(struct mapped_device *md,
+ struct dm_ima_context *context) {}
#endif /* CONFIG_IMA */
}
}
+#ifdef CONFIG_IMA
+
+/*
+ * Called while holding to _hash_lock, to guarantee the ordering of the
+ * following dm_ima_measure_on_* functions, which should be called
+ * right after dropping the _hash_lock
+ */
+static unsigned int dm_ima_init_context(struct hash_cell *hc,
+ struct dm_ima_context *context,
+ bool need_idx)
+{
+ lockdep_assert_held(&_hash_lock);
+
+ if (unlikely(!context))
+ return need_idx ? hc->md->ima.update_idx++ : 0;
+
+ context->update_idx = hc->md->ima.update_idx++;
+ strcpy(context->dev_name, hc->name);
+ strcpy(context->dev_uuid, hc->uuid ? : "");
+
+ return context->update_idx;
+}
+
+/*
+ * Called by do_resume() to guarantee correct ordering, since do_resume()
+ * does not grab the _hash_lock when the table is not getting swapped or
+ * when actually swapping the active table
+ */
+static bool dm_ima_need_measure(struct mapped_device *md,
+ struct dm_table *table,
+ struct dm_ima_context *context)
+{
+ int srcu_idx;
+ struct hash_cell *hc;
+ bool need_measure = false;
+
+ if (unlikely(!context))
+ return false;
+
+ down_write(&_hash_lock);
+ /* Check if the device has been removed */
+ hc = dm_get_mdptr(md);
+ if (hc) {
+ /*
+ * If we have a table, we need to make sure that it's the
+ * active table. Otherwise we raced with another process
+ * setting the active table and it will do the measurement
+ */
+ if (!table || dm_get_live_table(md, &srcu_idx) == table) {
+ dm_ima_init_context(hc, context, false);
+ need_measure = true;
+ }
+ if (table)
+ dm_put_live_table(md, srcu_idx);
+ }
+ up_write(&_hash_lock);
+
+ return need_measure;
+}
+#else
+static inline unsigned int dm_ima_init_context(struct hash_cell *hc,
+ struct dm_ima_context *context,
+ bool neex_idx)
+{
+ return 0;
+}
+static inline bool dm_ima_need_measure(struct mapped_device *md,
+ struct dm_table *table,
+ struct dm_ima_context *context)
+{
+ return false;
+}
+#endif
+
/*
* The kdev_t and uuid of a device can never change once it is
* initially inserted.
struct hash_cell *hc;
struct mapped_device *md;
struct dm_table *t;
+ struct dm_ima_context *ima_context = NULL;
+ unsigned int ima_idx;
+ dm_ima_alloc_context(&ima_context, true);
retry:
dev_skipped = 0;
for (n = rb_first(&name_rb_tree); n; n = rb_next(n)) {
if (flags & DM_REMOVE_INTERRUPTIBLE && fatal_signal_pending(current)) {
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
return -EINTR;
}
continue;
}
+ ima_idx = dm_ima_init_context(hc, ima_context, true);
t = __hash_remove(hc);
up_write(&_hash_lock);
dm_sync_table(md);
dm_table_destroy(t);
}
- dm_ima_measure_on_device_remove(md, true);
+ dm_ima_measure_on_device_remove(md, true, ima_context, ima_idx);
dm_put(md);
if (likely(flags & DM_REMOVE_KEEP_OPEN_DEVICES))
dm_destroy(md);
if (dev_skipped && !(flags & DM_REMOVE_ONLY_DEFERRED))
DMWARN("remove_all left %d open device(s)", dev_skipped);
+ dm_ima_free_context(ima_context);
return 0;
}
struct mapped_device *md;
unsigned int change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
int srcu_idx;
+ struct dm_ima_context *ima_context = NULL;
/*
* duplicate new.
if (!new_data)
return ERR_PTR(-ENOMEM);
+ dm_ima_alloc_context(&ima_context, true);
down_write(&_hash_lock);
/*
param->name, new);
dm_put(hc->md);
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
kfree(new_data);
return ERR_PTR(-EBUSY);
}
DMERR("Unable to rename non-existent device, %s to %s%s",
param->name, change_uuid ? "uuid " : "", new);
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
kfree(new_data);
return ERR_PTR(-ENXIO);
}
param->name, new, hc->uuid);
dm_put(hc->md);
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
kfree(new_data);
return ERR_PTR(-EINVAL);
}
md = hc->md;
- dm_ima_measure_on_device_rename(md);
+ dm_ima_init_context(hc, ima_context, false);
up_write(&_hash_lock);
+ dm_ima_measure_on_device_rename(md, ima_context);
+ dm_ima_free_context(ima_context);
kfree(old_name);
return md;
struct mapped_device *md;
int r;
struct dm_table *t;
+ struct dm_ima_context *ima_context = NULL;
+ unsigned int ima_idx;
+ dm_ima_alloc_context(&ima_context, true);
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
if (!hc) {
DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
return -ENXIO;
}
if (r == -EBUSY && param->flags & DM_DEFERRED_REMOVE) {
up_write(&_hash_lock);
dm_put(md);
+ dm_ima_free_context(ima_context);
return 0;
}
DMDEBUG_LIMIT("unable to remove open device %s", hc->name);
up_write(&_hash_lock);
dm_put(md);
+ dm_ima_free_context(ima_context);
return r;
}
+ ima_idx = dm_ima_init_context(hc, ima_context, true);
t = __hash_remove(hc);
up_write(&_hash_lock);
param->flags &= ~DM_DEFERRED_REMOVE;
- dm_ima_measure_on_device_remove(md, false);
+ dm_ima_measure_on_device_remove(md, false, ima_context, ima_idx);
+ dm_ima_free_context(ima_context);
if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr, false))
param->flags |= DM_UEVENT_GENERATED_FLAG;
struct mapped_device *md;
struct dm_table *new_map, *old_map = NULL;
bool need_resize_uevent = false;
+ struct dm_ima_context *ima_context = NULL;
+ dm_ima_alloc_context(&ima_context, true);
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
if (!hc) {
DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
return -ENXIO;
}
new_map = hc->new_map;
hc->new_map = NULL;
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
+ if (new_map)
+ dm_ima_init_context(hc, ima_context, false);
up_write(&_hash_lock);
/* Do we need to load a new map ? */
if (new_map) {
sector_t old_size, new_size;
+ dm_ima_context_table_op(md, ima_context, DM_IMA_TABLE_SAVE);
/* Suspend if it isn't already suspended */
if (param->flags & DM_SKIP_LOCKFS_FLAG)
suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
if (hc && !hc->new_map) {
hc->new_map = new_map;
new_map = NULL;
+ dm_ima_init_context(hc, ima_context,
+ false);
} else {
r = -ENXIO;
}
if (new_map) {
dm_sync_table(md);
dm_table_destroy(new_map);
- }
+ } else
+ dm_ima_context_table_op(md, ima_context, DM_IMA_TABLE_RESTORE);
+ dm_ima_free_context(ima_context);
dm_put(md);
return r;
}
if (IS_ERR(old_map)) {
dm_sync_table(md);
dm_table_destroy(new_map);
+ dm_ima_free_context(ima_context);
dm_put(md);
return PTR_ERR(old_map);
}
+ if (dm_ima_need_measure(md, new_map, ima_context))
+ dm_ima_measure_on_device_resume(md, true, ima_context);
new_size = dm_get_size(md);
if (old_size && new_size && old_size != new_size)
need_resize_uevent = true;
if (dm_suspended_md(md)) {
r = dm_resume(md);
if (!r) {
- dm_ima_measure_on_device_resume(md, new_map ? true : false);
+ if (!new_map && dm_ima_need_measure(md, NULL,
+ ima_context))
+ dm_ima_measure_on_device_resume(md, false,
+ ima_context);
if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr, need_resize_uevent))
param->flags |= DM_UEVENT_GENERATED_FLAG;
if (!r)
__dev_status(md, param);
+ dm_ima_free_context(ima_context);
dm_put(md);
return r;
}
static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
- int r;
+ int r, srcu_idx;
struct hash_cell *hc;
struct dm_table *t, *old_map = NULL;
struct mapped_device *md;
struct target_type *immutable_target_type;
+ struct dm_ima_context *ima_context = NULL;
md = find_device(param);
if (!md)
if (r)
goto err_unlock_md_type;
- dm_ima_measure_on_table_load(t);
-
immutable_target_type = dm_get_immutable_target_type(md);
if (immutable_target_type &&
(immutable_target_type != dm_table_get_immutable_target_type(t)) &&
dm_unlock_md_type(md);
+ dm_ima_alloc_context(&ima_context, false);
/* stage inactive table */
down_write(&_hash_lock);
hc = dm_get_mdptr(md);
if (!hc) {
DMERR("device has been removed from the dev hash table.");
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
r = -ENXIO;
goto err_destroy_table;
}
if (hc->new_map)
old_map = hc->new_map;
hc->new_map = t;
+ dm_ima_init_context(hc, ima_context, false);
+ /* Make sure new_map doesn't get freed before we measure it*/
+ dm_get_live_table(md, &srcu_idx);
up_write(&_hash_lock);
+ dm_ima_measure_on_table_load(t, ima_context);
+ dm_ima_free_context(ima_context);
+ dm_put_live_table(md, srcu_idx);
+
param->flags |= DM_INACTIVE_PRESENT_FLAG;
__dev_status(md, param);
struct mapped_device *md;
struct dm_table *old_map = NULL;
bool has_new_map = false;
+ struct dm_ima_context *ima_context = NULL;
+ dm_ima_alloc_context(&ima_context, true);
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
if (!hc) {
DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
+ dm_ima_free_context(ima_context);
return -ENXIO;
}
has_new_map = true;
}
+ dm_ima_init_context(hc, ima_context, false);
md = hc->md;
up_write(&_hash_lock);
+ dm_ima_measure_on_table_clear(md, has_new_map, ima_context);
+ dm_ima_free_context(ima_context);
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
__dev_status(md, param);
dm_sync_table(md);
dm_table_destroy(old_map);
}
- dm_ima_measure_on_table_clear(md, has_new_map);
dm_put(md);
return 0;