From b60d8cf0cbe56500af98b3d3857245e94d904b19 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 2 Oct 2017 17:28:04 -0400 Subject: [PATCH] osd: additional protection for out-of-bounds EC reads Fixes: http://tracker.ceph.com/issues/21629 Signed-off-by: Jason Dillaman (cherry picked from commit 881f2a02aecef0cd6bf8ec3e5045b76c8441e832) --- src/osd/PrimaryLogPG.cc | 19 +++++++++++++++++-- src/test/librados/misc.cc | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/osd/PrimaryLogPG.cc b/src/osd/PrimaryLogPG.cc index c079c1b1fc314..32ef1ed885a26 100644 --- a/src/osd/PrimaryLogPG.cc +++ b/src/osd/PrimaryLogPG.cc @@ -4716,13 +4716,28 @@ int PrimaryLogPG::do_extent_cmp(OpContext *ctx, OSDOp& osd_op) dout(20) << __func__ << dendl; ceph_osd_op& op = osd_op.op; - if (!ctx->obs->exists || ctx->obs->oi.is_whiteout()) { + auto& oi = ctx->new_obs.oi; + uint64_t size = oi.size; + if ((oi.truncate_seq < op.extent.truncate_seq) && + (op.extent.offset + op.extent.length > op.extent.truncate_size)) { + size = op.extent.truncate_size; + } + + if (op.extent.offset >= size) { + op.extent.length = 0; + } else if (op.extent.offset + op.extent.length > size) { + op.extent.length = size - op.extent.offset; + } + + if (op.extent.length == 0) { + dout(20) << __func__ << " zero length extent" << dendl; + return finish_extent_cmp(osd_op, bufferlist{}); + } else if (!ctx->obs->exists || ctx->obs->oi.is_whiteout()) { dout(20) << __func__ << " object DNE" << dendl; return finish_extent_cmp(osd_op, {}); } else if (pool.info.require_rollback()) { // If there is a data digest and it is possible we are reading // entire object, pass the digest. - auto& oi = ctx->new_obs.oi; boost::optional maybe_crc; if (oi.is_data_digest() && op.checksum.offset == 0 && op.checksum.length >= oi.size) { diff --git a/src/test/librados/misc.cc b/src/test/librados/misc.cc index ea4d3e713e7ac..f7ce348b0a0f8 100644 --- a/src/test/librados/misc.cc +++ b/src/test/librados/misc.cc @@ -28,6 +28,7 @@ using std::string; typedef RadosTest LibRadosMisc; typedef RadosTestPP LibRadosMiscPP; +typedef RadosTestECPP LibRadosMiscECPP; TEST(LibRadosMiscVersion, Version) { int major, minor, extra; @@ -1356,3 +1357,24 @@ TEST_F(LibRadosMiscPP, Applications) { ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta)); ASSERT_EQ(expected_meta, meta); } + +TEST_F(LibRadosMiscECPP, CompareExtentRange) { + bufferlist bl1; + bl1.append("ceph"); + ObjectWriteOperation write; + write.write(0, bl1); + ASSERT_EQ(0, ioctx.operate("foo", &write)); + + bufferlist bl2; + bl2.append("ph"); + bl2.append(std::string(2, '\0')); + ObjectReadOperation read1; + read1.cmpext(2, bl2, nullptr); + ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr)); + + bufferlist bl3; + bl3.append(std::string(4, '\0')); + ObjectReadOperation read2; + read2.cmpext(2097152, bl3, nullptr); + ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr)); +} -- 2.39.5