From: Casey Bodley Date: Fri, 22 Mar 2019 13:57:33 +0000 (-0400) Subject: rgw: decrypt filter does not cross multipart boundaries X-Git-Tag: v13.2.6~100^2~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=67f2b9cf8d93526a17a140f67297b79c46682db5;p=ceph.git rgw: decrypt filter does not cross multipart boundaries 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 (cherry picked from commit b782902954abd20e49c0ed1c14cebee4c8ab6f88) --- diff --git a/src/rgw/rgw_crypt.cc b/src/rgw/rgw_crypt.cc index 3516db5847079..5cdeff86c4a57 100644 --- a/src/rgw/rgw_crypt.cc +++ b/src/rgw/rgw_crypt.cc @@ -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[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; } @@ -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[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; } diff --git a/src/rgw/rgw_crypt.h b/src/rgw/rgw_crypt.h index db88d835ec056..6311c66fd72f7 100644 --- a/src/rgw/rgw_crypt.h +++ b/src/rgw/rgw_crypt.h @@ -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 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, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index efed2da0b245e..b78f6d367c1b6 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -350,14 +350,11 @@ int RGWGetObj_ObjStore_S3::get_decrypt_filter(std::unique_ptr res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses); if (res == 0) { if (block_crypt != nullptr) { - auto f = std::unique_ptr(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(s->cct, cb, std::move(block_crypt)); + if (manifest_bl != nullptr) { + res = f->read_manifest(*manifest_bl); + if (res == 0) { + *filter = std::move(f); } } }