* Mon Aug 18 2025 Miroslav Rezanina <mrezanin@redhat.com> - 10.0.0-11
- kvm-rbd-Fix-.bdrv_get_specific_info-implementation.patch [RHEL-105440] - Resolves: RHEL-105440 (Openstack guest becomes inaccessible via network when storage network on the hypervisor is disabled/lost [rhel-10.1])
This commit is contained in:
		
							parent
							
								
									87e30aa5d8
								
							
						
					
					
						commit
						b979eb91ef
					
				
							
								
								
									
										273
									
								
								kvm-rbd-Fix-.bdrv_get_specific_info-implementation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								kvm-rbd-Fix-.bdrv_get_specific_info-implementation.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,273 @@ | ||||
| From 1fe4e3379f5f3ae4e5554b18b4b8c50fedd9203f Mon Sep 17 00:00:00 2001 | ||||
| From: Kevin Wolf <kwolf@redhat.com> | ||||
| Date: Mon, 11 Aug 2025 15:40:10 +0200 | ||||
| Subject: [PATCH] rbd: Fix .bdrv_get_specific_info implementation | ||||
| 
 | ||||
| RH-Author: Kevin Wolf <kwolf@redhat.com> | ||||
| RH-MergeRequest: 399: rbd: Fix .bdrv_get_specific_info implementation | ||||
| RH-Jira: RHEL-105440 | ||||
| RH-Acked-by: Hanna Czenczek <hreitz@redhat.com> | ||||
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> | ||||
| RH-Commit: [1/1] 840c954c84c97f768ae6cfb4aa0e2766b22a6f06 (kmwolf/centos-qemu-kvm) | ||||
| 
 | ||||
| qemu_rbd_get_specific_info() has at least two problems: | ||||
| 
 | ||||
| The first is that it issues a blocking rbd_read() call in order to probe | ||||
| the encryption format for the image while querying the node. This means | ||||
| that if the connection to the server goes down, not only I/O is stuck | ||||
| (which is unavoidable), but query-names-block-nodes will actually make | ||||
| the whole QEMU instance unresponsive. .bdrv_get_specific_info | ||||
| implementations shouldn't perform blocking operations, but only return | ||||
| what is already known. | ||||
| 
 | ||||
| The second is that the information returned isn't even correct. If the | ||||
| image is already opened with encryption enabled at the RBD level, we'll | ||||
| probe for "double encryption", i.e. if the encrypted data contains | ||||
| another encryption header. If it doesn't (which is the normal case), we | ||||
| won't return the encryption format. If it does, we return misleading | ||||
| information because it looks like we're talking about the outer level | ||||
| (the encryption format of the image itself) while the information is | ||||
| about an encryption header in the guest data. | ||||
| 
 | ||||
| Fix this by storing the encryption format in BDRVRBDState when the image | ||||
| is opened (and we do blocking operations anyway) and returning only the | ||||
| stored information in qemu_rbd_get_specific_info(). | ||||
| 
 | ||||
| The information we'll store is either the actual encryption format that | ||||
| we enabled on the RBD level, or if the image is unencrypted, the result | ||||
| of the same probing as we previously did when querying the node. Probing | ||||
| image formats based on content that can be modified by the guest has | ||||
| long been known as problematic, but as long as we only output it to the | ||||
| user instead of making decisions based on it, it should be okay. It is | ||||
| undoubtedly useful in the context of 'qemu-img info' when you're trying | ||||
| to figure out which encryption options you have to use to open the | ||||
| image successfully. | ||||
| 
 | ||||
| Fixes: 42e4ac9ef5a6 ("block/rbd: Add support for rbd image encryption") | ||||
| Buglink: https://issues.redhat.com/browse/RHEL-105440 | ||||
| Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||||
| Message-ID: <20250811134010.81787-1-kwolf@redhat.com> | ||||
| Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | ||||
| Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||||
| (cherry picked from commit 4af976ef398e4e823addc00bf1c58787ba4952fe) | ||||
| Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||||
| ---
 | ||||
|  block/rbd.c          | 104 ++++++++++++++++++++++++++++--------------- | ||||
|  qapi/block-core.json |   9 +++- | ||||
|  2 files changed, 76 insertions(+), 37 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/rbd.c b/block/rbd.c
 | ||||
