Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

blk-crypto: add ioctls to create and prepare hardware-wrapped keys

Until this point, the kernel can use hardware-wrapped keys to do
encryption if userspace provides one -- specifically a key in
ephemerally-wrapped form. However, no generic way has been provided for
userspace to get such a key in the first place.

Getting such a key is a two-step process. First, the key needs to be
imported from a raw key or generated by the hardware, producing a key in
long-term wrapped form. This happens once in the whole lifetime of the
key. Second, the long-term wrapped key needs to be converted into
ephemerally-wrapped form. This happens each time the key is "unlocked".

In Android, these operations are supported in a generic way through
KeyMint, a userspace abstraction layer. However, that method is
Android-specific and can't be used on other Linux systems, may rely on
proprietary libraries, and also misleads people into supporting KeyMint
features like rollback resistance that make sense for other KeyMint keys
but don't make sense for hardware-wrapped inline encryption keys.

Therefore, this patch provides a generic kernel interface for these
operations by introducing new block device ioctls:

- BLKCRYPTOIMPORTKEY: convert a raw key to long-term wrapped form.

- BLKCRYPTOGENERATEKEY: have the hardware generate a new key, then
return it in long-term wrapped form.

- BLKCRYPTOPREPAREKEY: convert a key from long-term wrapped form to
ephemerally-wrapped form.

These ioctls are implemented using new operations in blk_crypto_ll_ops.

Signed-off-by: Eric Biggers <ebiggers@google.com>
Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> # sm8650
Link: https://lore.kernel.org/r/20250204060041.409950-4-ebiggers@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Eric Biggers and committed by
Jens Axboe
1ebd4a3c e35fde43

