Skip to content

Commit aa6ce87

Browse files
Satya Tangiralasnitm
authored andcommitted
dm: add support for passing through inline crypto support
Update the device-mapper core to support exposing the inline crypto support of the underlying device(s) through the device-mapper device. This works by creating a "passthrough keyslot manager" for the dm device, which declares support for encryption settings which all underlying devices support. When a supported setting is used, the bio cloning code handles cloning the crypto context to the bios for all the underlying devices. When an unsupported setting is used, the blk-crypto fallback is used as usual. Crypto support on each underlying device is ignored unless the corresponding dm target opts into exposing it. This is needed because for inline crypto to semantically operate on the original bio, the data must not be transformed by the dm target. Thus, targets like dm-linear can expose crypto support of the underlying device, but targets like dm-crypt can't. (dm-crypt could use inline crypto itself, though.) A DM device's table can only be changed if the "new" inline encryption capabilities are a (*not* necessarily strict) superset of the "old" inline encryption capabilities. Attempts to make changes to the table that result in some inline encryption capability becoming no longer supported will be rejected. For the sake of clarity, key eviction from underlying devices will be handled in a future patch. Co-developed-by: Eric Biggers <[email protected]> Signed-off-by: Eric Biggers <[email protected]> Signed-off-by: Satya Tangirala <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent d3b17a2 commit aa6ce87

File tree

5 files changed

+197
-3
lines changed

5 files changed

+197
-3
lines changed

drivers/md/dm-core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/ktime.h>
1414
#include <linux/genhd.h>
1515
#include <linux/blk-mq.h>
16+
#include <linux/keyslot-manager.h>
1617

1718
#include <trace/events/block.h>
1819

@@ -162,6 +163,10 @@ struct dm_table {
162163
void *event_context;
163164

164165
struct dm_md_mempools *mempools;
166+
167+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
168+
struct blk_keyslot_manager *ksm;
169+
#endif
165170
};
166171

167172
static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj)

drivers/md/dm-table.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ static void free_devices(struct list_head *devices, struct mapped_device *md)
187187
}
188188
}
189189

190+
static void dm_table_destroy_keyslot_manager(struct dm_table *t);
191+
190192
void dm_table_destroy(struct dm_table *t)
191193
{
192194
unsigned int i;
@@ -215,6 +217,8 @@ void dm_table_destroy(struct dm_table *t)
215217

216218
dm_free_md_mempools(t->mempools);
217219

220+
dm_table_destroy_keyslot_manager(t);
221+
218222
kfree(t);
219223
}
220224

@@ -1203,6 +1207,157 @@ static int dm_table_register_integrity(struct dm_table *t)
12031207
return 0;
12041208
}
12051209

