Skip to content

Commit 7e121f0

Browse files
committed
dm: pass through operations on wrapped inline crypto keys
JIRA: https://issues.redhat.com/browse/RHEL-119008 Upstream Status: kernel/git/torvalds/linux.git commit e939127 Author: Eric Biggers <ebiggers@google.com> Date: Thu May 1 14:23:20 2025 -0700 dm: pass through operations on wrapped inline crypto keys Make the device-mapper layer pass through the derive_sw_secret, import_key, generate_key, and prepare_key blk-crypto operations when all underlying devices support hardware-wrapped inline crypto keys and are passing through inline crypto support. Commit ebc4176 ("blk-crypto: add basic hardware-wrapped key support") already made BLK_CRYPTO_KEY_TYPE_HW_WRAPPED be passed through in the same way that the other crypto capabilities are. But the wrapped key support also includes additional operations in blk_crypto_ll_ops, and the dm layer needs to implement those to pass them through. derive_sw_secret is needed by fscrypt, while the other operations are needed for the new blk-crypto ioctls to work on device-mapper devices and not just the raw partitions. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 parent 6c9cbd3 commit 7e121f0

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

drivers/md/dm-table.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,176 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile,
11961196
return 0;
11971197
}
11981198

1199+
enum dm_wrappedkey_op {
1200+
DERIVE_SW_SECRET,
1201+
IMPORT_KEY,
1202+
GENERATE_KEY,
1203+
PREPARE_KEY,
1204+
};
1205+
1206+
struct dm_wrappedkey_op_args {
1207+
enum dm_wrappedkey_op op;
1208+
int err;
1209+
union {
1210+
struct {
1211+
const u8 *eph_key;
1212+
size_t eph_key_size;
1213+
u8 *sw_secret;
1214+
} derive_sw_secret;
1215+
struct {
1216+
const u8 *raw_key;
1217+
size_t raw_key_size;
1218+
u8 *lt_key;
1219+
} import_key;
1220+
struct {
1221+
u8 *lt_key;
1222+
} generate_key;
1223+
struct {
1224+
const u8 *lt_key;
1225+
size_t lt_key_size;
1226+
u8 *eph_key;
1227+
} prepare_key;
1228+
};
1229+
};
1230+
1231+
static int dm_wrappedkey_op_callback(struct dm_target *ti, struct dm_dev *dev,
1232+
sector_t start, sector_t len, void *data)
1233+
{
1234+
struct dm_wrappedkey_op_args *args = data;
1235+
struct block_device *bdev = dev->bdev;
1236+
struct blk_crypto_profile *profile =
1237+
bdev_get_queue(bdev)->crypto_profile;
1238+
int err = -EOPNOTSUPP;
1239+
1240+
if (!args->err)
1241+
return 0;
1242+
1243+
switch (args->op) {
1244+
case DERIVE_SW_SECRET:
1245+
err = blk_crypto_derive_sw_secret(
1246+
bdev,
1247+
args->derive_sw_secret.eph_key,
1248+
args->derive_sw_secret.eph_key_size,
1249+
args->derive_sw_secret.sw_secret);
1250+
break;
1251+
case IMPORT_KEY:
1252+
err = blk_crypto_import_key(profile,
1253+
args->import_key.raw_key,
1254+
args->import_key.raw_key_size,
1255+
args->import_key.lt_key);
1256+
break;
1257+
case GENERATE_KEY:
1258+
err = blk_crypto_generate_key(profile,
1259+
args->generate_key.lt_key);
1260+
break;
1261+
case PREPARE_KEY:
1262+
err = blk_crypto_prepare_key(profile,
1263+
args->prepare_key.lt_key,
1264+
args->prepare_key.lt_key_size,
1265+
args->prepare_key.eph_key);
1266+
break;
1267+
}
1268+
args->err = err;
1269+
1270+
/* Try another device in case this fails. */
1271+
return 0;
1272+
}
1273+
1274+
static int dm_exec_wrappedkey_op(struct blk_crypto_profile *profile,
1275+
struct dm_wrappedkey_op_args *args)
1276+
{
1277+
struct mapped_device *md =
1278+
container_of(profile, struct dm_crypto_profile, profile)->md;
1279+
struct dm_target *ti;
1280+
struct dm_table *t;
1281+
int srcu_idx;
1282+
int i;
1283+
1284+
args->err = -EOPNOTSUPP;
1285+
1286+
t = dm_get_live_table(md, &srcu_idx);
1287+
if (!t)
1288+
goto out;
1289+
1290+
/*
1291+
* blk-crypto currently has no support for multiple incompatible
1292+
* implementations of wrapped inline crypto keys on a single system.
1293+
* It was already checked earlier that support for wrapped keys was
1294+
* declared on all underlying devices. Thus, all the underlying devices
1295+
* should support all wrapped key operations and they should behave
1296+
* identically, i.e. work with the same keys. So, just executing the
1297+
* operation on the first device on which it works suffices for now.
1298+
*/
1299+
for (i = 0; i < t->num_targets; i++) {
1300+
ti = dm_table_get_target(t, i);
1301+
if (!ti->type->iterate_devices)
1302+
continue;
1303+
ti->type->iterate_devices(ti, dm_wrappedkey_op_callback, args);
1304+
if (!args->err)
1305+
break;
1306+
}
1307+
out:
1308+
dm_put_live_table(md, srcu_idx);
1309+
return args->err;
1310+
}
1311+
1312+
static int dm_derive_sw_secret(struct blk_crypto_profile *profile,
1313+
const u8 *eph_key, size_t eph_key_size,
1314+
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
1315+
{
1316+
struct dm_wrappedkey_op_args args = {
1317+
.op = DERIVE_SW_SECRET,
1318+
.derive_sw_secret = {
1319+
.eph_key = eph_key,
1320+
.eph_key_size = eph_key_size,
1321+
.sw_secret = sw_secret,
1322+
},
1323+
};
1324+
return dm_exec_wrappedkey_op(profile, &args);
1325+
}
1326+
1327+
static int dm_import_key(struct blk_crypto_profile *profile,
1328+
const u8 *raw_key, size_t raw_key_size,
1329+
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
1330+
{
1331+
struct dm_wrappedkey_op_args args = {
1332+
.op = IMPORT_KEY,
1333+
.import_key = {
1334+
.raw_key = raw_key,
1335+
.raw_key_size = raw_key_size,
1336+
.lt_key = lt_key,
1337+
},
1338+
};
1339+
return dm_exec_wrappedkey_op(profile, &args);
1340+
}
1341+
1342+
static int dm_generate_key(struct blk_crypto_profile *profile,
1343+
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
1344+
{
1345+
struct dm_wrappedkey_op_args args = {
1346+
.op = GENERATE_KEY,
1347+
.generate_key = {
1348+
.lt_key = lt_key,
1349+
},
1350+
};
1351+
return dm_exec_wrappedkey_op(profile, &args);
1352+
}
1353+
1354+
static int dm_prepare_key(struct blk_crypto_profile *profile,
1355+
const u8 *lt_key, size_t lt_key_size,
1356+
u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
1357+
{
1358+
struct dm_wrappedkey_op_args args = {
1359+
.op = PREPARE_KEY,
1360+
.prepare_key = {
1361+
.lt_key = lt_key,
1362+
.lt_key_size = lt_key_size,
1363+
.eph_key = eph_key,
1364+
},
1365+
};
1366+
return dm_exec_wrappedkey_op(profile, &args);
1367+
}
1368+
11991369
static int
12001370
device_intersect_crypto_capabilities(struct dm_target *ti, struct dm_dev *dev,
12011371
sector_t start, sector_t len, void *data)
@@ -1270,6 +1440,13 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
12701440
profile);
12711441
}
12721442

1443+
if (profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
1444+
profile->ll_ops.derive_sw_secret = dm_derive_sw_secret;
1445+
profile->ll_ops.import_key = dm_import_key;
1446+
profile->ll_ops.generate_key = dm_generate_key;
1447+
profile->ll_ops.prepare_key = dm_prepare_key;
1448+
}
1449+
12731450
if (t->md->queue &&
12741451
!blk_crypto_has_capabilities(profile,
12751452
t->md->queue->crypto_profile)) {

0 commit comments

Comments
 (0)