Project

General

Profile

Actions

Bug #14400

closed

Snappy decompressor may assert when handling segmented input bufferlist

Added by Igor Fedotov over 8 years ago. Updated over 8 years ago.

Status:
Resolved
Priority:
Urgent
Assignee:
-
Category:
-
Target version:
-
% Done:

0%

Source:
other
Tags:
Backport:
Regression:
No
Severity:
3 - minor
Reviewed:
Affected Versions:
ceph-qa-suite:
Pull request ID:
Crash signature (v1):
Crash signature (v2):

Description

The issue may occur when the first data segment in an input bufferlist for SnappyCompressor::decompress call is less then 8 bytes.

The root cause is bufferlist::get_contiguous() method call that might invalidate bufferlist iterator initialized in BufferlistSource ctor:

class BufferlistSource : public snappy::Source {
list<bufferptr>::const_iterator pb;
...
public:
BufferlistSource(bufferlist &data): pb(data.buffers().begin()), pb_off(0), left(data.length()) {}

class SnappyCompressor : public Compressor {
...
virtual int decompress(bufferlist &src, bufferlist &dst) {
BufferlistSource source(src);
size_t res_len = 0;
// Trick, decompress only need first 32bits buffer
if (snappy::GetUncompressedLength(src.get_contiguous(0, 8), 8, &res_len))
return -1;
...

Following patch for snappy compressor UT demonstrates the issue:
diff --git a/src/test/compressor/test_compression_snappy.cc b/src/test/compressor/test_compression_snappy.cc
index 69b0ebf..6768136 100644
--- a/src/test/compressor/test_compression_snappy.cc
+++ b/src/test/compressor/test_compression_snappy.cc
@ -38,6 +38,39 @ TEST
EXPECT_EQ(res, 0);
}

TEST
{
+ const size_t small_prefix_size=3;

SnappyCompressor sp;
+ EXPECT_EQ(sp.get_method_name(), "snappy");
+ string test(128*1024,0);
+ int len = test.size();
+ bufferlist in, out;
+ in.append(test.c_str(), len);
+ int res = sp.compress(in, out);
+ EXPECT_EQ(res, 0);
+ EXPECT_GT(out.length(), 3u);
+
+ bufferlist out2, tmp;
+ const size_t small_prefix=3;
+ tmp.substr_of(out, 0, small_prefix_size );
+ out2.append( tmp );
+ size_t left = out.length()-small_prefix_size;
+ size_t offs = small_prefix;
+ while( left > 0 ){
+ size_t shard_size = MIN;
+ tmp.substr_of(out, offs, shard_size );
+ out2.append( tmp );
+ left -= shard_size;
+ offs = shard_size;
}

bufferlist after;
+ res = sp.decompress(out2, after);
+ EXPECT_EQ(res, 0);
}

int main(int argc, char *argv) {
vector<const char
> args;
argv_to_vec(argc, (const char **)argv, args);

Actions

Also available in: Atom PDF