diff options
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 37 |
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 |
480 | static inline size_t align_val(size_t val) | ||
481 | { | ||
482 | return (val + ALIGN_MASK) & ~ALIGN_MASK; | ||
483 | } | ||
480 | static inline void *align_ptr(void *ptr) | 484 | static 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 | */ |