diff options
-rw-r--r-- | drivers/md/dm-ioctl.c | 23 | ||||
-rw-r--r-- | include/linux/dm-ioctl.h | 12 |
2 files changed, 30 insertions, 5 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3a8f6a0e6eb5..4cacdad2270a 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1504,6 +1504,7 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1504 | 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) |
1505 | { | 1505 | { |
1506 | struct dm_ioctl tmp, *dmi; | 1506 | struct dm_ioctl tmp, *dmi; |
1507 | int secure_data; | ||
1507 | 1508 | ||
1508 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) | 1509 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) |
1509 | return -EFAULT; | 1510 | return -EFAULT; |
@@ -1511,17 +1512,28 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1511 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) | 1512 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) |
1512 | return -EINVAL; | 1513 | return -EINVAL; |
1513 | 1514 | ||
1515 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | ||
1516 | |||
1514 | dmi = vmalloc(tmp.data_size); | 1517 | dmi = vmalloc(tmp.data_size); |
1515 | if (!dmi) | 1518 | if (!dmi) { |
1519 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1520 | return -EFAULT; | ||
1516 | return -ENOMEM; | 1521 | return -ENOMEM; |
1522 | } | ||
1517 | 1523 | ||
1518 | if (copy_from_user(dmi, user, tmp.data_size)) | 1524 | if (copy_from_user(dmi, user, tmp.data_size)) |
1519 | goto bad; | 1525 | goto bad; |
1520 | 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 | |||
1521 | *param = dmi; | 1531 | *param = dmi; |
1522 | return 0; | 1532 | return 0; |
1523 | 1533 | ||
1524 | bad: | 1534 | bad: |
1535 | if (secure_data) | ||
1536 | memset(dmi, 0, tmp.data_size); | ||
1525 | vfree(dmi); | 1537 | vfree(dmi); |
1526 | return -EFAULT; | 1538 | return -EFAULT; |
1527 | } | 1539 | } |
@@ -1531,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1531 | /* Always clear this flag */ | 1543 | /* Always clear this flag */ |
1532 | param->flags &= ~DM_BUFFER_FULL_FLAG; | 1544 | param->flags &= ~DM_BUFFER_FULL_FLAG; |
1533 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; | 1545 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; |
1546 | param->flags &= ~DM_SECURE_DATA_FLAG; | ||
1534 | 1547 | ||
1535 | /* Ignores parameters */ | 1548 | /* Ignores parameters */ |
1536 | if (cmd == DM_REMOVE_ALL_CMD || | 1549 | if (cmd == DM_REMOVE_ALL_CMD || |
@@ -1558,6 +1571,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1558 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1571 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1559 | { | 1572 | { |
1560 | int r = 0; | 1573 | int r = 0; |
1574 | int wipe_buffer; | ||
1561 | unsigned int cmd; | 1575 | unsigned int cmd; |
1562 | struct dm_ioctl *uninitialized_var(param); | 1576 | struct dm_ioctl *uninitialized_var(param); |
1563 | ioctl_fn fn = NULL; | 1577 | ioctl_fn fn = NULL; |
@@ -1602,13 +1616,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1602 | * Copy the parameters into kernel space. | 1616 | * Copy the parameters into kernel space. |
1603 | */ | 1617 | */ |
1604 | r = copy_params(user, ¶m); | 1618 | r = copy_params(user, ¶m); |
1605 | input_param_size = param->data_size; | ||
1606 | 1619 | ||
1607 | current->flags &= ~PF_MEMALLOC; | 1620 | current->flags &= ~PF_MEMALLOC; |
1608 | 1621 | ||
1609 | if (r) | 1622 | if (r) |
1610 | return r; | 1623 | return r; |
1611 | 1624 | ||
1625 | input_param_size = param->data_size; | ||
1626 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1627 | |||
1612 | r = validate_params(cmd, param); | 1628 | r = validate_params(cmd, param); |
1613 | if (r) | 1629 | if (r) |
1614 | goto out; | 1630 | goto out; |
@@ -1623,6 +1639,9 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1623 | r = -EFAULT; | 1639 | r = -EFAULT; |
1624 | 1640 | ||
1625 | out: | 1641 | out: |
1642 | if (wipe_buffer) | ||
1643 | memset(param, 0, input_param_size); | ||
1644 | |||
1626 | vfree(param); | 1645 | vfree(param); |
1627 | return r; | 1646 | return r; |
1628 | } | 1647 | } |
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 78bbf47bbb96..3708455ee6c3 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h | |||
@@ -267,9 +267,9 @@ enum { | |||
267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | 267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) |
268 | 268 | ||
269 | #define DM_VERSION_MAJOR 4 | 269 | #define DM_VERSION_MAJOR 4 |
270 | #define DM_VERSION_MINOR 19 | 270 | #define DM_VERSION_MINOR 20 |
271 | #define DM_VERSION_PATCHLEVEL 1 | 271 | #define DM_VERSION_PATCHLEVEL 0 |
272 | #define DM_VERSION_EXTRA "-ioctl (2011-01-07)" | 272 | #define DM_VERSION_EXTRA "-ioctl (2011-02-02)" |
273 | 273 | ||
274 | /* Status bits */ | 274 | /* Status bits */ |
275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |
@@ -328,4 +328,10 @@ enum { | |||
328 | */ | 328 | */ |
329 | #define DM_UUID_FLAG (1 << 14) /* In */ | 329 | #define DM_UUID_FLAG (1 << 14) /* In */ |
330 | 330 | ||
331 | /* | ||
332 | * If set, all buffers are wiped after use. Use when sending | ||
333 | * or requesting sensitive data such as an encryption key. | ||
334 | */ | ||
335 | #define DM_SECURE_DATA_FLAG (1 << 15) /* In */ | ||
336 | |||
331 | #endif /* _LINUX_DM_IOCTL_H */ | 337 | #endif /* _LINUX_DM_IOCTL_H */ |