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 | ||
