Project

General

Profile

Actions

Bug #13713

closed

Ceph CRC32 algorithm appears broken

Added by Chris Holcombe over 8 years ago. Updated over 8 years ago.

Status:
Rejected
Priority:
High
Assignee:
-
Category:
-
Target version:
-
% Done:

0%

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

Description

I was looking at wireshark packets and I wanted to see if I could verify the crc checksums that Ceph is generating and receiving. The code shows that Ceph is using the castagnoli crc32 variant. I wasn't able to reproduce the checksum so I fell back to looking at Ceph's unit tests and tried to reproduce this: https://github.com/ceph/ceph/blob/master/src/test/common/test_crc32c.cc#L21

I have example code here in Rust: https://gist.github.com/cholcombe973/b0846a814be0a9e885f8
and in Python that produce different results: https://gist.github.com/cholcombe973/a0af818d212e58ae151c

Is the unit test for this file using generated output from the crc32 algorithm in the code base or a known good hash?

I'm guessing I am doing something wrong here but I'm not entirely sure what.

Actions #1

Updated by Nathan Cutler over 8 years ago

  • Tracker changed from Tasks to Bug
  • Project changed from Stable releases to Ceph
Actions #2

Updated by Chris Holcombe over 8 years ago

I found a mailing list showing a known good crc for castagnoli: http://www.pdl.cmu.edu/mailinglists/ips/mail/msg04970.html
The crc's he gives there works with the Rust + Python libraries. I believe now that the rust and python libraries are correct. I still can't figure out how to reproduce ceph's crc values.

I also updated my rust example: https://play.rust-lang.org/?gist=6bca7e3630d48f9225e5&version=stable
It now initializes the crc algorithm with 0 just like Ceph does.

Actions #3

Updated by Chris Holcombe over 8 years ago

Chris Holcombe wrote:

I found a mailing list showing a known good crc for castagnoli: http://www.pdl.cmu.edu/mailinglists/ips/mail/msg04970.html
The crc's he gives there works with the Rust + Python libraries. I believe now that the rust and python libraries are correct. I still can't figure out how to reproduce ceph's crc values.

I also updated my rust example: https://play.rust-lang.org/?gist=3e51845d5541002da559&version=stable
It now initializes the crc algorithm with 0 just like Ceph does.

Actions #4

Updated by Chris Holcombe over 8 years ago

I'm almost sure at this point that the ceph crc calculation is incorrect.

I wrote a short C program utilizing the intel baseline code https://github.com/ceph/ceph/blob/master/src/common/crc32c_intel_baseline.c that sage told me to try out. The intel baseline code is producing crc's that disagree with what Mark Bakke <> says is the known good hash for 32 bytes of 00h.

I also tried another python library which 1) agree's with my previous rust/python findings and 2) disagrees with Ceph's crc calculation: https://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/files/crc32c.py?r=170

Actions #5

Updated by Chris Holcombe over 8 years ago

Here's a code snippet of python using google's crc32c python library https://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/files/crc32c.py?r=170

>>> import crc
>>> x = [0 for x in range(0,32)]
>>> x
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> len(x)
32
>>> crc.crc(x)
2324772522L

That crc agrees with the mailing list and disagrees with Ceph's crc
Actions #6

Updated by Dan van der Ster over 8 years ago

I checked the partial crc after each iteration in google's python implementation and found that the crc of the last iteration matches ceph's [1]:

from crc32c import crc
crc('foo bar baz')

crc 1197962378
crc 3599162226
crc 2946501991
crc 2501826906
crc 3132034983
crc 3851841059
crc 2745946046
crc 1047783679
crc 767476524
crc 4269731756
crc 4119623852

After finalize (crc ^ 0xFFFFFFFF) the crc becomes:

175343443L

So it looks like ceph_crc32c just isn't doing that final XOR step.

4119623852 ^ 0xFFFFFFFF

175343443

[1] From test_crc32c.cc

const char *a = "foo bar baz";
ASSERT_EQ(4119623852u, ceph_crc32c(0, (unsigned char *)a, strlen(a)));

Actions #7

Updated by Dan van der Ster over 8 years ago

(Sorry for the formatting on the last message -- I think it's readable anyway).

I read some more and found that crc32 implementations vary whether they xor the output with ~0. Linux's approach matches Ceph's -- don't XOR the output -- let the user decide. See https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/lib/crc32.c#n15

 * There are various incantations of crc32().  Some use a seed of 0 or ~0.
 * Some xor at the end with ~0.  The generic crc32() function takes
 * seed as an argument, and doesn't xor at the end.  Then individual
 * users can do whatever they need.
 *   drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
 *   fs/jffs2 uses seed 0, doesn't xor with ~0.
 *   fs/partitions/efi.c uses seed ~0, xor's with ~0.

Also, iscsi itself seems not to xor the output: https://github.com/radii/fio/blob/master/crc/crc32c.c#L123

Actions #8

Updated by Chris Holcombe over 8 years ago

Thanks! This was exactly the answer I was hoping for. I thought I might be missing something but I couldn't quite figure out what. Maybe I'll submit a pull request to the developer docs to make it more clear what is going on and why it's not obvious how to reproduce the crc hash.

Actions #9

Updated by Sage Weil over 8 years ago

  • Status changed from New to Rejected
Actions

Also available in: Atom PDF