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