| index 4f3d42a8e7..9b7b834f04 100644
 | ||||
| --- a/block/rbd.c
 | ||||
| +++ b/block/rbd.c
 | ||||
| @@ -99,6 +99,14 @@ typedef struct BDRVRBDState {
 | ||||
|      char *namespace; | ||||
|      uint64_t image_size; | ||||
|      uint64_t object_size; | ||||
| +
 | ||||
| +    /*
 | ||||
| +     * If @bs->encrypted is true, this is the encryption format actually loaded
 | ||||
| +     * at the librbd level. If it is false, it is the result of probing.
 | ||||
| +     * RBD_IMAGE_ENCRYPTION_FORMAT__MAX means that encryption is not enabled and
 | ||||
| +     * probing didn't find any known encryption header either.
 | ||||
| +     */
 | ||||
| +    RbdImageEncryptionFormat encryption_format;
 | ||||
|  } BDRVRBDState; | ||||
|   | ||||
|  typedef struct RBDTask { | ||||
| @@ -471,10 +479,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
| -static int qemu_rbd_encryption_load(rbd_image_t image,
 | ||||
| +static int qemu_rbd_encryption_load(BlockDriverState *bs,
 | ||||
| +                                    rbd_image_t image,
 | ||||
|                                      RbdEncryptionOptions *encrypt, | ||||
|                                      Error **errp) | ||||
|  { | ||||
| +    BDRVRBDState *s = bs->opaque;
 | ||||
|      int r = 0; | ||||
|      g_autofree char *passphrase = NULL; | ||||
|      rbd_encryption_luks1_format_options_t luks_opts; | ||||
| @@ -545,15 +555,19 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 | ||||
|          error_setg_errno(errp, -r, "encryption load fail"); | ||||
|          return r; | ||||
|      } | ||||
| +    bs->encrypted = true;
 | ||||
| +    s->encryption_format = encrypt->format;
 | ||||
|   | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
|  #ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 | ||||
| -static int qemu_rbd_encryption_load2(rbd_image_t image,
 | ||||
| +static int qemu_rbd_encryption_load2(BlockDriverState *bs,
 | ||||
| +                                     rbd_image_t image,
 | ||||
|                                       RbdEncryptionOptions *encrypt, | ||||
|                                       Error **errp) | ||||
|  { | ||||
| +    BDRVRBDState *s = bs->opaque;
 | ||||
|      int r = 0; | ||||
|      int encrypt_count = 1; | ||||
|      int i; | ||||
| @@ -639,6 +653,8 @@ static int qemu_rbd_encryption_load2(rbd_image_t image,
 | ||||
|          error_setg_errno(errp, -r, "layered encryption load fail"); | ||||
|          goto exit; | ||||
|      } | ||||
| +    bs->encrypted = true;
 | ||||
| +    s->encryption_format = encrypt->format;
 | ||||
|   | ||||
|  exit: | ||||
|      for (i = 0; i < encrypt_count; ++i) { | ||||
| @@ -672,6 +688,45 @@ exit:
 | ||||
|  #endif | ||||
|  #endif | ||||
|   | ||||
| +/*
 | ||||
| + * For an image without encryption enabled on the rbd layer, probe the start of
 | ||||
| + * the image if it could be opened as an encrypted image so that we can display
 | ||||
| + * it when the user queries the node (most importantly in qemu-img).
 | ||||
| + *
 | ||||
| + * If the guest writes an encryption header to its disk after this probing, this
 | ||||
| + * won't be reflected when queried, but that's okay. There is no reason why the
 | ||||
| + * user should want to apply encryption at the rbd level while the image is
 | ||||
| + * still in use. This is just guest data.
 | ||||
| + */
 | ||||
| +static void qemu_rbd_encryption_probe(BlockDriverState *bs)
 | ||||
| +{
 | ||||
| +    BDRVRBDState *s = bs->opaque;
 | ||||
| +    char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
 | ||||
| +    int r;
 | ||||
| +
 | ||||
| +    assert(s->encryption_format == RBD_IMAGE_ENCRYPTION_FORMAT__MAX);
 | ||||
| +
 | ||||
| +    r = rbd_read(s->image, 0,
 | ||||
| +                 RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
 | ||||
| +    if (r < RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
 | ||||
| +        return;
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (memcmp(buf, rbd_luks_header_verification,
 | ||||
| +               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| +        s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
 | ||||
| +    } else if (memcmp(buf, rbd_luks2_header_verification,
 | ||||
| +               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| +        s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
 | ||||
| +    } else if (memcmp(buf, rbd_layered_luks_header_verification,
 | ||||
| +               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| +        s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
 | ||||
| +    } else if (memcmp(buf, rbd_layered_luks2_header_verification,
 | ||||
| +               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| +        s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
 | ||||
| +    }
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* FIXME Deprecate and remove keypairs or make it available in QMP. */ | ||||
|  static int qemu_rbd_do_create(BlockdevCreateOptions *options, | ||||
|                                const char *keypairs, const char *password_secret, | ||||
| @@ -1134,17 +1189,18 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
|          goto failed_open; | ||||
|      } | ||||
|   | ||||
| +    s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT__MAX;
 | ||||
|      if (opts->encrypt) { | ||||
|  #ifdef LIBRBD_SUPPORTS_ENCRYPTION | ||||
|          if (opts->encrypt->parent) { | ||||
|  #ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 | ||||
| -            r = qemu_rbd_encryption_load2(s->image, opts->encrypt, errp);
 | ||||
| +            r = qemu_rbd_encryption_load2(bs, s->image, opts->encrypt, errp);
 | ||||
|  #else | ||||
|              r = -ENOTSUP; | ||||
|              error_setg(errp, "RBD library does not support layered encryption"); | ||||
|  #endif | ||||
|          } else { | ||||
| -            r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
 | ||||
| +            r = qemu_rbd_encryption_load(bs, s->image, opts->encrypt, errp);
 | ||||
|          } | ||||
|          if (r < 0) { | ||||
|              goto failed_post_open; | ||||
| @@ -1154,6 +1210,8 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
|          error_setg(errp, "RBD library does not support image encryption"); | ||||
|          goto failed_post_open; | ||||
|  #endif | ||||
| +    } else {
 | ||||
| +        qemu_rbd_encryption_probe(bs);
 | ||||
|      } | ||||
|   | ||||
|      r = rbd_stat(s->image, &info, sizeof(info)); | ||||
| @@ -1413,17 +1471,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
 | ||||
|  { | ||||
|      BDRVRBDState *s = bs->opaque; | ||||
|      ImageInfoSpecific *spec_info; | ||||
| -    char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
 | ||||
| -    int r;
 | ||||
| -
 | ||||
| -    if (s->image_size >= RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
 | ||||
| -        r = rbd_read(s->image, 0,
 | ||||
| -                     RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
 | ||||
| -        if (r < 0) {
 | ||||
| -            error_setg_errno(errp, -r, "cannot read image start for probe");
 | ||||
| -            return NULL;
 | ||||
| -        }
 | ||||
| -    }
 | ||||
|   | ||||
|      spec_info = g_new(ImageInfoSpecific, 1); | ||||
|      *spec_info = (ImageInfoSpecific){ | ||||
| @@ -1431,28 +1478,13 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
 | ||||
|          .u.rbd.data = g_new0(ImageInfoSpecificRbd, 1), | ||||
|      }; | ||||
|   | ||||
| -    if (memcmp(buf, rbd_luks_header_verification,
 | ||||
| -               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| -        spec_info->u.rbd.data->encryption_format =
 | ||||
| -                RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
 | ||||
| -        spec_info->u.rbd.data->has_encryption_format = true;
 | ||||
| -    } else if (memcmp(buf, rbd_luks2_header_verification,
 | ||||
| -               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| -        spec_info->u.rbd.data->encryption_format =
 | ||||
| -                RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
 | ||||
| -        spec_info->u.rbd.data->has_encryption_format = true;
 | ||||
| -    } else if (memcmp(buf, rbd_layered_luks_header_verification,
 | ||||
| -               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| -        spec_info->u.rbd.data->encryption_format =
 | ||||
| -                RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
 | ||||
| -        spec_info->u.rbd.data->has_encryption_format = true;
 | ||||
| -    } else if (memcmp(buf, rbd_layered_luks2_header_verification,
 | ||||
| -               RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
 | ||||
| -        spec_info->u.rbd.data->encryption_format =
 | ||||
| -                RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
 | ||||
| -        spec_info->u.rbd.data->has_encryption_format = true;
 | ||||
| +    if (s->encryption_format == RBD_IMAGE_ENCRYPTION_FORMAT__MAX) {
 | ||||
| +        assert(!bs->encrypted);
 | ||||
|      } else { | ||||
| -        spec_info->u.rbd.data->has_encryption_format = false;
 | ||||
| +        ImageInfoSpecificRbd *rbd_info = spec_info->u.rbd.data;
 | ||||
| +
 | ||||
| +        rbd_info->has_encryption_format = true;
 | ||||
| +        rbd_info->encryption_format = s->encryption_format;
 | ||||
|      } | ||||
|   | ||||
|      return spec_info; | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 7f70ec6d3c..d00161af87 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -158,7 +158,14 @@
 | ||||
|  ## | ||||
|  # @ImageInfoSpecificRbd: | ||||
|  # | ||||
| -# @encryption-format: Image encryption format
 | ||||
| +# @encryption-format: Image encryption format. If encryption is enabled for the
 | ||||
| +#     image (see encrypted in BlockNodeInfo), this is the actual format in which the
 | ||||
| +#     image is accessed. If encryption is not enabled, this is the result of
 | ||||
| +#     probing when the image was opened, to give a suggestion which encryption
 | ||||
| +#     format could be enabled. Note that probing results can be changed by the
 | ||||
| +#     guest by writing a (possibly partial) encryption format header to the
 | ||||
| +#     image, so don't treat this information as trusted if the guest is not
 | ||||
| +#     trusted.
 | ||||
|  # | ||||
|  # Since: 6.1 | ||||
|  ## | ||||
| -- 
 | ||||
| 2.39.3 | ||||
| 
 | ||||
| @ -143,7 +143,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version}                    \ | ||||
| Summary: QEMU is a machine emulator and virtualizer | ||||
| Name: qemu-kvm | ||||
| Version: 10.0.0 | ||||
| Release: 10%{?rcrel}%{?dist}%{?cc_suffix} | ||||
| Release: 11%{?rcrel}%{?dist}%{?cc_suffix} | ||||
| # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped | ||||
| # Epoch 15 used for RHEL 8 | ||||
| # Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5) | ||||
| @ -418,6 +418,8 @@ Patch127: kvm-iotests-graph-changes-while-io-add-test-case-with-re.patch | ||||
| Patch128: kvm-Declare-rtl8139-as-deprecated.patch | ||||
| # For RHEL-102325 - [qemu] enable variable service for edk2 | ||||
| Patch129: kvm-Enable-uefi-variable-service-for-edk2.patch | ||||
| # For RHEL-105440 - Openstack guest becomes inaccessible via network when storage network on the hypervisor is disabled/lost [rhel-10.1] | ||||
| Patch130: kvm-rbd-Fix-.bdrv_get_specific_info-implementation.patch | ||||
| 
 | ||||
| %if %{have_clang} | ||||
| BuildRequires: clang | ||||
| @ -1500,6 +1502,11 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ | ||||
| %endif | ||||
| 
 | ||||
| %changelog | ||||
| * Mon Aug 18 2025 Miroslav Rezanina <mrezanin@redhat.com> - 10.0.0-11 | ||||
| - kvm-rbd-Fix-.bdrv_get_specific_info-implementation.patch [RHEL-105440] | ||||
| - Resolves: RHEL-105440 | ||||
|   (Openstack guest becomes inaccessible via network when storage network on the hypervisor is disabled/lost [rhel-10.1]) | ||||
| 
 | ||||
| * Tue Aug 12 2025 Miroslav Rezanina <mrezanin@redhat.com> - 10.0.0-10 | ||||
| - kvm-Enable-uefi-variable-service-for-edk2.patch [RHEL-102325] | ||||
| - Resolves: RHEL-102325 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user