aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r--drivers/md/dm-ioctl.c37
1 files changed, 24 insertions, 13 deletions
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
477 * Round up the ptr to an 8-byte boundary. 477 * Round up the ptr to an 8-byte boundary.
478 */ 478 */
479#define ALIGN_MASK 7 479#define ALIGN_MASK 7
480static inline size_t align_val(size_t val)
481{
482 return (val + ALIGN_MASK) & ~ALIGN_MASK;
483}
480static inline void *align_ptr(void *ptr) 484static inline void *align_ptr(void *ptr)
481{ 485{
482 return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); 486 return (void *)align_val((size_t)ptr);
483} 487}
484 488
485/* 489/*
@@ -505,7 +509,7 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
505 struct hash_cell *hc; 509 struct hash_cell *hc;
506 size_t len, needed = 0; 510 size_t len, needed = 0;
507 struct gendisk *disk; 511 struct gendisk *disk;
508 struct dm_name_list *nl, *old_nl = NULL; 512 struct dm_name_list *orig_nl, *nl, *old_nl = NULL;
509 uint32_t *event_nr; 513 uint32_t *event_nr;
510 514
511 down_write(&_hash_lock); 515 down_write(&_hash_lock);
@@ -516,17 +520,15 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
516 */ 520 */
517 for (i = 0; i < NUM_BUCKETS; i++) { 521 for (i = 0; i < NUM_BUCKETS; i++) {
518 list_for_each_entry (hc, _name_buckets + i, name_list) { 522 list_for_each_entry (hc, _name_buckets + i, name_list) {
519 needed += sizeof(struct dm_name_list); 523 needed += align_val(offsetof(struct dm_name_list, name) + strlen(hc->name) + 1);
520 needed += strlen(hc->name) + 1; 524 needed += align_val(sizeof(uint32_t));
521 needed += ALIGN_MASK;
522 needed += (sizeof(uint32_t) + ALIGN_MASK) & ~ALIGN_MASK;
523 } 525 }
524 } 526 }
525 527
526 /* 528 /*
527 * Grab our output buffer. 529 * Grab our output buffer.
528 */ 530 */
529 nl = get_result_buffer(param, param_size, &len); 531 nl = orig_nl = get_result_buffer(param, param_size, &len);
530 if (len < needed) { 532 if (len < needed) {
531 param->flags |= DM_BUFFER_FULL_FLAG; 533 param->flags |= DM_BUFFER_FULL_FLAG;
532 goto out; 534 goto out;
@@ -549,11 +551,16 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
549 strcpy(nl->name, hc->name); 551 strcpy(nl->name, hc->name);
550 552
551 old_nl = nl; 553 old_nl = nl;
552 event_nr = align_ptr(((void *) (nl + 1)) + strlen(hc->name) + 1); 554 event_nr = align_ptr(nl->name + strlen(hc->name) + 1);
553 *event_nr = dm_get_event_nr(hc->md); 555 *event_nr = dm_get_event_nr(hc->md);
554 nl = align_ptr(event_nr + 1); 556 nl = align_ptr(event_nr + 1);
555 } 557 }
556 } 558 }
559 /*
560 * If mismatch happens, security may be compromised due to buffer
561 * overflow, so it's better to crash.
562 */
563 BUG_ON((char *)nl - (char *)orig_nl != needed);
557 564
558 out: 565 out:
559 up_write(&_hash_lock); 566 up_write(&_hash_lock);
@@ -1621,7 +1628,8 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para
1621 * which has a variable size, is not used by the function processing 1628 * which has a variable size, is not used by the function processing
1622 * the ioctl. 1629 * the ioctl.
1623 */ 1630 */
1624#define IOCTL_FLAGS_NO_PARAMS 1 1631#define IOCTL_FLAGS_NO_PARAMS 1
1632#define IOCTL_FLAGS_ISSUE_GLOBAL_EVENT 2
1625 1633
1626/*----------------------------------------------------------------- 1634/*-----------------------------------------------------------------
1627 * Implementation of open/close/ioctl on the special char 1635 * Implementation of open/close/ioctl on the special char
@@ -1635,12 +1643,12 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
1635 ioctl_fn fn; 1643 ioctl_fn fn;
1636 } _ioctls[] = { 1644 } _ioctls[] = {
1637 {DM_VERSION_CMD, 0, NULL}, /* version is dealt with elsewhere */ 1645 {DM_VERSION_CMD, 0, NULL}, /* version is dealt with elsewhere */
1638 {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS, remove_all}, 1646 {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, remove_all},
1639 {DM_LIST_DEVICES_CMD, 0, list_devices}, 1647 {DM_LIST_DEVICES_CMD, 0, list_devices},
1640 1648
1641 {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_create}, 1649 {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_create},
1642 {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_remove}, 1650 {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_remove},
1643 {DM_DEV_RENAME_CMD, 0, dev_rename}, 1651 {DM_DEV_RENAME_CMD, IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_rename},
1644 {DM_DEV_SUSPEND_CMD, IOCTL_FLAGS_NO_PARAMS, dev_suspend}, 1652 {DM_DEV_SUSPEND_CMD, IOCTL_FLAGS_NO_PARAMS, dev_suspend},
1645 {DM_DEV_STATUS_CMD, IOCTL_FLAGS_NO_PARAMS, dev_status}, 1653 {DM_DEV_STATUS_CMD, IOCTL_FLAGS_NO_PARAMS, dev_status},
1646 {DM_DEV_WAIT_CMD, 0, dev_wait}, 1654 {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
1869 unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS)) 1877 unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS))
1870 DMERR("ioctl %d tried to output some data but has IOCTL_FLAGS_NO_PARAMS set", cmd); 1878 DMERR("ioctl %d tried to output some data but has IOCTL_FLAGS_NO_PARAMS set", cmd);
1871 1879
1880 if (!r && ioctl_flags & IOCTL_FLAGS_ISSUE_GLOBAL_EVENT)
1881 dm_issue_global_event();
1882
1872 /* 1883 /*
1873 * Copy the results back to userland. 1884 * Copy the results back to userland.
1874 */ 1885 */