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 <cbodley@redhat.com>
This commit is contained in:
Casey Bodley 2023-06-28 17:14:16 -04:00
parent d8a82f5aaa
commit e7d98fb369
3 changed files with 55 additions and 8 deletions

View File

@ -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"
@ -3426,11 +3427,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<size_t> 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

View File

@ -162,6 +162,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."

View File

@ -605,10 +605,24 @@ int RGWGetObj_ObjStore_S3::get_decrypt_filter(std::unique_ptr<RGWGetObj_Filter>
// in case of a multipart upload, we need to know the part lengths to
// correctly decrypt across part boundaries
std::vector<size_t> 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<RGWGetObj_BlockDecrypt>(
@ -2764,10 +2778,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<size_t> 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<RGWGetObj_BlockDecrypt>(