1210+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
1211+
1212+
struct dm_keyslot_manager {
1213+
struct blk_keyslot_manager ksm;
1214+
struct mapped_device *md;
1215+
};
1216+
1217+
static int device_intersect_crypto_modes(struct dm_target *ti,
1218+
struct dm_dev *dev, sector_t start,
1219+
sector_t len, void *data)
1220+
{
1221+
struct blk_keyslot_manager *parent = data;
1222+
struct blk_keyslot_manager *child = bdev_get_queue(dev->bdev)->ksm;
1223+
1224+
blk_ksm_intersect_modes(parent, child);
1225+
return 0;
1226+
}
1227+
1228+
void dm_destroy_keyslot_manager(struct blk_keyslot_manager *ksm)
1229+
{
1230+
struct dm_keyslot_manager *dksm = container_of(ksm,
1231+
struct dm_keyslot_manager,
1232+
ksm);
1233+
1234+
if (!ksm)
1235+
return;
1236+
1237+
blk_ksm_destroy(ksm);
1238+
kfree(dksm);
1239+
}
1240+
1241+
static void dm_table_destroy_keyslot_manager(struct dm_table *t)
1242+
{
1243+
dm_destroy_keyslot_manager(t->ksm);
1244+
t->ksm = NULL;
1245+
}
1246+
1247+
/*
1248+
* Constructs and initializes t->ksm with a keyslot manager that
1249+
* represents the common set of crypto capabilities of the devices
1250+
* described by the dm_table. However, if the constructed keyslot
1251+
* manager does not support a superset of the crypto capabilities
1252+
* supported by the current keyslot manager of the mapped_device,
1253+
* it returns an error instead, since we don't support restricting
1254+
* crypto capabilities on table changes. Finally, if the constructed
1255+
* keyslot manager doesn't actually support any crypto modes at all,
1256+
* it just returns NULL.
1257+
*/
1258+
static int dm_table_construct_keyslot_manager(struct dm_table *t)
1259+
{
1260+
struct dm_keyslot_manager *dksm;
1261+
struct blk_keyslot_manager *ksm;
1262+
struct dm_target *ti;
1263+
unsigned int i;
1264+
bool ksm_is_empty = true;
1265+
1266+
dksm = kmalloc(sizeof(*dksm), GFP_KERNEL);
1267+
if (!dksm)
1268+
return -ENOMEM;
1269+
dksm->md = t->md;
1270+
1271+
ksm = &dksm->ksm;
1272+
blk_ksm_init_passthrough(ksm);
1273+
ksm->max_dun_bytes_supported = UINT_MAX;
1274+
memset(ksm->crypto_modes_supported, 0xFF,
1275+
sizeof(ksm->crypto_modes_supported));
1276+
1277+
for (i = 0; i < dm_table_get_num_targets(t); i++) {
1278+
ti = dm_table_get_target(t, i);
1279+
1280+
if (!dm_target_passes_crypto(ti->type)) {
1281+
blk_ksm_intersect_modes(ksm, NULL);
1282+
break;
1283+
}
1284+
if (!ti->type->iterate_devices)
1285+
continue;
1286+
ti->type->iterate_devices(ti, device_intersect_crypto_modes,
1287+
ksm);
1288+
}
1289+
1290+
if (t->md->queue && !blk_ksm_is_superset(ksm, t->md->queue->ksm)) {
1291+
DMWARN("Inline encryption capabilities of new DM table were more restrictive than the old table's. This is not supported!");
1292+
dm_destroy_keyslot_manager(ksm);
1293+
return -EINVAL;
1294+
}
1295+
1296+
/*
1297+
* If the new KSM doesn't actually support any crypto modes, we may as
1298+
* well represent it with a NULL ksm.
1299+
*/
1300+
ksm_is_empty = true;
1301+
for (i = 0; i < ARRAY_SIZE(ksm->crypto_modes_supported); i++) {
1302+
if (ksm->crypto_modes_supported[i]) {
1303+
ksm_is_empty = false;
1304+
break;
1305+
}
1306+
}
1307+
1308+
if (ksm_is_empty) {
1309+
dm_destroy_keyslot_manager(ksm);
1310+
ksm = NULL;
1311+
}
1312+
1313+
/*
1314+
* t->ksm is only set temporarily while the table is being set
1315+
* up, and it gets set to NULL after the capabilities have
1316+
* been transferred to the request_queue.
1317+
*/
1318+
t->ksm = ksm;
1319+
1320+
return 0;
1321+
}
1322+
1323+
static void dm_update_keyslot_manager(struct request_queue *q,
1324+
struct dm_table *t)
1325+
{
1326+
if (!t->ksm)
1327+
return;
1328+
1329+
/* Make the ksm less restrictive */
1330+
if (!q->ksm) {
1331+
blk_ksm_register(t->ksm, q);
1332+
} else {
1333+
blk_ksm_update_capabilities(q->ksm, t->ksm);
1334+
dm_destroy_keyslot_manager(t->ksm);
1335+
}
1336+
t->ksm = NULL;
1337+
}
1338+
1339+
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
1340+
1341+
static int dm_table_construct_keyslot_manager(struct dm_table *t)
1342+
{
1343+
return 0;
1344+
}
1345+
1346+
void dm_destroy_keyslot_manager(struct blk_keyslot_manager *ksm)
1347+
{
1348+
}
1349+
1350+
static void dm_table_destroy_keyslot_manager(struct dm_table *t)
1351+
{
1352+
}
1353+
1354+
static void dm_update_keyslot_manager(struct request_queue *q,
1355+
struct dm_table *t)
1356+
{
1357+
}
1358+
1359+
#endif /* !CONFIG_BLK_INLINE_ENCRYPTION */
1360+
12061361
/*
12071362
* Prepares the table for use by building the indices,
12081363
* setting the type, and allocating mempools.
@@ -1229,6 +1384,12 @@ int dm_table_complete(struct dm_table *t)
12291384
return r;
12301385
}
12311386

1387+
r = dm_table_construct_keyslot_manager(t);
1388+
if (r) {
1389+
DMERR("could not construct keyslot manager.");
1390+
return r;
1391+
}
1392+
12321393
r = dm_table_alloc_md_mempools(t, t->md);
12331394
if (r)
12341395
DMERR("unable to allocate mempools");
@@ -1863,6 +2024,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
18632024
}
18642025
#endif
18652026

2027+
dm_update_keyslot_manager(q, t);
18662028
blk_queue_update_readahead(q);
18672029
}
18682030

drivers/md/dm.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/refcount.h>
2929
#include <linux/part_stat.h>
3030
#include <linux/blk-crypto.h>
31+
#include <linux/keyslot-manager.h>
3132

3233
#define DM_MSG_PREFIX "core"
3334

@@ -1722,6 +1723,19 @@ static const struct dax_operations dm_dax_ops;
17221723

17231724
static void dm_wq_work(struct work_struct *work);
17241725

1726+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
1727+
static void dm_queue_destroy_keyslot_manager(struct request_queue *q)
1728+
{
1729+
dm_destroy_keyslot_manager(q->ksm);
1730+
}
1731+
1732+
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
1733+
1734+
static inline void dm_queue_destroy_keyslot_manager(struct request_queue *q)
1735+
{
1736+
}
1737+
#endif /* !CONFIG_BLK_INLINE_ENCRYPTION */
1738+
17251739
static void cleanup_mapped_device(struct mapped_device *md)
17261740
{
17271741
if (md->wq)
@@ -1743,8 +1757,10 @@ static void cleanup_mapped_device(struct mapped_device *md)
17431757
put_disk(md->disk);
17441758
}
17451759

