+++ /dev/null
-From 62e082430ea4bb5b28909ca4375bb683931e22aa Mon Sep 17 00:00:00 2001
-From: Mikulas Patocka <mpatocka@redhat.com>
-Date: Wed, 20 Sep 2017 07:29:49 -0400
-Subject: dm ioctl: fix alignment of event number in the device list
-
-From: Mikulas Patocka <mpatocka@redhat.com>
-
-commit 62e082430ea4bb5b28909ca4375bb683931e22aa upstream.
-
-The size of struct dm_name_list is different on 32-bit and 64-bit
-kernels (so "(nl + 1)" differs between 32-bit and 64-bit kernels).
-
-This mismatch caused some harmless difference in padding when using 32-bit
-or 64-bit kernel. Commit 23d70c5e52dd ("dm ioctl: report event number in
-DM_LIST_DEVICES") added reporting event number in the output of
-DM_LIST_DEVICES_CMD. This difference in padding makes it impossible for
-userspace to determine the location of the event number (the location
-would be different when running on 32-bit and 64-bit kernels).
-
-Fix the padding by using offsetof(struct dm_name_list, name) instead of
-sizeof(struct dm_name_list) to determine the location of entries.
-
-Also, the ioctl version number is incremented to 37 so that userspace
-can use the version number to determine that the event number is present
-and correctly located.
-
-In addition, a global event is now raised when a DM device is created,
-removed, renamed or when table is swapped, so that the user can monitor
-for device changes.
-
-Reported-by: Eugene Syromiatnikov <esyr@redhat.com>
-Fixes: 23d70c5e52dd ("dm ioctl: report event number in DM_LIST_DEVICES")
-Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
-Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
-diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
-index 24eddbdf2ab4..203144762f36 100644
---- a/drivers/md/dm-core.h
-+++ b/drivers/md/dm-core.h
-@@ -149,5 +149,6 @@ static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen
-
- extern atomic_t dm_global_event_nr;
- extern wait_queue_head_t dm_global_eventq;
-+void dm_issue_global_event(void);
-
- #endif
-diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
-index 8756a6850431..e52676fa9832 100644
---- a/drivers/md/dm-ioctl.c
-+++ b/drivers/md/dm-ioctl.c
-@@ -477,9 +477,13 @@ static int remove_all(struct file *filp, struct dm_ioctl *param, size_t param_si
- * Round up the ptr to an 8-byte boundary.
- */
- #define ALIGN_MASK 7
-+static inline size_t align_val(size_t val)
-+{
-+ return (val + ALIGN_MASK) & ~ALIGN_MASK;
-+}
- static inline void *align_ptr(void *ptr)
- {
-- return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK);
-+ return (void *)align_val((size_t)ptr);
- }
-
- /*
-@@ -505,7 +509,7 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
- struct hash_cell *hc;
- size_t len, needed = 0;
- struct gendisk *disk;
-- struct dm_name_list *nl, *old_nl = NULL;
-+ struct dm_name_list *orig_nl, *nl, *old_nl = NULL;
- uint32_t *event_nr;
-
- down_write(&_hash_lock);
-@@ -516,17 +520,15 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
- */
- for (i = 0; i < NUM_BUCKETS; i++) {
- list_for_each_entry (hc, _name_buckets + i, name_list) {
-- needed += sizeof(struct dm_name_list);
-- needed += strlen(hc->name) + 1;
-- needed += ALIGN_MASK;
-- needed += (sizeof(uint32_t) + ALIGN_MASK) & ~ALIGN_MASK;
-+ needed += align_val(offsetof(struct dm_name_list, name) + strlen(hc->name) + 1);
-+ needed += align_val(sizeof(uint32_t));
- }
- }
-
- /*
- * Grab our output buffer.
- */
-- nl = get_result_buffer(param, param_size, &len);
-+ nl = orig_nl = get_result_buffer(param, param_size, &len);
- if (len < needed) {
- param->flags |= DM_BUFFER_FULL_FLAG;
- goto out;
-@@ -549,11 +551,16 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
- strcpy(nl->name, hc->name);
-
- old_nl = nl;
-- event_nr = align_ptr(((void *) (nl + 1)) + strlen(hc->name) + 1);
-+ event_nr = align_ptr(nl->name + strlen(hc->name) + 1);
- *event_nr = dm_get_event_nr(hc->md);
- nl = align_ptr(event_nr + 1);
- }
- }
-+ /*
-+ * If mismatch happens, security may be compromised due to buffer
-+ * overflow, so it's better to crash.
-+ */
-+ BUG_ON((char *)nl - (char *)orig_nl != needed);
-
- out:
- up_write(&_hash_lock);
-@@ -1621,7 +1628,8 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para
- * which has a variable size, is not used by the function processing
- * the ioctl.
- */
--#define IOCTL_FLAGS_NO_PARAMS 1
-+#define IOCTL_FLAGS_NO_PARAMS 1
-+#define IOCTL_FLAGS_ISSUE_GLOBAL_EVENT 2
-
- /*-----------------------------------------------------------------
- * Implementation of open/close/ioctl on the special char
-@@ -1635,12 +1643,12 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
- ioctl_fn fn;
- } _ioctls[] = {
- {DM_VERSION_CMD, 0, NULL}, /* version is dealt with elsewhere */
-- {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS, remove_all},
-+ {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, remove_all},
- {DM_LIST_DEVICES_CMD, 0, list_devices},
-
-- {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_create},
-- {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_remove},
-- {DM_DEV_RENAME_CMD, 0, dev_rename},
-+ {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_create},
-+ {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_remove},
-+ {DM_DEV_RENAME_CMD, IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_rename},
- {DM_DEV_SUSPEND_CMD, IOCTL_FLAGS_NO_PARAMS, dev_suspend},
- {DM_DEV_STATUS_CMD, IOCTL_FLAGS_NO_PARAMS, dev_status},
- {DM_DEV_WAIT_CMD, 0, dev_wait},
-@@ -1869,6 +1877,9 @@ static int ctl_ioctl(struct file *file, uint command, struct dm_ioctl __user *us
- unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS))
- DMERR("ioctl %d tried to output some data but has IOCTL_FLAGS_NO_PARAMS set", cmd);
-
-+ if (!r && ioctl_flags & IOCTL_FLAGS_ISSUE_GLOBAL_EVENT)
-+ dm_issue_global_event();
-+
- /*
- * Copy the results back to userland.
- */
-diff --git a/drivers/md/dm.c b/drivers/md/dm.c
-index 6e54145969c5..4be85324f44d 100644
---- a/drivers/md/dm.c
-+++ b/drivers/md/dm.c
-@@ -52,6 +52,12 @@ static struct workqueue_struct *deferred_remove_workqueue;
- atomic_t dm_global_event_nr = ATOMIC_INIT(0);
- DECLARE_WAIT_QUEUE_HEAD(dm_global_eventq);
-
-+void dm_issue_global_event(void)
-+{
-+ atomic_inc(&dm_global_event_nr);
-+ wake_up(&dm_global_eventq);
-+}
-+
- /*
- * One of these is allocated per bio.
- */
-@@ -1865,9 +1871,8 @@ static void event_callback(void *context)
- dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj);
-
- atomic_inc(&md->event_nr);
-- atomic_inc(&dm_global_event_nr);
- wake_up(&md->eventq);
-- wake_up(&dm_global_eventq);
-+ dm_issue_global_event();
- }
-
- /*
-@@ -2283,6 +2288,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
- }
-
- map = __bind(md, table, &limits);
-+ dm_issue_global_event();
-
- out:
- mutex_unlock(&md->suspend_lock);
-diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h
-index 412c06a624c8..ccaea525340b 100644
---- a/include/uapi/linux/dm-ioctl.h
-+++ b/include/uapi/linux/dm-ioctl.h
-@@ -269,9 +269,9 @@ enum {
- #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
-
- #define DM_VERSION_MAJOR 4
--#define DM_VERSION_MINOR 36
-+#define DM_VERSION_MINOR 37
- #define DM_VERSION_PATCHLEVEL 0
--#define DM_VERSION_EXTRA "-ioctl (2017-06-09)"
-+#define DM_VERSION_EXTRA "-ioctl (2017-09-20)"
-
- /* Status bits */
- #define DM_READONLY_FLAG (1 << 0) /* In/Out */