diff options
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 6d12775a106..4cacdad2270 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1501,14 +1501,10 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1501 | return r; | 1501 | return r; |
1502 | } | 1502 | } |
1503 | 1503 | ||
1504 | static void free_params(struct dm_ioctl *param) | ||
1505 | { | ||
1506 | vfree(param); | ||
1507 | } | ||
1508 | |||
1509 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | 1504 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) |
1510 | { | 1505 | { |
1511 | struct dm_ioctl tmp, *dmi; | 1506 | struct dm_ioctl tmp, *dmi; |
1507 | int secure_data; | ||
1512 | 1508 | ||
1513 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) | 1509 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) |
1514 | return -EFAULT; | 1510 | return -EFAULT; |
@@ -1516,17 +1512,30 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1516 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) | 1512 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) |
1517 | return -EINVAL; | 1513 | return -EINVAL; |
1518 | 1514 | ||
1515 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | ||
1516 | |||
1519 | dmi = vmalloc(tmp.data_size); | 1517 | dmi = vmalloc(tmp.data_size); |
1520 | if (!dmi) | 1518 | if (!dmi) { |
1519 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1520 | return -EFAULT; | ||
1521 | return -ENOMEM; | 1521 | return -ENOMEM; |
1522 | |||
1523 | if (copy_from_user(dmi, user, tmp.data_size)) { | ||
1524 | vfree(dmi); | ||
1525 | return -EFAULT; | ||
1526 | } | 1522 | } |
1527 | 1523 | ||
1524 | if (copy_from_user(dmi, user, tmp.data_size)) | ||
1525 | goto bad; | ||
1526 | |||
1527 | /* Wipe the user buffer so we do not return it to userspace */ | ||
1528 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1529 | goto bad; | ||
1530 | |||
1528 | *param = dmi; | 1531 | *param = dmi; |
1529 | return 0; | 1532 | return 0; |
1533 | |||
1534 | bad: | ||
1535 | if (secure_data) | ||
1536 | memset(dmi, 0, tmp.data_size); | ||
1537 | vfree(dmi); | ||
1538 | return -EFAULT; | ||
1530 | } | 1539 | } |
1531 | 1540 | ||
1532 | static int validate_params(uint cmd, struct dm_ioctl *param) | 1541 | static int validate_params(uint cmd, struct dm_ioctl *param) |
@@ -1534,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1534 | /* Always clear this flag */ | 1543 | /* Always clear this flag */ |
1535 | param->flags &= ~DM_BUFFER_FULL_FLAG; | 1544 | param->flags &= ~DM_BUFFER_FULL_FLAG; |
1536 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; | 1545 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; |
1546 | param->flags &= ~DM_SECURE_DATA_FLAG; | ||
1537 | 1547 | ||
1538 | /* Ignores parameters */ | 1548 | /* Ignores parameters */ |
1539 | if (cmd == DM_REMOVE_ALL_CMD || | 1549 | if (cmd == DM_REMOVE_ALL_CMD || |
@@ -1561,10 +1571,11 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1561 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1571 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1562 | { | 1572 | { |
1563 | int r = 0; | 1573 | int r = 0; |
1574 | int wipe_buffer; | ||
1564 | unsigned int cmd; | 1575 | unsigned int cmd; |
1565 | struct dm_ioctl *uninitialized_var(param); | 1576 | struct dm_ioctl *uninitialized_var(param); |
1566 | ioctl_fn fn = NULL; | 1577 | ioctl_fn fn = NULL; |
1567 | size_t param_size; | 1578 | size_t input_param_size; |
1568 | 1579 | ||
1569 | /* only root can play with this */ | 1580 | /* only root can play with this */ |
1570 | if (!capable(CAP_SYS_ADMIN)) | 1581 | if (!capable(CAP_SYS_ADMIN)) |
@@ -1611,13 +1622,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1611 | if (r) | 1622 | if (r) |
1612 | return r; | 1623 | return r; |
1613 | 1624 | ||
1625 | input_param_size = param->data_size; | ||
1626 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1627 | |||
1614 | r = validate_params(cmd, param); | 1628 | r = validate_params(cmd, param); |
1615 | if (r) | 1629 | if (r) |
1616 | goto out; | 1630 | goto out; |
1617 | 1631 | ||
1618 | param_size = param->data_size; | ||
1619 | param->data_size = sizeof(*param); | 1632 | param->data_size = sizeof(*param); |
1620 | r = fn(param, param_size); | 1633 | r = fn(param, input_param_size); |
1621 | 1634 | ||
1622 | /* | 1635 | /* |
1623 | * Copy the results back to userland. | 1636 | * Copy the results back to userland. |
@@ -1625,8 +1638,11 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1625 | if (!r && copy_to_user(user, param, param->data_size)) | 1638 | if (!r && copy_to_user(user, param, param->data_size)) |
1626 | r = -EFAULT; | 1639 | r = -EFAULT; |
1627 | 1640 | ||
1628 | out: | 1641 | out: |
1629 | free_params(param); | 1642 | if (wipe_buffer) |
1643 | memset(param, 0, input_param_size); | ||
1644 | |||
1645 | vfree(param); | ||
1630 | return r; | 1646 | return r; |
1631 | } | 1647 | } |
1632 | 1648 | ||