Skip to content

Commit

Permalink
rgw: decrypt filter does not cross multipart boundaries
Browse files Browse the repository at this point in the history
multipart uploads with sse encrypts each part separately, using an
initialization vector based on the part offset

decryption must respect the same part boundaries, and start each part
with a fresh initialization vector. this means that the decrypt filter
must flush data up to part boundaries before starting the next

Fixes: http://tracker.ceph.com/issues/38700

Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit b782902)
  • Loading branch information
cbodley authored and theanalyst committed Apr 1, 2019
1 parent 64524b5 commit 67f2b9c
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 41 deletions.
83 changes: 50 additions & 33 deletions src/rgw/rgw_crypt.cc
Expand Up @@ -604,31 +604,47 @@ int RGWGetObj_BlockDecrypt::fixup_range(off_t& bl_ofs, off_t& bl_end) {
return 0;
}

int RGWGetObj_BlockDecrypt::process(bufferlist& in, size_t part_ofs, size_t size)
{
bufferlist data;
if (!crypt->decrypt(in, 0, size, data, part_ofs)) {
return -ERR_INTERNAL_ERROR;
}
off_t send_size = size - enc_begin_skip;
if (ofs + enc_begin_skip + send_size > end + 1) {
send_size = end + 1 - ofs - enc_begin_skip;
}
int res = next->handle_data(data, enc_begin_skip, send_size);
enc_begin_skip = 0;
ofs += size;
in.splice(0, size);
return res;
}

int RGWGetObj_BlockDecrypt::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) {
int res = 0;
ldout(cct, 25) << "Decrypt " << bl_len << " bytes" << dendl;
bl.copy(bl_ofs, bl_len, cache);

int res = 0;
size_t part_ofs = ofs;
size_t i = 0;
while (i<parts_len.size() && (part_ofs >= parts_len[i])) {
part_ofs -= parts_len[i];
i++;
for (size_t part : parts_len) {
if (part_ofs >= part) {
part_ofs -= part;
} else if (part_ofs + cache.length() >= part) {
// flush data up to part boundaries, aligned or not
res = process(cache, part_ofs, part - part_ofs);
if (res < 0) {
return res;
}
part_ofs = 0;
} else {
break;
}
}
bl.copy(bl_ofs, bl_len, cache);
// write up to block boundaries, aligned only
off_t aligned_size = cache.length() & ~(block_size - 1);
if (aligned_size > 0) {
bufferlist data;
if (! crypt->decrypt(cache, 0, aligned_size, data, part_ofs) ) {
return -ERR_INTERNAL_ERROR;
}
off_t send_size = aligned_size - enc_begin_skip;
if (ofs + enc_begin_skip + send_size > end + 1) {
send_size = end + 1 - ofs - enc_begin_skip;
}
res = next->handle_data(data, enc_begin_skip, send_size);
enc_begin_skip = 0;
ofs += aligned_size;
cache.splice(0, aligned_size);
res = process(cache, part_ofs, aligned_size);
}
return res;
}
Expand All @@ -637,25 +653,26 @@ int RGWGetObj_BlockDecrypt::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_l
* flush remainder of data to output
*/
int RGWGetObj_BlockDecrypt::flush() {
ldout(cct, 25) << "Decrypt flushing " << cache.length() << " bytes" << dendl;
int res = 0;
size_t part_ofs = ofs;
size_t i = 0;
while (i<parts_len.size() && (part_ofs > parts_len[i])) {
part_ofs -= parts_len[i];
i++;
for (size_t part : parts_len) {
if (part_ofs >= part) {
part_ofs -= part;
} else if (part_ofs + cache.length() >= part) {
// flush data up to part boundaries, aligned or not
res = process(cache, part_ofs, part - part_ofs);
if (res < 0) {
return res;
}
part_ofs = 0;
} else {
break;
}
}
// flush up to block boundaries, aligned or not
if (cache.length() > 0) {
bufferlist data;
if (! crypt->decrypt(cache, 0, cache.length(), data, part_ofs) ) {
return -ERR_INTERNAL_ERROR;
}
off_t send_size = cache.length() - enc_begin_skip;
if (ofs + enc_begin_skip + send_size > end + 1) {
send_size = end + 1 - ofs - enc_begin_skip;
}
res = next->handle_data(data, enc_begin_skip, send_size);
enc_begin_skip = 0;
ofs += send_size;
res = process(cache, part_ofs, cache.length());
}
return res;
}
Expand Down
2 changes: 2 additions & 0 deletions src/rgw/rgw_crypt.h
Expand Up @@ -94,6 +94,8 @@ class RGWGetObj_BlockDecrypt : public RGWGetObj_Filter {
bufferlist cache; /**< stores extra data that could not (yet) be processed by BlockCrypt */
size_t block_size; /**< snapshot of \ref BlockCrypt.get_block_size() */
std::vector<size_t> parts_len; /**< size of parts of multipart object, parsed from manifest */

int process(bufferlist& cipher, size_t part_ofs, size_t size);
public:
RGWGetObj_BlockDecrypt(CephContext* cct,
RGWGetObj_Filter* next,
Expand Down
13 changes: 5 additions & 8 deletions src/rgw/rgw_rest_s3.cc
Expand Up @@ -350,14 +350,11 @@ int RGWGetObj_ObjStore_S3::get_decrypt_filter(std::unique_ptr<RGWGetObj_Filter>
res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses);
if (res == 0) {
if (block_crypt != nullptr) {
auto f = std::unique_ptr<RGWGetObj_BlockDecrypt>(new RGWGetObj_BlockDecrypt(s->cct, cb, std::move(block_crypt)));
//RGWGetObj_BlockDecrypt* f = new RGWGetObj_BlockDecrypt(s->cct, cb, std::move(block_crypt));
if (f != nullptr) {
if (manifest_bl != nullptr) {
res = f->read_manifest(*manifest_bl);
if (res == 0) {
*filter = std::move(f);
}
auto f = std::make_unique<RGWGetObj_BlockDecrypt>(s->cct, cb, std::move(block_crypt));
if (manifest_bl != nullptr) {
res = f->read_manifest(*manifest_bl);
if (res == 0) {
*filter = std::move(f);
}
}
}
Expand Down

0 comments on commit 67f2b9c

Please sign in to comment.