aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-ioctl.c23
-rw-r--r--include/linux/dm-ioctl.h12
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)
1504static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) 1504static 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
1524bad: 1534bad:
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)
1558static int ctl_ioctl(uint command, struct dm_ioctl __user *user) 1571static 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, &param); 1618 r = copy_params(user, &param);
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
1625out: 1641out:
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 */