1746-
if (md->queue)
1760+
if (md->queue) {
1761+
dm_queue_destroy_keyslot_manager(md->queue);
17471762
blk_cleanup_queue(md->queue);
1763+
}
17481764

17491765
cleanup_srcu_struct(&md->io_barrier);
17501766

include/linux/device-mapper.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ struct target_type {
257257
#define DM_TARGET_NOWAIT 0x00000080
258258
#define dm_target_supports_nowait(type) ((type)->features & DM_TARGET_NOWAIT)
259259

260+
/*
261+
* A target supports passing through inline crypto support.
262+
*/
263+
#define DM_TARGET_PASSES_CRYPTO 0x00000100
264+
#define dm_target_passes_crypto(type) ((type)->features & DM_TARGET_PASSES_CRYPTO)
265+
260266
struct dm_target {
261267
struct dm_table *table;
262268
struct target_type *type;
@@ -533,6 +539,11 @@ void dm_table_run_md_queue_async(struct dm_table *t);
533539
struct dm_table *dm_swap_table(struct mapped_device *md,
534540
struct dm_table *t);
535541

542+
/*
543+
* Table keyslot manager functions
544+
*/
545+
void dm_destroy_keyslot_manager(struct blk_keyslot_manager *ksm);
546+
536547
/*
537548
* A wrapper around vmalloc.
538549
*/

include/uapi/linux/dm-ioctl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ enum {
272272
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
273273

274274
#define DM_VERSION_MAJOR 4
275-
#define DM_VERSION_MINOR 43
275+
#define DM_VERSION_MINOR 44
276276
#define DM_VERSION_PATCHLEVEL 0
277-
#define DM_VERSION_EXTRA "-ioctl (2020-10-01)"
277+
#define DM_VERSION_EXTRA "-ioctl (2021-02-01)"
278278

279279
/* Status bits */
280280
#define DM_READONLY_FLAG (1 << 0) /* In/Out */

0 commit comments

Comments
 (0)