dm ioctl: add flag to wipe buffers for secure data

Add DM_SECURE_DATA_FLAG which userspace can use to ensure
that all buffers allocated for dm-ioctl are wiped
immediately after use.

The user buffer is wiped as well (we do not want to keep
and return sensitive data back to userspace if the flag is set).

Wiping is useful for cryptsetup to ensure that the key
is present in memory only in defined places and only
for the time needed.

(For crypt, key can be present in table during load or table
status, wait and message commands).

Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

authored by Milan Broz and committed by Alasdair G Kergon f8681205 6bb43b5d

+30 -5
+21 -2
drivers/md/dm-ioctl.c
··· 1504 static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) 1505 { 1506 struct dm_ioctl tmp, *dmi; 1507 1508 if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) 1509 return -EFAULT; ··· 1512 if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) 1513 return -EINVAL; 1514 1515 dmi = vmalloc(tmp.data_size); 1516 - if (!dmi) 1517 return -ENOMEM; 1518 1519 if (copy_from_user(dmi, user, tmp.data_size)) 1520 goto bad; 1521 1522 *param = dmi; 1523 return 0; 1524 1525 bad: 1526 vfree(dmi); 1527 return -EFAULT; 1528 } ··· 1543 /* Always clear this flag */ 1544 param->flags &= ~DM_BUFFER_FULL_FLAG; 1545 param->flags &= ~DM_UEVENT_GENERATED_FLAG; 1546 1547 /* Ignores parameters */ 1548 if (cmd == DM_REMOVE_ALL_CMD || ··· 1571 static int ctl_ioctl(uint command, struct dm_ioctl __user *user) 1572 { 1573 int r = 0; 1574 unsigned int cmd; 1575 struct dm_ioctl *uninitialized_var(param); 1576 ioctl_fn fn = NULL; ··· 1616 * Copy the parameters into kernel space. 1617 */ 1618 r = copy_params(user, &param); 1619 - input_param_size = param->data_size; 1620 1621 current->flags &= ~PF_MEMALLOC; 1622 1623 if (r) 1624 return r; 1625 1626 r = validate_params(cmd, param); 1627 if (r) ··· 1639 r = -EFAULT; 1640 1641 out: 1642 vfree(param); 1643 return r; 1644 }
··· 1504 static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) 1505 { 1506 struct dm_ioctl tmp, *dmi; 1507 + int secure_data; 1508 1509 if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) 1510 return -EFAULT; ··· 1511 if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) 1512 return -EINVAL; 1513 1514 + secure_data = tmp.flags & DM_SECURE_DATA_FLAG; 1515 + 1516 dmi = vmalloc(tmp.data_size); 1517 + if (!dmi) { 1518 + if (secure_data && clear_user(user, tmp.data_size)) 1519 + return -EFAULT; 1520 return -ENOMEM; 1521 + } 1522 1523 if (copy_from_user(dmi, user, tmp.data_size)) 1524 + goto bad; 1525 + 1526 + /* Wipe the user buffer so we do not return it to userspace */ 1527 + if (secure_data && clear_user(user, tmp.data_size)) 1528 goto bad; 1529 1530 *param = dmi; 1531 return 0; 1532 1533 bad: 1534 + if (secure_data) 1535 + memset(dmi, 0, tmp.data_size); 1536 vfree(dmi); 1537 return -EFAULT; 1538 } ··· 1531 /* Always clear this flag */ 1532 param->flags &= ~DM_BUFFER_FULL_FLAG; 1533 param->flags &= ~DM_UEVENT_GENERATED_FLAG; 1534 + param->flags &= ~DM_SECURE_DATA_FLAG; 1535 1536 /* Ignores parameters */ 1537 if (cmd == DM_REMOVE_ALL_CMD || ··· 1558 static int ctl_ioctl(uint command, struct dm_ioctl __user *user) 1559 { 1560 int r = 0; 1561 + int wipe_buffer; 1562 unsigned int cmd; 1563 struct dm_ioctl *uninitialized_var(param); 1564 ioctl_fn fn = NULL; ··· 1602 * Copy the parameters into kernel space. 1603 */ 1604 r = copy_params(user, &param); 1605 1606 current->flags &= ~PF_MEMALLOC; 1607 1608 if (r) 1609 return r; 1610 + 1611 + input_param_size = param->data_size; 1612 + wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; 1613 1614 r = validate_params(cmd, param); 1615 if (r) ··· 1623 r = -EFAULT; 1624 1625 out: 1626 + if (wipe_buffer) 1627 + memset(param, 0, input_param_size); 1628 + 1629 vfree(param); 1630 return r; 1631 }
+9 -3
include/linux/dm-ioctl.h
··· 267 #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) 268 269 #define DM_VERSION_MAJOR 4 270 - #define DM_VERSION_MINOR 19 271 - #define DM_VERSION_PATCHLEVEL 1 272 - #define DM_VERSION_EXTRA "-ioctl (2011-01-07)" 273 274 /* Status bits */ 275 #define DM_READONLY_FLAG (1 << 0) /* In/Out */ ··· 327 * if no uuid was previously supplied: an existing uuid cannot be changed. 328 */ 329 #define DM_UUID_FLAG (1 << 14) /* In */ 330 331 #endif /* _LINUX_DM_IOCTL_H */
··· 267 #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) 268 269 #define DM_VERSION_MAJOR 4 270 + #define DM_VERSION_MINOR 20 271 + #define DM_VERSION_PATCHLEVEL 0 272 + #define DM_VERSION_EXTRA "-ioctl (2011-02-02)" 273 274 /* Status bits */ 275 #define DM_READONLY_FLAG (1 << 0) /* In/Out */ ··· 327 * if no uuid was previously supplied: an existing uuid cannot be changed. 328 */ 329 #define DM_UUID_FLAG (1 << 14) /* In */ 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 337 #endif /* _LINUX_DM_IOCTL_H */