From d61004d5ba661ffd13e517064f3a079d1fe25853 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Wed, 28 Jun 2023 17:14:16 -0400 Subject: [PATCH] rgw: fetch_remote_obj() preserves original part lengths for BlockDecrypt because multisite replicates multipart objects as a single part, we lose information about the part sizes from the original manifest that is necessary to correctly decrypt across those part boundaries on replication, parse the part lengths out of the source object's manifest, and store them in a separate RGW_ATTR_CRYPT_PARTS for use on decryption Fixes: https://tracker.ceph.com/issues/46062 Signed-off-by: Casey Bodley (cherry picked from commit e7d98fb36994559b08bf0e2273d333d8fc125886) --- src/rgw/driver/rados/rgw_rados.cc | 18 +++++++++++++ src/rgw/rgw_common.h | 1 + src/rgw/rgw_rest_s3.cc | 44 +++++++++++++++++++++++++------ 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/rgw/driver/rados/rgw_rados.cc b/src/rgw/driver/rados/rgw_rados.cc index df334e99e3998..c7100af4bb626 100644 --- a/src/rgw/driver/rados/rgw_rados.cc +++ b/src/rgw/driver/rados/rgw_rados.cc @@ -45,6 +45,7 @@ #include "rgw_tools.h" #include "rgw_coroutine.h" #include "rgw_compression.h" +#include "rgw_crypt.h" #include "rgw_etag_verifier.h" #include "rgw_worker.h" #include "rgw_notify.h" @@ -3417,11 +3418,28 @@ public: } } } + /* We need the manifest to recompute the ETag for verification */ iter = src_attrs.find(RGW_ATTR_MANIFEST); if (iter != src_attrs.end()) { manifest_bl = std::move(iter->second); src_attrs.erase(iter); + + // if the source object was encrypted, preserve the original object's + // part lengths + if (src_attrs.count(RGW_ATTR_CRYPT_MODE)) { + std::vector parts_len; + int r = RGWGetObj_BlockDecrypt::read_manifest_parts(dpp, manifest_bl, + parts_len); + if (r < 0) { + ldpp_dout(dpp, 4) << "failed to read part lengths from the manifest" << dendl; + } else { + // store the encoded part lenghts in RGW_ATTR_CRYPT_PARTS + bufferlist parts_bl; + encode(parts_len, parts_bl); + src_attrs[RGW_ATTR_CRYPT_PARTS] = std::move(parts_bl); + } + } } // filter out olh attributes diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index d0bd47253a847..43c0a60af8aa5 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -161,6 +161,7 @@ using ceph::crypto::MD5; #define RGW_ATTR_CRYPT_KEYSEL RGW_ATTR_CRYPT_PREFIX "keysel" #define RGW_ATTR_CRYPT_CONTEXT RGW_ATTR_CRYPT_PREFIX "context" #define RGW_ATTR_CRYPT_DATAKEY RGW_ATTR_CRYPT_PREFIX "datakey" +#define RGW_ATTR_CRYPT_PARTS RGW_ATTR_CRYPT_PREFIX "part-lengths" /* SSE-S3 Encryption Attributes */ #define RGW_ATTR_BUCKET_ENCRYPTION_PREFIX RGW_ATTR_PREFIX "sse-s3." diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 97f2c261ea334..497afc19d5d96 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -604,10 +604,24 @@ int RGWGetObj_ObjStore_S3::get_decrypt_filter(std::unique_ptr // in case of a multipart upload, we need to know the part lengths to // correctly decrypt across part boundaries std::vector parts_len; - res = RGWGetObj_BlockDecrypt::read_manifest_parts(this, *manifest_bl, - parts_len); - if (res < 0) { - return res; + + // for replicated objects, the original part lengths are preserved in an xattr + if (auto i = attrs.find(RGW_ATTR_CRYPT_PARTS); i != attrs.end()) { + try { + auto p = i->second.cbegin(); + using ceph::decode; + decode(parts_len, p); + } catch (const buffer::error&) { + ldpp_dout(this, 1) << "failed to decode RGW_ATTR_CRYPT_PARTS" << dendl; + return -EIO; + } + } else { + // otherwise, we read the part lengths from the manifest + res = RGWGetObj_BlockDecrypt::read_manifest_parts(this, *manifest_bl, + parts_len); + if (res < 0) { + return res; + } } *filter = std::make_unique( @@ -2763,10 +2777,24 @@ int RGWPutObj_ObjStore_S3::get_decrypt_filter( // in case of a multipart upload, we need to know the part lengths to // correctly decrypt across part boundaries std::vector parts_len; - res = RGWGetObj_BlockDecrypt::read_manifest_parts(this, *manifest_bl, - parts_len); - if (res < 0) { - return res; + + // for replicated objects, the original part lengths are preserved in an xattr + if (auto i = attrs.find(RGW_ATTR_CRYPT_PARTS); i != attrs.end()) { + try { + auto p = i->second.cbegin(); + using ceph::decode; + decode(parts_len, p); + } catch (const buffer::error&) { + ldpp_dout(this, 1) << "failed to decode RGW_ATTR_CRYPT_PARTS" << dendl; + return -EIO; + } + } else { + // otherwise, we read the part lengths from the manifest + res = RGWGetObj_BlockDecrypt::read_manifest_parts(this, *manifest_bl, + parts_len); + if (res < 0) { + return res; + } } *filter = std::make_unique( -- 2.39.5