diff options
-rw-r--r-- | drivers/md/dm-ioctl.c | 45 |
1 files changed, 32 insertions, 13 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index a37aeba7dc1b..0666b5d14b88 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1543,7 +1543,21 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1543 | return r; | 1543 | return r; |
1544 | } | 1544 | } |
1545 | 1545 | ||
1546 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | 1546 | #define DM_PARAMS_VMALLOC 0x0001 /* Params alloced with vmalloc not kmalloc */ |
1547 | #define DM_WIPE_BUFFER 0x0010 /* Wipe input buffer before returning from ioctl */ | ||
1548 | |||
1549 | static void free_params(struct dm_ioctl *param, size_t param_size, int param_flags) | ||
1550 | { | ||
1551 | if (param_flags & DM_WIPE_BUFFER) | ||
1552 | memset(param, 0, param_size); | ||
1553 | |||
1554 | if (param_flags & DM_PARAMS_VMALLOC) | ||
1555 | vfree(param); | ||
1556 | else | ||
1557 | kfree(param); | ||
1558 | } | ||
1559 | |||
1560 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param, int *param_flags) | ||
1547 | { | 1561 | { |
1548 | struct dm_ioctl tmp, *dmi; | 1562 | struct dm_ioctl tmp, *dmi; |
1549 | int secure_data; | 1563 | int secure_data; |
@@ -1556,10 +1570,21 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1556 | 1570 | ||
1557 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | 1571 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; |
1558 | 1572 | ||
1573 | *param_flags = secure_data ? DM_WIPE_BUFFER : 0; | ||
1574 | |||
1559 | /* | 1575 | /* |
1560 | * Try to avoid low memory issues when a device is suspended. | 1576 | * Try to avoid low memory issues when a device is suspended. |
1577 | * Use kmalloc() rather than vmalloc() when we can. | ||
1561 | */ | 1578 | */ |
1562 | dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL); | 1579 | dmi = NULL; |
1580 | if (tmp.data_size <= KMALLOC_MAX_SIZE) | ||
1581 | dmi = kmalloc(tmp.data_size, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); | ||
1582 | |||
1583 | if (!dmi) { | ||
1584 | dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL); | ||
1585 | *param_flags |= DM_PARAMS_VMALLOC; | ||
1586 | } | ||
1587 | |||
1563 | if (!dmi) { | 1588 | if (!dmi) { |
1564 | if (secure_data && clear_user(user, tmp.data_size)) | 1589 | if (secure_data && clear_user(user, tmp.data_size)) |
1565 | return -EFAULT; | 1590 | return -EFAULT; |
@@ -1585,9 +1610,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1585 | return 0; | 1610 | return 0; |
1586 | 1611 | ||
1587 | bad: | 1612 | bad: |
1588 | if (secure_data) | 1613 | free_params(dmi, tmp.data_size, *param_flags); |
1589 | memset(dmi, 0, tmp.data_size); | 1614 | |
1590 | vfree(dmi); | ||
1591 | return -EFAULT; | 1615 | return -EFAULT; |
1592 | } | 1616 | } |
1593 | 1617 | ||
@@ -1624,7 +1648,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1624 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1648 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1625 | { | 1649 | { |
1626 | int r = 0; | 1650 | int r = 0; |
1627 | int wipe_buffer; | 1651 | int param_flags; |
1628 | unsigned int cmd; | 1652 | unsigned int cmd; |
1629 | struct dm_ioctl *uninitialized_var(param); | 1653 | struct dm_ioctl *uninitialized_var(param); |
1630 | ioctl_fn fn = NULL; | 1654 | ioctl_fn fn = NULL; |
@@ -1662,14 +1686,12 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1662 | /* | 1686 | /* |
1663 | * Copy the parameters into kernel space. | 1687 | * Copy the parameters into kernel space. |
1664 | */ | 1688 | */ |
1665 | r = copy_params(user, ¶m); | 1689 | r = copy_params(user, ¶m, ¶m_flags); |
1666 | 1690 | ||
1667 | if (r) | 1691 | if (r) |
1668 | return r; | 1692 | return r; |
1669 | 1693 | ||
1670 | input_param_size = param->data_size; | 1694 | input_param_size = param->data_size; |
1671 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1672 | |||
1673 | r = validate_params(cmd, param); | 1695 | r = validate_params(cmd, param); |
1674 | if (r) | 1696 | if (r) |
1675 | goto out; | 1697 | goto out; |
@@ -1684,10 +1706,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1684 | r = -EFAULT; | 1706 | r = -EFAULT; |
1685 | 1707 | ||
1686 | out: | 1708 | out: |
1687 | if (wipe_buffer) | 1709 | free_params(param, input_param_size, param_flags); |
1688 | memset(param, 0, input_param_size); | ||
1689 | |||
1690 | vfree(param); | ||
1691 | return r; | 1710 | return r; |
1692 | } | 1711 | } |
1693 | 1712 | ||