+350 -4
+36
Documentation/block/inline-encryption.rst
··· 492 492 blk-crypto-fallback doesn't support hardware-wrapped keys. Therefore, 493 493 hardware-wrapped keys can only be used with actual inline encryption hardware. 494 494 495 + All the above deals with hardware-wrapped keys in ephemerally-wrapped form only. 496 + To get such keys in the first place, new block device ioctls have been added to 497 + provide a generic interface to creating and preparing such keys: 498 + 499 + - ``BLKCRYPTOIMPORTKEY`` converts a raw key to long-term wrapped form. It takes 500 + in a pointer to a ``struct blk_crypto_import_key_arg``. The caller must set 501 + ``raw_key_ptr`` and ``raw_key_size`` to the pointer and size (in bytes) of the 502 + raw key to import. On success, ``BLKCRYPTOIMPORTKEY`` returns 0 and writes 503 + the resulting long-term wrapped key blob to the buffer pointed to by 504 + ``lt_key_ptr``, which is of maximum size ``lt_key_size``. It also updates 505 + ``lt_key_size`` to be the actual size of the key. On failure, it returns -1 506 + and sets errno. An errno of ``EOPNOTSUPP`` indicates that the block device 507 + does not support hardware-wrapped keys. An errno of ``EOVERFLOW`` indicates 508 + that the output buffer did not have enough space for the key blob. 509 + 510 + - ``BLKCRYPTOGENERATEKEY`` is like ``BLKCRYPTOIMPORTKEY``, but it has the 511 + hardware generate the key instead of importing one. It takes in a pointer to 512 + a ``struct blk_crypto_generate_key_arg``. 513 + 514 + - ``BLKCRYPTOPREPAREKEY`` converts a key from long-term wrapped form to 515 + ephemerally-wrapped form. It takes in a pointer to a ``struct 516 + blk_crypto_prepare_key_arg``. The caller must set ``lt_key_ptr`` and 517 + ``lt_key_size`` to the pointer and size (in bytes) of the long-term wrapped 518 + key blob to convert. On success, ``BLKCRYPTOPREPAREKEY`` returns 0 and writes 519 + the resulting ephemerally-wrapped key blob to the buffer pointed to by 520 + ``eph_key_ptr``, which is of maximum size ``eph_key_size``. It also updates 521 + ``eph_key_size`` to be the actual size of the key. On failure, it returns -1 522 + and sets errno. Errno values of ``EOPNOTSUPP`` and ``EOVERFLOW`` mean the 523 + same as they do for ``BLKCRYPTOIMPORTKEY``. An errno of ``EBADMSG`` indicates 524 + that the long-term wrapped key is invalid. 525 + 526 + Userspace needs to use either ``BLKCRYPTOIMPORTKEY`` or ``BLKCRYPTOGENERATEKEY`` 527 + once to create a key, and then ``BLKCRYPTOPREPAREKEY`` each time the key is 528 + unlocked and added to the kernel. Note that these ioctls have no relevance for 529 + raw keys; they are only for hardware-wrapped keys. 530 + 495 531 Testability 496 532 ----------- 497 533
+2
Documentation/userspace-api/ioctl/ioctl-number.rst
··· 85 85 0x10 20-2F arch/s390/include/uapi/asm/hypfs.h 86 86 0x12 all linux/fs.h BLK* ioctls 87 87 linux/blkpg.h 88 + linux/blkzoned.h 89 + linux/blk-crypto.h 88 90 0x15 all linux/fs.h FS_IOC_* ioctls 89 91 0x1b all InfiniBand Subsystem 90 92 <http://infiniband.sourceforge.net/>
+9
block/blk-crypto-internal.h
··· 83 83 bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile, 84 84 const struct blk_crypto_config *cfg); 85 85 86 + int blk_crypto_ioctl(struct block_device *bdev, unsigned int cmd, 87 + void __user *argp); 88 + 86 89 #else /* CONFIG_BLK_INLINE_ENCRYPTION */ 87 90 88 91 static inline int blk_crypto_sysfs_register(struct gendisk *disk) ··· 131 128 static inline bool blk_crypto_rq_has_keyslot(struct request *rq) 132 129 { 133 130 return false; 131 + } 132 + 133 + static inline int blk_crypto_ioctl(struct block_device *bdev, unsigned int cmd, 134 + void __user *argp) 135 + { 136 + return -ENOTTY; 134 137 } 135 138 136 139 #endif /* CONFIG_BLK_INLINE_ENCRYPTION */
+55
block/blk-crypto-profile.c
··· 502 502 return err; 503 503 } 504 504 505 + int blk_crypto_import_key(struct blk_crypto_profile *profile, 506 + const u8 *raw_key, size_t raw_key_size, 507 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) 508 + { 509 + int ret; 510 + 511 + if (!profile) 512 + return -EOPNOTSUPP; 513 + if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED)) 514 + return -EOPNOTSUPP; 515 + if (!profile->ll_ops.import_key) 516 + return -EOPNOTSUPP; 517 + blk_crypto_hw_enter(profile); 518 + ret = profile->ll_ops.import_key(profile, raw_key, raw_key_size, 519 + lt_key); 520 + blk_crypto_hw_exit(profile); 521 + return ret; 522 + } 523 + 524 + int blk_crypto_generate_key(struct blk_crypto_profile *profile, 525 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) 526 + { 527 + int ret; 528 + 529 + if (!profile) 530 + return -EOPNOTSUPP; 531 + if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED)) 532 + return -EOPNOTSUPP; 533 + if (!profile->ll_ops.generate_key) 534 + return -EOPNOTSUPP; 535 + blk_crypto_hw_enter(profile); 536 + ret = profile->ll_ops.generate_key(profile, lt_key); 537 + blk_crypto_hw_exit(profile); 538 + return ret; 539 + } 540 + 541 + int blk_crypto_prepare_key(struct blk_crypto_profile *profile, 542 + const u8 *lt_key, size_t lt_key_size, 543 + u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) 544 + { 545 + int ret; 546 + 547 + if (!profile) 548 + return -EOPNOTSUPP; 549 + if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED)) 550 + return -EOPNOTSUPP; 551 + if (!profile->ll_ops.prepare_key) 552 + return -EOPNOTSUPP; 553 + blk_crypto_hw_enter(profile); 554 + ret = profile->ll_ops.prepare_key(profile, lt_key, lt_key_size, 555 + eph_key); 556 + blk_crypto_hw_exit(profile); 557 + return ret; 558 + } 559 + 505 560 /** 506 561 * blk_crypto_intersect_capabilities() - restrict supported crypto capabilities 507 562 * by child device
+143
block/blk-crypto.c
··· 469 469 pr_warn_ratelimited("%pg: error %d evicting key\n", bdev, err); 470 470 } 471 471 EXPORT_SYMBOL_GPL(blk_crypto_evict_key); 472 + 473 + static int blk_crypto_ioctl_import_key(struct blk_crypto_profile *profile, 474 + void __user *argp) 475 + { 476 + struct blk_crypto_import_key_arg arg; 477 + u8 raw_key[BLK_CRYPTO_MAX_RAW_KEY_SIZE]; 478 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]; 479 + int ret; 480 + 481 + if (copy_from_user(&arg, argp, sizeof(arg))) 482 + return -EFAULT; 483 + 484 + if (memchr_inv(arg.reserved, 0, sizeof(arg.reserved))) 485 + return -EINVAL; 486 + 487 + if (arg.raw_key_size < 16 || arg.raw_key_size > sizeof(raw_key)) 488 + return -EINVAL; 489 + 490 + if (copy_from_user(raw_key, u64_to_user_ptr(arg.raw_key_ptr), 491 + arg.raw_key_size)) { 492 + ret = -EFAULT; 493 + goto out; 494 + } 495 + ret = blk_crypto_import_key(profile, raw_key, arg.raw_key_size, lt_key); 496 + if (ret < 0) 497 + goto out; 498 + if (ret > arg.lt_key_size) { 499 + ret = -EOVERFLOW; 500 + goto out; 501 + } 502 + arg.lt_key_size = ret; 503 + if (copy_to_user(u64_to_user_ptr(arg.lt_key_ptr), lt_key, 504 + arg.lt_key_size) || 505 + copy_to_user(argp, &arg, sizeof(arg))) { 506 + ret = -EFAULT; 507 + goto out; 508 + } 509 + ret = 0; 510 + 511 + out: 512 + memzero_explicit(raw_key, sizeof(raw_key)); 513 + memzero_explicit(lt_key, sizeof(lt_key)); 514 + return ret; 515 + } 516 + 517 + static int blk_crypto_ioctl_generate_key(struct blk_crypto_profile *profile, 518 + void __user *argp) 519 + { 520 + struct blk_crypto_generate_key_arg arg; 521 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]; 522 + int ret; 523 + 524 + if (copy_from_user(&arg, argp, sizeof(arg))) 525 + return -EFAULT; 526 + 527 + if (memchr_inv(arg.reserved, 0, sizeof(arg.reserved))) 528 + return -EINVAL; 529 + 530 + ret = blk_crypto_generate_key(profile, lt_key); 531 + if (ret < 0) 532 + goto out; 533 + if (ret > arg.lt_key_size) { 534 + ret = -EOVERFLOW; 535 + goto out; 536 + } 537 + arg.lt_key_size = ret; 538 + if (copy_to_user(u64_to_user_ptr(arg.lt_key_ptr), lt_key, 539 + arg.lt_key_size) || 540 + copy_to_user(argp, &arg, sizeof(arg))) { 541 + ret = -EFAULT; 542 + goto out; 543 + } 544 + ret = 0; 545 + 546 + out: 547 + memzero_explicit(lt_key, sizeof(lt_key)); 548 + return ret; 549 + } 550 + 551 + static int blk_crypto_ioctl_prepare_key(struct blk_crypto_profile *profile, 552 + void __user *argp) 553 + { 554 + struct blk_crypto_prepare_key_arg arg; 555 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]; 556 + u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]; 557 + int ret; 558 + 559 + if (copy_from_user(&arg, argp, sizeof(arg))) 560 + return -EFAULT; 561 + 562 + if (memchr_inv(arg.reserved, 0, sizeof(arg.reserved))) 563 + return -EINVAL; 564 + 565 + if (arg.lt_key_size > sizeof(lt_key)) 566 + return -EINVAL; 567 + 568 + if (copy_from_user(lt_key, u64_to_user_ptr(arg.lt_key_ptr), 569 + arg.lt_key_size)) { 570 + ret = -EFAULT; 571 + goto out; 572 + } 573 + ret = blk_crypto_prepare_key(profile, lt_key, arg.lt_key_size, eph_key); 574 + if (ret < 0) 575 + goto out; 576 + if (ret > arg.eph_key_size) { 577 + ret = -EOVERFLOW; 578 + goto out; 579 + } 580 + arg.eph_key_size = ret; 581 + if (copy_to_user(u64_to_user_ptr(arg.eph_key_ptr), eph_key, 582 + arg.eph_key_size) || 583 + copy_to_user(argp, &arg, sizeof(arg))) { 584 + ret = -EFAULT; 585 + goto out; 586 + } 587 + ret = 0; 588 + 589 + out: 590 + memzero_explicit(lt_key, sizeof(lt_key)); 591 + memzero_explicit(eph_key, sizeof(eph_key)); 592 + return ret; 593 + } 594 + 595 + int blk_crypto_ioctl(struct block_device *bdev, unsigned int cmd, 596 + void __user *argp) 597 + { 598 + struct blk_crypto_profile *profile = 599 + bdev_get_queue(bdev)->crypto_profile; 600 + 601 + if (!profile) 602 + return -EOPNOTSUPP; 603 + 604 + switch (cmd) { 605 + case BLKCRYPTOIMPORTKEY: 606 + return blk_crypto_ioctl_import_key(profile, argp); 607 + case BLKCRYPTOGENERATEKEY: 608 + return blk_crypto_ioctl_generate_key(profile, argp); 609 + case BLKCRYPTOPREPAREKEY: 610 + return blk_crypto_ioctl_prepare_key(profile, argp); 611 + default: 612 + return -ENOTTY; 613 + } 614 + }
+5
block/ioctl.c
··· 15 15 #include <linux/io_uring/cmd.h> 16 16 #include <uapi/linux/blkdev.h> 17 17 #include "blk.h" 18 + #include "blk-crypto-internal.h" 18 19 19 20 static int blkpg_do_ioctl(struct block_device *bdev, 20 21 struct blkpg_partition __user *upart, int op) ··· 621 620 case BLKTRACESTOP: 622 621 case BLKTRACETEARDOWN: 623 622 return blk_trace_ioctl(bdev, cmd, argp); 623 + case BLKCRYPTOIMPORTKEY: 624 + case BLKCRYPTOGENERATEKEY: 625 + case BLKCRYPTOPREPAREKEY: 626 + return blk_crypto_ioctl(bdev, cmd, argp); 624 627 case IOC_PR_REGISTER: 625 628 return blkdev_pr_register(bdev, mode, argp); 626 629 case IOC_PR_RESERVE:
+53
include/linux/blk-crypto-profile.h
··· 71 71 int (*derive_sw_secret)(struct blk_crypto_profile *profile, 72 72 const u8 *eph_key, size_t eph_key_size, 73 73 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); 74 + 75 + /** 76 + * @import_key: Create a hardware-wrapped key by importing a raw key. 77 + * 78 + * This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED 79 + * is supported. 80 + * 81 + * On success, must write the new key in long-term wrapped form to 82 + * @lt_key and return its size in bytes. On failure, must return a 83 + * -errno value. 84 + */ 85 + int (*import_key)(struct blk_crypto_profile *profile, 86 + const u8 *raw_key, size_t raw_key_size, 87 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 88 + 89 + /** 90 + * @generate_key: Generate a hardware-wrapped key. 91 + * 92 + * This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED 93 + * is supported. 94 + * 95 + * On success, must write the new key in long-term wrapped form to 96 + * @lt_key and return its size in bytes. On failure, must return a 97 + * -errno value. 98 + */ 99 + int (*generate_key)(struct blk_crypto_profile *profile, 100 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 101 + 102 + /** 103 + * @prepare_key: Prepare a hardware-wrapped key to be used. 104 + * 105 + * Prepare a hardware-wrapped key to be used by converting it from 106 + * long-term wrapped form to ephemerally-wrapped form. This only needs 107 + * to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED is supported. 108 + * 109 + * On success, must write the key in ephemerally-wrapped form to 110 + * @eph_key and return its size in bytes. On failure, must return 111 + * -EBADMSG if the key is invalid, or another -errno on other error. 112 + */ 113 + int (*prepare_key)(struct blk_crypto_profile *profile, 114 + const u8 *lt_key, size_t lt_key_size, 115 + u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 74 116 }; 75 117 76 118 /** ··· 204 162 void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile); 205 163 206 164 void blk_crypto_profile_destroy(struct blk_crypto_profile *profile); 165 + 166 + int blk_crypto_import_key(struct blk_crypto_profile *profile, 167 + const u8 *raw_key, size_t raw_key_size, 168 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 169 + 170 + int blk_crypto_generate_key(struct blk_crypto_profile *profile, 171 + u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 172 + 173 + int blk_crypto_prepare_key(struct blk_crypto_profile *profile, 174 + const u8 *lt_key, size_t lt_key_size, 175 + u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); 207 176 208 177 void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent, 209 178 const struct blk_crypto_profile *child);
+1
include/linux/blk-crypto.h
··· 8 8 9 9 #include <linux/minmax.h> 10 10 #include <linux/types.h> 11 + #include <uapi/linux/blk-crypto.h> 11 12 12 13 enum blk_crypto_mode_num { 13 14 BLK_ENCRYPTION_MODE_INVALID,
+44
include/uapi/linux/blk-crypto.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + #ifndef _UAPI_LINUX_BLK_CRYPTO_H 3 + #define _UAPI_LINUX_BLK_CRYPTO_H 4 + 5 + #include <linux/ioctl.h> 6 + #include <linux/types.h> 7 + 8 + struct blk_crypto_import_key_arg { 9 + /* Raw key (input) */ 10 + __u64 raw_key_ptr; 11 + __u64 raw_key_size; 12 + /* Long-term wrapped key blob (output) */ 13 + __u64 lt_key_ptr; 14 + __u64 lt_key_size; 15 + __u64 reserved[4]; 16 + }; 17 + 18 + struct blk_crypto_generate_key_arg { 19 + /* Long-term wrapped key blob (output) */ 20 + __u64 lt_key_ptr; 21 + __u64 lt_key_size; 22 + __u64 reserved[4]; 23 + }; 24 + 25 + struct blk_crypto_prepare_key_arg { 26 + /* Long-term wrapped key blob (input) */ 27 + __u64 lt_key_ptr; 28 + __u64 lt_key_size; 29 + /* Ephemerally-wrapped key blob (output) */ 30 + __u64 eph_key_ptr; 31 + __u64 eph_key_size; 32 + __u64 reserved[4]; 33 + }; 34 + 35 + /* 36 + * These ioctls share the block device ioctl space; see uapi/linux/fs.h. 37 + * 140-141 are reserved for future blk-crypto ioctls; any more than that would 38 + * require an additional allocation from the block device ioctl space. 39 + */ 40 + #define BLKCRYPTOIMPORTKEY _IOWR(0x12, 137, struct blk_crypto_import_key_arg) 41 + #define BLKCRYPTOGENERATEKEY _IOWR(0x12, 138, struct blk_crypto_generate_key_arg) 42 + #define BLKCRYPTOPREPAREKEY _IOWR(0x12, 139, struct blk_crypto_prepare_key_arg) 43 + 44 + #endif /* _UAPI_LINUX_BLK_CRYPTO_H */
+2 -4
include/uapi/linux/fs.h
··· 212 212 #define BLKROTATIONAL _IO(0x12,126) 213 213 #define BLKZEROOUT _IO(0x12,127) 214 214 #define BLKGETDISKSEQ _IOR(0x12,128,__u64) 215 - /* 216 - * A jump here: 130-136 are reserved for zoned block devices 217 - * (see uapi/linux/blkzoned.h) 218 - */ 215 + /* 130-136 are used by zoned block device ioctls (uapi/linux/blkzoned.h) */ 216 + /* 137-141 are used by blk-crypto ioctls (uapi/linux/blk-crypto.h) */ 219 217 220 218 #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ 221 219 #define FIBMAP _IO(0x00,1) /* bmap access */