Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 1 | /* |
| 2 | * QEMU block full disk encryption |
| 3 | * |
| 4 | * Copyright (c) 2015-2016 Red Hat, Inc. |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
Chetan Pant | 61f3c91 | 2020-10-23 12:44:24 +0000 | [diff] [blame] | 9 | * version 2.1 of the License, or (at your option) any later version. |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | * |
| 19 | */ |
| 20 | |
| 21 | #include "qemu/osdep.h" |
| 22 | |
| 23 | #include "block/block_int.h" |
Markus Armbruster | f853465 | 2018-06-14 21:14:34 +0200 | [diff] [blame] | 24 | #include "block/qdict.h" |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 25 | #include "sysemu/block-backend.h" |
| 26 | #include "crypto/block.h" |
| 27 | #include "qapi/opts-visitor.h" |
Markus Armbruster | 9af2398 | 2018-02-11 10:36:01 +0100 | [diff] [blame] | 28 | #include "qapi/qapi-visit-crypto.h" |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 29 | #include "qapi/qobject-input-visitor.h" |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 30 | #include "qapi/error.h" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 31 | #include "qemu/module.h" |
Markus Armbruster | 922a01a | 2018-02-01 12:18:46 +0100 | [diff] [blame] | 32 | #include "qemu/option.h" |
Daniel Henrique Barboza | 1bba30d | 2020-01-30 18:39:06 -0300 | [diff] [blame] | 33 | #include "qemu/cutils.h" |
Peter Maydell | 5df022c | 2022-02-26 18:07:23 +0000 | [diff] [blame] | 34 | #include "qemu/memalign.h" |
Michael S. Tsirkin | 0d8c41d | 2018-05-03 22:50:20 +0300 | [diff] [blame] | 35 | #include "crypto.h" |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 36 | |
| 37 | typedef struct BlockCrypto BlockCrypto; |
| 38 | |
| 39 | struct BlockCrypto { |
| 40 | QCryptoBlock *block; |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 41 | bool updating_keys; |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 42 | BdrvChild *header; /* Reference to the detached LUKS header */ |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 43 | }; |
| 44 | |
| 45 | |
| 46 | static int block_crypto_probe_generic(QCryptoBlockFormat format, |
| 47 | const uint8_t *buf, |
| 48 | int buf_size, |
| 49 | const char *filename) |
| 50 | { |
| 51 | if (qcrypto_block_has_format(format, buf, buf_size)) { |
| 52 | return 100; |
| 53 | } else { |
| 54 | return 0; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 59 | static int block_crypto_read_func(QCryptoBlock *block, |
| 60 | size_t offset, |
| 61 | uint8_t *buf, |
| 62 | size_t buflen, |
| 63 | void *opaque, |
| 64 | Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 65 | { |
| 66 | BlockDriverState *bs = opaque; |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 67 | BlockCrypto *crypto = bs->opaque; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 68 | ssize_t ret; |
| 69 | |
Kevin Wolf | 1f051dc | 2023-10-27 17:53:33 +0200 | [diff] [blame] | 70 | GLOBAL_STATE_CODE(); |
| 71 | GRAPH_RDLOCK_GUARD_MAINLOOP(); |
| 72 | |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 73 | ret = bdrv_pread(crypto->header ? crypto->header : bs->file, |
| 74 | offset, buflen, buf, 0); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 75 | if (ret < 0) { |
| 76 | error_setg_errno(errp, -ret, "Could not read encryption header"); |
| 77 | return ret; |
| 78 | } |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 79 | return 0; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 80 | } |
| 81 | |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 82 | static int block_crypto_write_func(QCryptoBlock *block, |
| 83 | size_t offset, |
| 84 | const uint8_t *buf, |
| 85 | size_t buflen, |
| 86 | void *opaque, |
| 87 | Error **errp) |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 88 | { |
| 89 | BlockDriverState *bs = opaque; |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 90 | BlockCrypto *crypto = bs->opaque; |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 91 | ssize_t ret; |
| 92 | |
Kevin Wolf | 1f051dc | 2023-10-27 17:53:33 +0200 | [diff] [blame] | 93 | GLOBAL_STATE_CODE(); |
| 94 | GRAPH_RDLOCK_GUARD_MAINLOOP(); |
| 95 | |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 96 | ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file, |
| 97 | offset, buflen, buf, 0); |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 98 | if (ret < 0) { |
| 99 | error_setg_errno(errp, -ret, "Could not write encryption header"); |
| 100 | return ret; |
| 101 | } |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 102 | return 0; |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 103 | } |
| 104 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 105 | |
| 106 | struct BlockCryptoCreateData { |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 107 | BlockBackend *blk; |
| 108 | uint64_t size; |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 109 | PreallocMode prealloc; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 110 | }; |
| 111 | |
| 112 | |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 113 | static int coroutine_fn GRAPH_UNLOCKED |
| 114 | block_crypto_create_write_func(QCryptoBlock *block, size_t offset, |
| 115 | const uint8_t *buf, size_t buflen, void *opaque, |
| 116 | Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 117 | { |
| 118 | struct BlockCryptoCreateData *data = opaque; |
| 119 | ssize_t ret; |
| 120 | |
Alberto Faria | a9262f5 | 2022-07-05 17:15:11 +0100 | [diff] [blame] | 121 | ret = blk_pwrite(data->blk, offset, buflen, buf, 0); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 122 | if (ret < 0) { |
| 123 | error_setg_errno(errp, -ret, "Could not write encryption header"); |
| 124 | return ret; |
| 125 | } |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 126 | return 0; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 127 | } |
| 128 | |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 129 | static int coroutine_fn GRAPH_UNLOCKED |
| 130 | block_crypto_create_init_func(QCryptoBlock *block, size_t headerlen, |
| 131 | void *opaque, Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 132 | { |
| 133 | struct BlockCryptoCreateData *data = opaque; |
Maxim Levitsky | 3d1900a | 2019-09-26 00:35:27 +0300 | [diff] [blame] | 134 | Error *local_error = NULL; |
| 135 | int ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 136 | |
Kevin Wolf | 3d7ed9c | 2018-03-05 18:15:26 +0100 | [diff] [blame] | 137 | if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) { |
Maxim Levitsky | 3d1900a | 2019-09-26 00:35:27 +0300 | [diff] [blame] | 138 | ret = -EFBIG; |
| 139 | goto error; |
Kevin Wolf | 3d7ed9c | 2018-03-05 18:15:26 +0100 | [diff] [blame] | 140 | } |
| 141 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 142 | /* User provided size should reflect amount of space made |
| 143 | * available to the guest, so we must take account of that |
| 144 | * which will be used by the crypto header |
| 145 | */ |
Maxim Levitsky | 3d1900a | 2019-09-26 00:35:27 +0300 | [diff] [blame] | 146 | ret = blk_truncate(data->blk, data->size + headerlen, false, |
| 147 | data->prealloc, 0, &local_error); |
| 148 | |
| 149 | if (ret >= 0) { |
Alberto Faria | 757dda5 | 2022-06-09 16:27:38 +0100 | [diff] [blame] | 150 | return 0; |
Maxim Levitsky | 3d1900a | 2019-09-26 00:35:27 +0300 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | error: |
| 154 | if (ret == -EFBIG) { |
| 155 | /* Replace the error message with a better one */ |
| 156 | error_free(local_error); |
| 157 | error_setg(errp, "The requested file size is too large"); |
| 158 | } else { |
| 159 | error_propagate(errp, local_error); |
| 160 | } |
| 161 | |
| 162 | return ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 163 | } |
| 164 | |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 165 | static int coroutine_fn GRAPH_UNLOCKED |
| 166 | block_crypto_co_format_luks_payload(BlockdevCreateOptionsLUKS *luks_opts, |
| 167 | Error **errp) |
| 168 | { |
| 169 | BlockDriverState *bs = NULL; |
| 170 | BlockBackend *blk = NULL; |
| 171 | Error *local_error = NULL; |
| 172 | int ret; |
| 173 | |
| 174 | if (luks_opts->size > INT64_MAX) { |
| 175 | return -EFBIG; |
| 176 | } |
| 177 | |
| 178 | bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); |
| 179 | if (bs == NULL) { |
| 180 | return -EIO; |
| 181 | } |
| 182 | |
| 183 | blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, |
| 184 | BLK_PERM_ALL, errp); |
| 185 | if (!blk) { |
| 186 | ret = -EPERM; |
| 187 | goto fail; |
| 188 | } |
| 189 | |
| 190 | ret = blk_truncate(blk, luks_opts->size, true, |
| 191 | luks_opts->preallocation, 0, &local_error); |
| 192 | if (ret < 0) { |
| 193 | if (ret == -EFBIG) { |
| 194 | /* Replace the error message with a better one */ |
| 195 | error_free(local_error); |
| 196 | error_setg(errp, "The requested file size is too large"); |
| 197 | } |
| 198 | goto fail; |
| 199 | } |
| 200 | |
| 201 | ret = 0; |
| 202 | |
| 203 | fail: |
| 204 | bdrv_co_unref(bs); |
| 205 | return ret; |
| 206 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 207 | |
| 208 | static QemuOptsList block_crypto_runtime_opts_luks = { |
| 209 | .name = "crypto", |
| 210 | .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head), |
| 211 | .desc = { |
Daniel P. Berrange | 4a47f85 | 2017-06-23 17:24:01 +0100 | [diff] [blame] | 212 | BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 213 | { /* end of list */ } |
| 214 | }, |
| 215 | }; |
| 216 | |
| 217 | |
| 218 | static QemuOptsList block_crypto_create_opts_luks = { |
| 219 | .name = "crypto", |
| 220 | .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head), |
| 221 | .desc = { |
| 222 | { |
| 223 | .name = BLOCK_OPT_SIZE, |
| 224 | .type = QEMU_OPT_SIZE, |
| 225 | .help = "Virtual disk size" |
| 226 | }, |
Daniel P. Berrange | 4a47f85 | 2017-06-23 17:24:01 +0100 | [diff] [blame] | 227 | BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), |
| 228 | BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""), |
| 229 | BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""), |
| 230 | BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""), |
| 231 | BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""), |
| 232 | BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""), |
| 233 | BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), |
Hyman Huang | 35286da | 2024-01-30 13:37:23 +0800 | [diff] [blame] | 234 | BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(""), |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 235 | { /* end of list */ } |
| 236 | }, |
| 237 | }; |
| 238 | |
| 239 | |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 240 | static QemuOptsList block_crypto_amend_opts_luks = { |
| 241 | .name = "crypto", |
| 242 | .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head), |
| 243 | .desc = { |
| 244 | BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""), |
| 245 | BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""), |
| 246 | BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""), |
| 247 | BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""), |
| 248 | BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), |
| 249 | { /* end of list */ } |
| 250 | }, |
| 251 | }; |
| 252 | |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 253 | QCryptoBlockOpenOptions * |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 254 | block_crypto_open_opts_init(QDict *opts, Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 255 | { |
Eric Blake | 09204ea | 2016-06-09 10:48:36 -0600 | [diff] [blame] | 256 | Visitor *v; |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 257 | QCryptoBlockOpenOptions *ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 258 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 259 | v = qobject_input_visitor_new_flat_confused(opts, errp); |
Markus Armbruster | e6af90f | 2018-06-26 10:05:46 +0200 | [diff] [blame] | 260 | if (!v) { |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 261 | return NULL; |
Markus Armbruster | f853465 | 2018-06-14 21:14:34 +0200 | [diff] [blame] | 262 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 263 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 264 | visit_type_QCryptoBlockOpenOptions(v, NULL, &ret, errp); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 265 | |
Eric Blake | 09204ea | 2016-06-09 10:48:36 -0600 | [diff] [blame] | 266 | visit_free(v); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 267 | return ret; |
| 268 | } |
| 269 | |
| 270 | |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 271 | QCryptoBlockCreateOptions * |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 272 | block_crypto_create_opts_init(QDict *opts, Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 273 | { |
Eric Blake | 09204ea | 2016-06-09 10:48:36 -0600 | [diff] [blame] | 274 | Visitor *v; |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 275 | QCryptoBlockCreateOptions *ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 276 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 277 | v = qobject_input_visitor_new_flat_confused(opts, errp); |
Markus Armbruster | e6af90f | 2018-06-26 10:05:46 +0200 | [diff] [blame] | 278 | if (!v) { |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 279 | return NULL; |
Markus Armbruster | f853465 | 2018-06-14 21:14:34 +0200 | [diff] [blame] | 280 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 281 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 282 | visit_type_QCryptoBlockCreateOptions(v, NULL, &ret, errp); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 283 | |
Eric Blake | 09204ea | 2016-06-09 10:48:36 -0600 | [diff] [blame] | 284 | visit_free(v); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 285 | return ret; |
| 286 | } |
| 287 | |
Maxim Levitsky | 43cbd06 | 2020-06-25 14:55:36 +0200 | [diff] [blame] | 288 | QCryptoBlockAmendOptions * |
| 289 | block_crypto_amend_opts_init(QDict *opts, Error **errp) |
| 290 | { |
| 291 | Visitor *v; |
| 292 | QCryptoBlockAmendOptions *ret; |
| 293 | |
| 294 | v = qobject_input_visitor_new_flat_confused(opts, errp); |
| 295 | if (!v) { |
| 296 | return NULL; |
| 297 | } |
| 298 | |
| 299 | visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp); |
| 300 | |
| 301 | visit_free(v); |
| 302 | return ret; |
| 303 | } |
| 304 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 305 | |
| 306 | static int block_crypto_open_generic(QCryptoBlockFormat format, |
| 307 | QemuOptsList *opts_spec, |
| 308 | BlockDriverState *bs, |
| 309 | QDict *options, |
| 310 | int flags, |
| 311 | Error **errp) |
| 312 | { |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 313 | ERRP_GUARD(); |
| 314 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 315 | BlockCrypto *crypto = bs->opaque; |
| 316 | QemuOpts *opts = NULL; |
Vladimir Sementsov-Ogievskiy | 8393078 | 2022-07-26 23:11:21 +0300 | [diff] [blame] | 317 | int ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 318 | QCryptoBlockOpenOptions *open_opts = NULL; |
| 319 | unsigned int cflags = 0; |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 320 | QDict *cryptoopts = NULL; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 321 | |
Kevin Wolf | a4b740d | 2023-10-27 17:53:32 +0200 | [diff] [blame] | 322 | GLOBAL_STATE_CODE(); |
| 323 | |
Vladimir Sementsov-Ogievskiy | 8393078 | 2022-07-26 23:11:21 +0300 | [diff] [blame] | 324 | ret = bdrv_open_file_child(NULL, options, "file", bs, errp); |
| 325 | if (ret < 0) { |
| 326 | return ret; |
Kevin Wolf | 4e4bf5c | 2016-12-16 18:52:37 +0100 | [diff] [blame] | 327 | } |
| 328 | |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 329 | crypto->header = bdrv_open_child(NULL, options, "header", bs, |
| 330 | &child_of_bds, BDRV_CHILD_METADATA, |
| 331 | true, errp); |
| 332 | if (*errp != NULL) { |
| 333 | return -EINVAL; |
| 334 | } |
| 335 | |
Kevin Wolf | a4b740d | 2023-10-27 17:53:32 +0200 | [diff] [blame] | 336 | GRAPH_RDLOCK_GUARD_MAINLOOP(); |
| 337 | |
Daniel P. Berrange | d67a6b0 | 2017-09-27 13:53:40 +0100 | [diff] [blame] | 338 | bs->supported_write_flags = BDRV_REQ_FUA & |
| 339 | bs->file->bs->supported_write_flags; |
| 340 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 341 | opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); |
Markus Armbruster | af175e8 | 2020-07-07 18:06:03 +0200 | [diff] [blame] | 342 | if (!qemu_opts_absorb_qdict(opts, options, errp)) { |
Vladimir Sementsov-Ogievskiy | 8393078 | 2022-07-26 23:11:21 +0300 | [diff] [blame] | 343 | ret = -EINVAL; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 344 | goto cleanup; |
| 345 | } |
| 346 | |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 347 | cryptoopts = qemu_opts_to_qdict(opts, NULL); |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 348 | qdict_put_str(cryptoopts, "format", QCryptoBlockFormat_str(format)); |
Daniel P. Berrange | 306a06e | 2017-06-23 17:24:00 +0100 | [diff] [blame] | 349 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 350 | open_opts = block_crypto_open_opts_init(cryptoopts, errp); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 351 | if (!open_opts) { |
Vladimir Sementsov-Ogievskiy | 8393078 | 2022-07-26 23:11:21 +0300 | [diff] [blame] | 352 | ret = -EINVAL; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 353 | goto cleanup; |
| 354 | } |
| 355 | |
| 356 | if (flags & BDRV_O_NO_IO) { |
| 357 | cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; |
| 358 | } |
Hyman Huang | 9ad5c4e | 2024-01-30 13:37:19 +0800 | [diff] [blame] | 359 | if (crypto->header != NULL) { |
| 360 | cflags |= QCRYPTO_BLOCK_OPEN_DETACHED; |
| 361 | } |
Daniel P. Berrange | 1cd9a78 | 2017-06-23 17:24:17 +0100 | [diff] [blame] | 362 | crypto->block = qcrypto_block_open(open_opts, NULL, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 363 | block_crypto_read_func, |
| 364 | bs, |
| 365 | cflags, |
| 366 | errp); |
| 367 | |
| 368 | if (!crypto->block) { |
| 369 | ret = -EIO; |
| 370 | goto cleanup; |
| 371 | } |
| 372 | |
Eric Blake | 5411541 | 2016-06-23 16:37:26 -0600 | [diff] [blame] | 373 | bs->encrypted = true; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 374 | |
| 375 | ret = 0; |
| 376 | cleanup: |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 377 | qobject_unref(cryptoopts); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 378 | qapi_free_QCryptoBlockOpenOptions(open_opts); |
| 379 | return ret; |
| 380 | } |
| 381 | |
| 382 | |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 383 | static int coroutine_fn GRAPH_UNLOCKED |
Kevin Wolf | 91817e9 | 2023-01-26 18:24:22 +0100 | [diff] [blame] | 384 | block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, |
| 385 | QCryptoBlockCreateOptions *opts, |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 386 | PreallocMode prealloc, |
| 387 | unsigned int flags, |
| 388 | Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 389 | { |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 390 | int ret; |
| 391 | BlockBackend *blk; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 392 | QCryptoBlock *crypto = NULL; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 393 | struct BlockCryptoCreateData data; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 394 | |
Kevin Wolf | 91817e9 | 2023-01-26 18:24:22 +0100 | [diff] [blame] | 395 | blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, |
| 396 | errp); |
Eric Blake | a3aeeab | 2020-04-28 14:26:46 -0500 | [diff] [blame] | 397 | if (!blk) { |
| 398 | ret = -EPERM; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 399 | goto cleanup; |
Kevin Wolf | 3b5a1f6 | 2018-03-02 11:48:45 +0100 | [diff] [blame] | 400 | } |
| 401 | |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 402 | if (prealloc == PREALLOC_MODE_METADATA) { |
| 403 | prealloc = PREALLOC_MODE_OFF; |
| 404 | } |
| 405 | |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 406 | data = (struct BlockCryptoCreateData) { |
| 407 | .blk = blk, |
Hyman Huang | 35286da | 2024-01-30 13:37:23 +0800 | [diff] [blame] | 408 | .size = flags & QCRYPTO_BLOCK_CREATE_DETACHED ? 0 : size, |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 409 | .prealloc = prealloc, |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 410 | }; |
Kevin Wolf | 3b5a1f6 | 2018-03-02 11:48:45 +0100 | [diff] [blame] | 411 | |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 412 | crypto = qcrypto_block_create(opts, NULL, |
Maxim Levitsky | e0d0ddc | 2020-06-25 14:55:41 +0200 | [diff] [blame] | 413 | block_crypto_create_init_func, |
| 414 | block_crypto_create_write_func, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 415 | &data, |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 416 | flags, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 417 | errp); |
| 418 | |
| 419 | if (!crypto) { |
| 420 | ret = -EIO; |
| 421 | goto cleanup; |
| 422 | } |
| 423 | |
| 424 | ret = 0; |
| 425 | cleanup: |
| 426 | qcrypto_block_free(crypto); |
Kevin Wolf | b2ab5f5 | 2023-05-04 13:57:33 +0200 | [diff] [blame] | 427 | blk_co_unref(blk); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 428 | return ret; |
| 429 | } |
| 430 | |
Kevin Wolf | c2b8e31 | 2023-02-03 16:21:42 +0100 | [diff] [blame] | 431 | static int coroutine_fn GRAPH_RDLOCK |
Max Reitz | c80d8b0 | 2019-09-18 11:51:40 +0200 | [diff] [blame] | 432 | block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, |
Kevin Wolf | 92b9279 | 2020-04-24 14:54:39 +0200 | [diff] [blame] | 433 | PreallocMode prealloc, BdrvRequestFlags flags, |
| 434 | Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 435 | { |
| 436 | BlockCrypto *crypto = bs->opaque; |
Daniel P. Berrange | 3137655 | 2017-09-27 13:53:37 +0100 | [diff] [blame] | 437 | uint64_t payload_offset = |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 438 | qcrypto_block_get_payload_offset(crypto->block); |
Kevin Wolf | 120bc74 | 2018-03-20 16:38:51 +0100 | [diff] [blame] | 439 | |
| 440 | if (payload_offset > INT64_MAX - offset) { |
| 441 | error_setg(errp, "The requested file size is too large"); |
| 442 | return -EFBIG; |
| 443 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 444 | |
| 445 | offset += payload_offset; |
| 446 | |
Kevin Wolf | 7b8e485 | 2020-04-24 14:54:40 +0200 | [diff] [blame] | 447 | return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 448 | } |
| 449 | |
| 450 | static void block_crypto_close(BlockDriverState *bs) |
| 451 | { |
| 452 | BlockCrypto *crypto = bs->opaque; |
| 453 | qcrypto_block_free(crypto->block); |
| 454 | } |
| 455 | |
Daniel P. Berrange | f87e08f | 2018-01-18 10:31:43 +0000 | [diff] [blame] | 456 | static int block_crypto_reopen_prepare(BDRVReopenState *state, |
| 457 | BlockReopenQueue *queue, Error **errp) |
| 458 | { |
| 459 | /* nothing needs checking */ |
| 460 | return 0; |
| 461 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 462 | |
Daniel P. Berrange | 161253e | 2017-09-27 13:53:35 +0100 | [diff] [blame] | 463 | /* |
| 464 | * 1 MB bounce buffer gives good performance / memory tradeoff |
| 465 | * when using cache=none|directsync. |
| 466 | */ |
| 467 | #define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 468 | |
Kevin Wolf | b9b10c3 | 2023-02-03 16:21:50 +0100 | [diff] [blame] | 469 | static int coroutine_fn GRAPH_RDLOCK |
Vladimir Sementsov-Ogievskiy | f7ef38d | 2021-09-03 13:27:59 +0300 | [diff] [blame] | 470 | block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
| 471 | QEMUIOVector *qiov, BdrvRequestFlags flags) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 472 | { |
| 473 | BlockCrypto *crypto = bs->opaque; |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 474 | uint64_t cur_bytes; /* number of bytes in current iteration */ |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 475 | uint64_t bytes_done = 0; |
| 476 | uint8_t *cipher_data = NULL; |
| 477 | QEMUIOVector hd_qiov; |
| 478 | int ret = 0; |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 479 | uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); |
| 480 | uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 481 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 482 | assert(payload_offset < INT64_MAX); |
| 483 | assert(QEMU_IS_ALIGNED(offset, sector_size)); |
| 484 | assert(QEMU_IS_ALIGNED(bytes, sector_size)); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 485 | |
| 486 | qemu_iovec_init(&hd_qiov, qiov->niov); |
| 487 | |
Daniel P. Berrange | 161253e | 2017-09-27 13:53:35 +0100 | [diff] [blame] | 488 | /* Bounce buffer because we don't wish to expose cipher text |
| 489 | * in qiov which points to guest memory. |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 490 | */ |
| 491 | cipher_data = |
Daniel P. Berrange | 161253e | 2017-09-27 13:53:35 +0100 | [diff] [blame] | 492 | qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 493 | qiov->size)); |
| 494 | if (cipher_data == NULL) { |
| 495 | ret = -ENOMEM; |
| 496 | goto cleanup; |
| 497 | } |
| 498 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 499 | while (bytes) { |
| 500 | cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 501 | |
| 502 | qemu_iovec_reset(&hd_qiov); |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 503 | qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 504 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 505 | ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done, |
| 506 | cur_bytes, &hd_qiov, 0); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 507 | if (ret < 0) { |
| 508 | goto cleanup; |
| 509 | } |
| 510 | |
Daniel P. Berrange | 4609742 | 2017-09-27 13:53:39 +0100 | [diff] [blame] | 511 | if (qcrypto_block_decrypt(crypto->block, offset + bytes_done, |
| 512 | cipher_data, cur_bytes, NULL) < 0) { |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 513 | ret = -EIO; |
| 514 | goto cleanup; |
| 515 | } |
| 516 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 517 | qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 518 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 519 | bytes -= cur_bytes; |
| 520 | bytes_done += cur_bytes; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 521 | } |
| 522 | |
| 523 | cleanup: |
| 524 | qemu_iovec_destroy(&hd_qiov); |
| 525 | qemu_vfree(cipher_data); |
| 526 | |
| 527 | return ret; |
| 528 | } |
| 529 | |
| 530 | |
Kevin Wolf | b9b10c3 | 2023-02-03 16:21:50 +0100 | [diff] [blame] | 531 | static int coroutine_fn GRAPH_RDLOCK |
Vladimir Sementsov-Ogievskiy | e75abed | 2021-09-03 13:28:00 +0300 | [diff] [blame] | 532 | block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, |
| 533 | QEMUIOVector *qiov, BdrvRequestFlags flags) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 534 | { |
| 535 | BlockCrypto *crypto = bs->opaque; |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 536 | uint64_t cur_bytes; /* number of bytes in current iteration */ |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 537 | uint64_t bytes_done = 0; |
| 538 | uint8_t *cipher_data = NULL; |
| 539 | QEMUIOVector hd_qiov; |
| 540 | int ret = 0; |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 541 | uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); |
| 542 | uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 543 | |
Stefan Hajnoczi | e8b6535 | 2022-10-13 14:59:01 -0400 | [diff] [blame] | 544 | flags &= ~BDRV_REQ_REGISTERED_BUF; |
| 545 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 546 | assert(payload_offset < INT64_MAX); |
| 547 | assert(QEMU_IS_ALIGNED(offset, sector_size)); |
| 548 | assert(QEMU_IS_ALIGNED(bytes, sector_size)); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 549 | |
| 550 | qemu_iovec_init(&hd_qiov, qiov->niov); |
| 551 | |
Daniel P. Berrange | 161253e | 2017-09-27 13:53:35 +0100 | [diff] [blame] | 552 | /* Bounce buffer because we're not permitted to touch |
| 553 | * contents of qiov - it points to guest memory. |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 554 | */ |
| 555 | cipher_data = |
Daniel P. Berrange | 161253e | 2017-09-27 13:53:35 +0100 | [diff] [blame] | 556 | qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 557 | qiov->size)); |
| 558 | if (cipher_data == NULL) { |
| 559 | ret = -ENOMEM; |
| 560 | goto cleanup; |
| 561 | } |
| 562 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 563 | while (bytes) { |
| 564 | cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 565 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 566 | qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 567 | |
Daniel P. Berrange | 4609742 | 2017-09-27 13:53:39 +0100 | [diff] [blame] | 568 | if (qcrypto_block_encrypt(crypto->block, offset + bytes_done, |
| 569 | cipher_data, cur_bytes, NULL) < 0) { |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 570 | ret = -EIO; |
| 571 | goto cleanup; |
| 572 | } |
| 573 | |
| 574 | qemu_iovec_reset(&hd_qiov); |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 575 | qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 576 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 577 | ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done, |
Daniel P. Berrange | d67a6b0 | 2017-09-27 13:53:40 +0100 | [diff] [blame] | 578 | cur_bytes, &hd_qiov, flags); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 579 | if (ret < 0) { |
| 580 | goto cleanup; |
| 581 | } |
| 582 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 583 | bytes -= cur_bytes; |
| 584 | bytes_done += cur_bytes; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 585 | } |
| 586 | |
| 587 | cleanup: |
| 588 | qemu_iovec_destroy(&hd_qiov); |
| 589 | qemu_vfree(cipher_data); |
| 590 | |
| 591 | return ret; |
| 592 | } |
| 593 | |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 594 | static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp) |
| 595 | { |
| 596 | BlockCrypto *crypto = bs->opaque; |
| 597 | uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); |
| 598 | bs->bl.request_alignment = sector_size; /* No sub-sector I/O */ |
| 599 | } |
| 600 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 601 | |
Kevin Wolf | 8ab8140 | 2023-02-03 16:22:02 +0100 | [diff] [blame] | 602 | static int64_t coroutine_fn GRAPH_RDLOCK |
| 603 | block_crypto_co_getlength(BlockDriverState *bs) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 604 | { |
| 605 | BlockCrypto *crypto = bs->opaque; |
Emanuele Giuseppe Esposito | c86422c | 2023-01-13 21:42:04 +0100 | [diff] [blame] | 606 | int64_t len = bdrv_co_getlength(bs->file->bs); |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 607 | |
Daniel P. Berrange | 3137655 | 2017-09-27 13:53:37 +0100 | [diff] [blame] | 608 | uint64_t offset = qcrypto_block_get_payload_offset(crypto->block); |
| 609 | assert(offset < INT64_MAX); |
Kevin Wolf | e39e959 | 2018-03-05 17:39:31 +0100 | [diff] [blame] | 610 | |
| 611 | if (offset > len) { |
| 612 | return -EIO; |
| 613 | } |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 614 | |
| 615 | len -= offset; |
| 616 | |
| 617 | return len; |
| 618 | } |
| 619 | |
| 620 | |
Stefan Hajnoczi | a9da6e4 | 2020-02-21 11:25:20 +0000 | [diff] [blame] | 621 | static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts, |
| 622 | BlockDriverState *in_bs, |
| 623 | Error **errp) |
| 624 | { |
| 625 | g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL; |
| 626 | Error *local_err = NULL; |
| 627 | BlockMeasureInfo *info; |
| 628 | uint64_t size; |
| 629 | size_t luks_payload_size; |
| 630 | QDict *cryptoopts; |
| 631 | |
| 632 | /* |
| 633 | * Preallocation mode doesn't affect size requirements but we must consume |
| 634 | * the option. |
| 635 | */ |
| 636 | g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC)); |
| 637 | |
| 638 | size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); |
| 639 | |
| 640 | if (in_bs) { |
| 641 | int64_t ssize = bdrv_getlength(in_bs); |
| 642 | |
| 643 | if (ssize < 0) { |
| 644 | error_setg_errno(&local_err, -ssize, |
| 645 | "Unable to get image virtual_size"); |
| 646 | goto err; |
| 647 | } |
| 648 | |
| 649 | size = ssize; |
| 650 | } |
| 651 | |
| 652 | cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL, |
| 653 | &block_crypto_create_opts_luks, true); |
| 654 | qdict_put_str(cryptoopts, "format", "luks"); |
| 655 | create_opts = block_crypto_create_opts_init(cryptoopts, &local_err); |
| 656 | qobject_unref(cryptoopts); |
| 657 | if (!create_opts) { |
| 658 | goto err; |
| 659 | } |
| 660 | |
| 661 | if (!qcrypto_block_calculate_payload_offset(create_opts, NULL, |
| 662 | &luks_payload_size, |
| 663 | &local_err)) { |
| 664 | goto err; |
| 665 | } |
| 666 | |
| 667 | /* |
| 668 | * Unallocated blocks are still encrypted so allocation status makes no |
| 669 | * difference to the file size. |
| 670 | */ |
Eric Blake | 5d72c68 | 2020-05-21 14:21:34 -0500 | [diff] [blame] | 671 | info = g_new0(BlockMeasureInfo, 1); |
Stefan Hajnoczi | a9da6e4 | 2020-02-21 11:25:20 +0000 | [diff] [blame] | 672 | info->fully_allocated = luks_payload_size + size; |
| 673 | info->required = luks_payload_size + size; |
| 674 | return info; |
| 675 | |
| 676 | err: |
| 677 | error_propagate(errp, local_err); |
| 678 | return NULL; |
| 679 | } |
| 680 | |
| 681 | |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 682 | static int block_crypto_probe_luks(const uint8_t *buf, |
| 683 | int buf_size, |
| 684 | const char *filename) { |
Markus Armbruster | d23d2ef | 2024-09-04 13:18:22 +0200 | [diff] [blame] | 685 | return block_crypto_probe_generic(QCRYPTO_BLOCK_FORMAT_LUKS, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 686 | buf, buf_size, filename); |
| 687 | } |
| 688 | |
| 689 | static int block_crypto_open_luks(BlockDriverState *bs, |
| 690 | QDict *options, |
| 691 | int flags, |
| 692 | Error **errp) |
| 693 | { |
Markus Armbruster | d23d2ef | 2024-09-04 13:18:22 +0200 | [diff] [blame] | 694 | return block_crypto_open_generic(QCRYPTO_BLOCK_FORMAT_LUKS, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 695 | &block_crypto_runtime_opts_luks, |
| 696 | bs, options, flags, errp); |
| 697 | } |
| 698 | |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 699 | static int coroutine_fn GRAPH_UNLOCKED |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 700 | block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) |
| 701 | { |
| 702 | BlockdevCreateOptionsLUKS *luks_opts; |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 703 | BlockDriverState *hdr_bs = NULL; |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 704 | BlockDriverState *bs = NULL; |
| 705 | QCryptoBlockCreateOptions create_opts; |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 706 | PreallocMode preallocation = PREALLOC_MODE_OFF; |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 707 | unsigned int cflags = 0; |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 708 | int ret; |
| 709 | |
| 710 | assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); |
| 711 | luks_opts = &create_options->u.luks; |
| 712 | |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 713 | if (luks_opts->header == NULL && luks_opts->file == NULL) { |
| 714 | error_setg(errp, "Either the parameter 'header' or 'file' must " |
| 715 | "be specified"); |
| 716 | return -EINVAL; |
| 717 | } |
| 718 | |
| 719 | if ((luks_opts->preallocation != PREALLOC_MODE_OFF) && |
| 720 | (luks_opts->file == NULL)) { |
| 721 | error_setg(errp, "Parameter 'preallocation' requires 'file' to be " |
| 722 | "specified for formatting LUKS disk"); |
Hyman Huang | 433957b | 2024-01-30 13:37:20 +0800 | [diff] [blame] | 723 | return -EINVAL; |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 724 | } |
| 725 | |
| 726 | create_opts = (QCryptoBlockCreateOptions) { |
Markus Armbruster | d23d2ef | 2024-09-04 13:18:22 +0200 | [diff] [blame] | 727 | .format = QCRYPTO_BLOCK_FORMAT_LUKS, |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 728 | .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts), |
| 729 | }; |
| 730 | |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 731 | if (luks_opts->has_preallocation) { |
| 732 | preallocation = luks_opts->preallocation; |
| 733 | } |
| 734 | |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 735 | if (luks_opts->header) { |
| 736 | /* LUKS volume with detached header */ |
| 737 | hdr_bs = bdrv_co_open_blockdev_ref(luks_opts->header, errp); |
| 738 | if (hdr_bs == NULL) { |
| 739 | return -EIO; |
| 740 | } |
| 741 | |
| 742 | cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; |
| 743 | |
| 744 | /* Format the LUKS header node */ |
| 745 | ret = block_crypto_co_create_generic(hdr_bs, 0, &create_opts, |
| 746 | PREALLOC_MODE_OFF, cflags, errp); |
| 747 | if (ret < 0) { |
| 748 | goto fail; |
| 749 | } |
| 750 | |
| 751 | /* Format the LUKS payload node */ |
| 752 | if (luks_opts->file) { |
| 753 | ret = block_crypto_co_format_luks_payload(luks_opts, errp); |
| 754 | if (ret < 0) { |
| 755 | goto fail; |
| 756 | } |
| 757 | } |
| 758 | } else if (luks_opts->file) { |
| 759 | /* LUKS volume with none-detached header */ |
Hyman Huang | 433957b | 2024-01-30 13:37:20 +0800 | [diff] [blame] | 760 | bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); |
| 761 | if (bs == NULL) { |
| 762 | return -EIO; |
| 763 | } |
| 764 | |
| 765 | ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts, |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 766 | preallocation, cflags, errp); |
Hyman Huang | 433957b | 2024-01-30 13:37:20 +0800 | [diff] [blame] | 767 | if (ret < 0) { |
| 768 | goto fail; |
| 769 | } |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 770 | } |
| 771 | |
| 772 | ret = 0; |
| 773 | fail: |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 774 | if (hdr_bs != NULL) { |
| 775 | bdrv_co_unref(hdr_bs); |
| 776 | } |
| 777 | |
| 778 | if (bs != NULL) { |
| 779 | bdrv_co_unref(bs); |
| 780 | } |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 781 | return ret; |
| 782 | } |
| 783 | |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 784 | static int coroutine_fn GRAPH_UNLOCKED |
Kevin Wolf | 4ec8df0 | 2023-02-03 16:21:55 +0100 | [diff] [blame] | 785 | block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, |
| 786 | QemuOpts *opts, Error **errp) |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 787 | { |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 788 | QCryptoBlockCreateOptions *create_opts = NULL; |
| 789 | BlockDriverState *bs = NULL; |
| 790 | QDict *cryptoopts; |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 791 | PreallocMode prealloc; |
| 792 | char *buf = NULL; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 793 | int64_t size; |
Hyman Huang | 35286da | 2024-01-30 13:37:23 +0800 | [diff] [blame] | 794 | bool detached_hdr = |
| 795 | qemu_opt_get_bool(opts, "detached-header", false); |
| 796 | unsigned int cflags = 0; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 797 | int ret; |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 798 | Error *local_err = NULL; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 799 | |
| 800 | /* Parse options */ |
| 801 | size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); |
| 802 | |
Maxim Levitsky | 672de729 | 2019-07-16 19:19:01 +0300 | [diff] [blame] | 803 | buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); |
| 804 | prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, |
| 805 | PREALLOC_MODE_OFF, &local_err); |
| 806 | g_free(buf); |
| 807 | if (local_err) { |
| 808 | error_propagate(errp, local_err); |
| 809 | return -EINVAL; |
| 810 | } |
| 811 | |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 812 | cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL, |
| 813 | &block_crypto_create_opts_luks, |
| 814 | true); |
| 815 | |
Markus Armbruster | 796d323 | 2018-06-26 19:41:19 +0200 | [diff] [blame] | 816 | qdict_put_str(cryptoopts, "format", "luks"); |
| 817 | create_opts = block_crypto_create_opts_init(cryptoopts, errp); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 818 | if (!create_opts) { |
| 819 | ret = -EINVAL; |
| 820 | goto fail; |
| 821 | } |
| 822 | |
| 823 | /* Create protocol layer */ |
Emanuele Giuseppe Esposito | 2475a0d | 2022-11-28 09:23:31 -0500 | [diff] [blame] | 824 | ret = bdrv_co_create_file(filename, opts, errp); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 825 | if (ret < 0) { |
Kevin Wolf | 0b68589 | 2018-07-04 14:55:06 +0200 | [diff] [blame] | 826 | goto fail; |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 827 | } |
| 828 | |
Kevin Wolf | 91817e9 | 2023-01-26 18:24:22 +0100 | [diff] [blame] | 829 | bs = bdrv_co_open(filename, NULL, NULL, |
| 830 | BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 831 | if (!bs) { |
| 832 | ret = -EINVAL; |
| 833 | goto fail; |
| 834 | } |
| 835 | |
Hyman Huang | 35286da | 2024-01-30 13:37:23 +0800 | [diff] [blame] | 836 | if (detached_hdr) { |
| 837 | cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; |
| 838 | } |
| 839 | |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 840 | /* Create format layer */ |
Hyman Huang | d0112eb | 2024-01-30 13:37:22 +0800 | [diff] [blame] | 841 | ret = block_crypto_co_create_generic(bs, size, create_opts, |
Hyman Huang | 35286da | 2024-01-30 13:37:23 +0800 | [diff] [blame] | 842 | prealloc, cflags, errp); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 843 | if (ret < 0) { |
| 844 | goto fail; |
| 845 | } |
| 846 | |
| 847 | ret = 0; |
| 848 | fail: |
Daniel Henrique Barboza | 1bba30d | 2020-01-30 18:39:06 -0300 | [diff] [blame] | 849 | /* |
| 850 | * If an error occurred, delete 'filename'. Even if the file existed |
| 851 | * beforehand, it has been truncated and corrupted in the process. |
| 852 | */ |
Maxim Levitsky | a890f08 | 2020-12-17 19:09:03 +0200 | [diff] [blame] | 853 | if (ret) { |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 854 | bdrv_graph_co_rdlock(); |
Maxim Levitsky | a890f08 | 2020-12-17 19:09:03 +0200 | [diff] [blame] | 855 | bdrv_co_delete_file_noerr(bs); |
Kevin Wolf | 4db7ba3 | 2023-05-10 22:35:54 +0200 | [diff] [blame] | 856 | bdrv_graph_co_rdunlock(); |
Daniel Henrique Barboza | 1bba30d | 2020-01-30 18:39:06 -0300 | [diff] [blame] | 857 | } |
| 858 | |
Kevin Wolf | b2ab5f5 | 2023-05-04 13:57:33 +0200 | [diff] [blame] | 859 | bdrv_co_unref(bs); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 860 | qapi_free_QCryptoBlockCreateOptions(create_opts); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 861 | qobject_unref(cryptoopts); |
Kevin Wolf | 1ec4f41 | 2018-03-02 14:16:36 +0100 | [diff] [blame] | 862 | return ret; |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 863 | } |
| 864 | |
Emanuele Giuseppe Esposito | a00e70c | 2023-05-04 13:57:44 +0200 | [diff] [blame] | 865 | static int coroutine_fn GRAPH_RDLOCK |
Emanuele Giuseppe Esposito | 3d47eb0 | 2023-01-13 21:42:08 +0100 | [diff] [blame] | 866 | block_crypto_co_get_info_luks(BlockDriverState *bs, BlockDriverInfo *bdi) |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 867 | { |
| 868 | BlockDriverInfo subbdi; |
| 869 | int ret; |
| 870 | |
Emanuele Giuseppe Esposito | 3d47eb0 | 2023-01-13 21:42:08 +0100 | [diff] [blame] | 871 | ret = bdrv_co_get_info(bs->file->bs, &subbdi); |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 872 | if (ret != 0) { |
| 873 | return ret; |
| 874 | } |
| 875 | |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 876 | bdi->cluster_size = subbdi.cluster_size; |
| 877 | |
| 878 | return 0; |
| 879 | } |
| 880 | |
| 881 | static ImageInfoSpecific * |
Andrey Shinkevich | 1bf6e9c | 2019-02-08 18:06:06 +0300 | [diff] [blame] | 882 | block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 883 | { |
| 884 | BlockCrypto *crypto = bs->opaque; |
| 885 | ImageInfoSpecific *spec_info; |
| 886 | QCryptoBlockInfo *info; |
| 887 | |
Andrey Shinkevich | 1bf6e9c | 2019-02-08 18:06:06 +0300 | [diff] [blame] | 888 | info = qcrypto_block_get_info(crypto->block, errp); |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 889 | if (!info) { |
| 890 | return NULL; |
| 891 | } |
Markus Armbruster | d23d2ef | 2024-09-04 13:18:22 +0200 | [diff] [blame] | 892 | assert(info->format == QCRYPTO_BLOCK_FORMAT_LUKS); |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 893 | |
| 894 | spec_info = g_new(ImageInfoSpecific, 1); |
| 895 | spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS; |
| 896 | spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1); |
| 897 | *spec_info->u.luks.data = info->u.luks; |
| 898 | |
| 899 | /* Blank out pointers we've just stolen to avoid double free */ |
| 900 | memset(&info->u.luks, 0, sizeof(info->u.luks)); |
| 901 | |
| 902 | qapi_free_QCryptoBlockInfo(info); |
| 903 | |
| 904 | return spec_info; |
| 905 | } |
| 906 | |
Kevin Wolf | 3804e3c | 2023-09-11 11:46:12 +0200 | [diff] [blame] | 907 | static int GRAPH_RDLOCK |
Emanuele Giuseppe Esposito | c1019d1 | 2022-02-09 05:54:48 -0500 | [diff] [blame] | 908 | block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) |
| 909 | { |
| 910 | BlockCrypto *crypto = bs->opaque; |
| 911 | int ret; |
| 912 | |
| 913 | /* apply for exclusive read/write permissions to the underlying file */ |
| 914 | crypto->updating_keys = true; |
| 915 | ret = bdrv_child_refresh_perms(bs, bs->file, errp); |
| 916 | if (ret < 0) { |
| 917 | /* Well, in this case we will not be updating any keys */ |
| 918 | crypto->updating_keys = false; |
| 919 | } |
| 920 | return ret; |
| 921 | } |
| 922 | |
Kevin Wolf | 3804e3c | 2023-09-11 11:46:12 +0200 | [diff] [blame] | 923 | static void GRAPH_RDLOCK |
Emanuele Giuseppe Esposito | c1019d1 | 2022-02-09 05:54:48 -0500 | [diff] [blame] | 924 | block_crypto_amend_cleanup(BlockDriverState *bs) |
| 925 | { |
| 926 | BlockCrypto *crypto = bs->opaque; |
| 927 | Error *errp = NULL; |
| 928 | |
| 929 | /* release exclusive read/write permissions to the underlying file */ |
| 930 | crypto->updating_keys = false; |
| 931 | bdrv_child_refresh_perms(bs, bs->file, &errp); |
| 932 | |
| 933 | if (errp) { |
| 934 | error_report_err(errp); |
| 935 | } |
| 936 | } |
| 937 | |
| 938 | static int |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 939 | block_crypto_amend_options_generic_luks(BlockDriverState *bs, |
| 940 | QCryptoBlockAmendOptions *amend_options, |
| 941 | bool force, |
| 942 | Error **errp) |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 943 | { |
| 944 | BlockCrypto *crypto = bs->opaque; |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 945 | |
| 946 | assert(crypto); |
| 947 | assert(crypto->block); |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 948 | |
Emanuele Giuseppe Esposito | dae8492 | 2022-02-09 05:54:49 -0500 | [diff] [blame] | 949 | return qcrypto_block_amend_options(crypto->block, |
| 950 | block_crypto_read_func, |
| 951 | block_crypto_write_func, |
| 952 | bs, |
| 953 | amend_options, |
| 954 | force, |
| 955 | errp); |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 956 | } |
| 957 | |
Kevin Wolf | bd131d6 | 2023-09-29 16:51:48 +0200 | [diff] [blame] | 958 | static int GRAPH_RDLOCK |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 959 | block_crypto_amend_options_luks(BlockDriverState *bs, |
| 960 | QemuOpts *opts, |
| 961 | BlockDriverAmendStatusCB *status_cb, |
| 962 | void *cb_opaque, |
| 963 | bool force, |
| 964 | Error **errp) |
| 965 | { |
| 966 | BlockCrypto *crypto = bs->opaque; |
| 967 | QDict *cryptoopts = NULL; |
| 968 | QCryptoBlockAmendOptions *amend_options = NULL; |
| 969 | int ret = -EINVAL; |
| 970 | |
| 971 | assert(crypto); |
| 972 | assert(crypto->block); |
| 973 | |
| 974 | cryptoopts = qemu_opts_to_qdict(opts, NULL); |
| 975 | qdict_put_str(cryptoopts, "format", "luks"); |
| 976 | amend_options = block_crypto_amend_opts_init(cryptoopts, errp); |
| 977 | qobject_unref(cryptoopts); |
| 978 | if (!amend_options) { |
| 979 | goto cleanup; |
| 980 | } |
Emanuele Giuseppe Esposito | dae8492 | 2022-02-09 05:54:49 -0500 | [diff] [blame] | 981 | |
| 982 | ret = block_crypto_amend_prepare(bs, errp); |
| 983 | if (ret) { |
| 984 | goto perm_cleanup; |
| 985 | } |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 986 | ret = block_crypto_amend_options_generic_luks(bs, amend_options, |
| 987 | force, errp); |
Emanuele Giuseppe Esposito | dae8492 | 2022-02-09 05:54:49 -0500 | [diff] [blame] | 988 | |
| 989 | perm_cleanup: |
| 990 | block_crypto_amend_cleanup(bs); |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 991 | cleanup: |
| 992 | qapi_free_QCryptoBlockAmendOptions(amend_options); |
| 993 | return ret; |
| 994 | } |
| 995 | |
| 996 | static int |
| 997 | coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs, |
| 998 | BlockdevAmendOptions *opts, |
| 999 | bool force, |
| 1000 | Error **errp) |
| 1001 | { |
| 1002 | QCryptoBlockAmendOptions amend_opts; |
| 1003 | |
| 1004 | amend_opts = (QCryptoBlockAmendOptions) { |
Markus Armbruster | d23d2ef | 2024-09-04 13:18:22 +0200 | [diff] [blame] | 1005 | .format = QCRYPTO_BLOCK_FORMAT_LUKS, |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 1006 | .u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks), |
| 1007 | }; |
| 1008 | return block_crypto_amend_options_generic_luks(bs, &amend_opts, |
| 1009 | force, errp); |
| 1010 | } |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 1011 | |
| 1012 | static void |
| 1013 | block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c, |
| 1014 | const BdrvChildRole role, |
| 1015 | BlockReopenQueue *reopen_queue, |
| 1016 | uint64_t perm, uint64_t shared, |
| 1017 | uint64_t *nperm, uint64_t *nshared) |
| 1018 | { |
| 1019 | |
| 1020 | BlockCrypto *crypto = bs->opaque; |
| 1021 | |
| 1022 | bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); |
| 1023 | |
| 1024 | /* |
| 1025 | * For backward compatibility, manually share the write |
| 1026 | * and resize permission |
| 1027 | */ |
Maxim Levitsky | 662d0c5 | 2020-07-19 15:20:58 +0300 | [diff] [blame] | 1028 | *nshared |= shared & (BLK_PERM_WRITE | BLK_PERM_RESIZE); |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 1029 | /* |
| 1030 | * Since we are not fully a format driver, don't always request |
| 1031 | * the read/resize permission but only when explicitly |
| 1032 | * requested |
| 1033 | */ |
| 1034 | *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); |
| 1035 | *nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE); |
| 1036 | |
| 1037 | /* |
| 1038 | * This driver doesn't modify LUKS metadata except |
| 1039 | * when updating the encryption slots. |
| 1040 | * Thus unlike a proper format driver we don't ask for |
| 1041 | * shared write/read permission. However we need it |
| 1042 | * when we are updating the keys, to ensure that only we |
| 1043 | * have access to the device. |
| 1044 | * |
| 1045 | * Encryption update will set the crypto->updating_keys |
| 1046 | * during that period and refresh permissions |
| 1047 | * |
| 1048 | */ |
| 1049 | if (crypto->updating_keys) { |
| 1050 | /* need exclusive write access for header update */ |
| 1051 | *nperm |= BLK_PERM_WRITE; |
| 1052 | /* unshare read and write permission */ |
| 1053 | *nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE); |
| 1054 | } |
| 1055 | } |
| 1056 | |
| 1057 | |
Max Reitz | 2654267 | 2019-02-01 20:29:25 +0100 | [diff] [blame] | 1058 | static const char *const block_crypto_strong_runtime_opts[] = { |
| 1059 | BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, |
| 1060 | |
| 1061 | NULL |
| 1062 | }; |
| 1063 | |
Alberto Garcia | 782b9d0 | 2019-03-18 17:48:01 +0200 | [diff] [blame] | 1064 | static BlockDriver bdrv_crypto_luks = { |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 1065 | .format_name = "luks", |
| 1066 | .instance_size = sizeof(BlockCrypto), |
| 1067 | .bdrv_probe = block_crypto_probe_luks, |
| 1068 | .bdrv_open = block_crypto_open_luks, |
| 1069 | .bdrv_close = block_crypto_close, |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 1070 | .bdrv_child_perm = block_crypto_child_perms, |
Kevin Wolf | 1bedcaf | 2018-03-02 14:31:04 +0100 | [diff] [blame] | 1071 | .bdrv_co_create = block_crypto_co_create_luks, |
Stefan Hajnoczi | efc75e2 | 2018-01-18 13:43:45 +0100 | [diff] [blame] | 1072 | .bdrv_co_create_opts = block_crypto_co_create_opts_luks, |
Kevin Wolf | 061ca8a | 2018-06-21 17:54:35 +0200 | [diff] [blame] | 1073 | .bdrv_co_truncate = block_crypto_co_truncate, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 1074 | .create_opts = &block_crypto_create_opts_luks, |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 1075 | .amend_opts = &block_crypto_amend_opts_luks, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 1076 | |
Daniel P. Berrange | f87e08f | 2018-01-18 10:31:43 +0000 | [diff] [blame] | 1077 | .bdrv_reopen_prepare = block_crypto_reopen_prepare, |
Daniel P. Berrange | a73466f | 2017-09-27 13:53:38 +0100 | [diff] [blame] | 1078 | .bdrv_refresh_limits = block_crypto_refresh_limits, |
| 1079 | .bdrv_co_preadv = block_crypto_co_preadv, |
| 1080 | .bdrv_co_pwritev = block_crypto_co_pwritev, |
Emanuele Giuseppe Esposito | c86422c | 2023-01-13 21:42:04 +0100 | [diff] [blame] | 1081 | .bdrv_co_getlength = block_crypto_co_getlength, |
Stefan Hajnoczi | a9da6e4 | 2020-02-21 11:25:20 +0000 | [diff] [blame] | 1082 | .bdrv_measure = block_crypto_measure, |
Emanuele Giuseppe Esposito | 3d47eb0 | 2023-01-13 21:42:08 +0100 | [diff] [blame] | 1083 | .bdrv_co_get_info = block_crypto_co_get_info_luks, |
Daniel P. Berrange | c7c4cf4 | 2016-07-22 13:53:35 +0100 | [diff] [blame] | 1084 | .bdrv_get_specific_info = block_crypto_get_specific_info_luks, |
Maxim Levitsky | bbfdae9 | 2020-06-25 14:55:42 +0200 | [diff] [blame] | 1085 | .bdrv_amend_options = block_crypto_amend_options_luks, |
Maxim Levitsky | 30da9dd | 2020-06-25 14:55:46 +0200 | [diff] [blame] | 1086 | .bdrv_co_amend = block_crypto_co_amend_luks, |
Emanuele Giuseppe Esposito | c1019d1 | 2022-02-09 05:54:48 -0500 | [diff] [blame] | 1087 | .bdrv_amend_pre_run = block_crypto_amend_prepare, |
| 1088 | .bdrv_amend_clean = block_crypto_amend_cleanup, |
Max Reitz | 2654267 | 2019-02-01 20:29:25 +0100 | [diff] [blame] | 1089 | |
Max Reitz | d67066d | 2020-05-13 13:05:12 +0200 | [diff] [blame] | 1090 | .is_format = true, |
| 1091 | |
Max Reitz | 2654267 | 2019-02-01 20:29:25 +0100 | [diff] [blame] | 1092 | .strong_runtime_opts = block_crypto_strong_runtime_opts, |
Daniel P. Berrange | 7836857 | 2016-03-21 14:11:47 +0000 | [diff] [blame] | 1093 | }; |
| 1094 | |
| 1095 | static void block_crypto_init(void) |
| 1096 | { |
| 1097 | bdrv_register(&bdrv_crypto_luks); |
| 1098 | } |
| 1099 | |
| 1100 | block_init(block_crypto_init); |