Decode segfault with certain corrupted shares

Issue #21 open
Sudarshan Muralidhar created an issue
from pyeclib.ec_iface import ECDriver

shares  = ['G\x00\xde\x00\x10\x00\x00\x00\x00\x00\x83\x00,\x00)\x00\x00\x00\x0e\x00\x01\x00\x00\x00\xe4\x00\x00\x00\x00\x00~\x00\x00\x00\x85\x00\x00\x00\xfb\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00|\x00s\x00}\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x000\x00\x00\x00\xa4\x00\x14\x00\x00\x002\x00\xea\x00\xdca\xca7\xa1\xf5\x11\xba\x1e\xe3\x10\x86', '\x01\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)f\xd7c\x90.\xa7\xb4\x1d\xcd,q\xee\x03S\x03', '\x02\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xf3|\x13x\x90Uga\x83\xde\x81\x00\x00\x00\x00', '\x03\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\xb5\x1e\x014\xdf8\xe4\xdd\xbb\xe3J\xf0\xe0C\x85', '\x04\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\xfa\x18\xbcd>\xc7\x9f\xc1\x06a\x1b\xfd\xfeY\xc8']
shares2 = ['\x00\x00\xdf\x00\x10\x00\x00\x00\x00\x00s\x00,\x00\x00\x00H\x00\xae\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\x00\x00F\x00\xa1\x00\x1b\x00\x00\x00\xc0\x00\x00\x00\x00\x001\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\x00\\\x00,bv\xb3\xd7\xf8\xcf\x00w\xd0N\x00', '\x01\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xc9\xc6\x8c\x87-\x04.t\xea\x94\x8a;\x984\xe4', '\x02\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\xb9\xc4\xc6\x05|!\xf3$\xda\x19V\x00\x00\x00\x00', '\x03\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99s^Y\xae3Sn\x87\xc8\xca LH0t', '\x04\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x01\x00\xcc^\x0c\x0b\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x9d\xe6r\x94{3\x89\xe5\xa3\x1b\xb7%s\x9cQ']

ec_driver = ECDriver(k=3, m=2, ec_type='liberasurecode_rs_vand')
print ec_driver.decode(shares2)

This segfaults on decode, for both shares and shares2. These share lists were generated by encoding with the same ec_driver, and corrupting a few bytes. I'd expect the library to raise an exception, as the plaintext is not recoverable from the corrupted shares, but I instead get a segfault.

Comments (10)

  1. Tushar Gohad repo owner

    @bloodeagle40234 @kmgreen2, on a quick look, we are clearly missing a check for (index > k+m) at line 243 .. should be a better solution than the current proposal. It's kind of late here :-) so let me know if I am missing something:

    erasurecode_preprocessing.c:get_fragment_partition()
    
    238     /*
    239      * Fill in data and parity with available fragments
    240      */ 
    241     for (i = 0; i < num_fragments; i++) {
    242         index = get_fragment_idx(fragments[i]);
    243         if (index < 0) {
    244             return -EBADHEADER;
    245         }
    246         if (index < k) {
    247             data[index] = fragments[i];
    248         } else {
    249             parity[index - k] = fragments[i];
    250         }
    251     }
    
  2. Tushar Gohad repo owner

    @sudarshan_muralidhar I am not able to reproduce after this change:

    diff --git a/src/erasurecode_preprocessing.c b/src/erasurecode_preprocessing.c
    index 64c7edd..8492184 100644
    --- a/src/erasurecode_preprocessing.c
    +++ b/src/erasurecode_preprocessing.c
    @@ -240,7 +240,7 @@ int get_fragment_partition(
          */ 
         for (i = 0; i < num_fragments; i++) {
             index = get_fragment_idx(fragments[i]);
    -        if (index < 0){
    +        if (index < 0 || index > (k + m)) {
                 return -EBADHEADER;
             }
             if (index < k) {
    

    (will leave your test program running overnight) - this is a great catch. If you have any other tests we could add to the test suite, patch submissions are always welcome! Thanks

  3. Tushar Gohad repo owner

    @kmgreen2 thanks for confirming .. let me get this change pushed and also review other meta checks for anything missing.

  4. Sudarshan Muralidhar reporter

    Not quite resolved - there's still some segfaults. Specifically, if after corrupting, i just pass in the first 3 shares, I get a segfault. Code:

    from pyeclib.ec_iface import ECDriver
    from struct import pack
    from random import randint
    
    def mutate(share, mutations):
        for i in xrange(mutations):
            share = list(share)
            location = randint(0, len(share)-2)
            rand = randint(0, 255)
            corrupt = pack("h", rand)
            share[location] = corrupt[0]
            share[location + 1] = corrupt[1]
        return "".join(share), rand
    
    
    ec_driver = ECDriver(k=3, m=2, ec_type='liberasurecode_rs_vand')
    shares = ec_driver.encode("Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate -- we can not consecrate -- we can not hallow -- this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us -- that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion -- that we here highly resolve that these dead shall not have died in vain -- that this nation, under God, shall have a new birth of freedom -- and that government of the people, by the people, for the people, shall not perish from the earth.")
    
    # Use this to run until something segfaults
    
    while True:
        mutated, rand = mutate(shares[0], 10)
        try:
            # print rand
            ec_driver.decode([mutated] + shares[1:3])
        except Exception as e:
            pass
    
  5. Tushar Gohad repo owner

    @sudarshan_muralidhar thanks. This looks like an issue with the liberasurecode_rs_vand backend .. @kmgreen2 you might be able to tell this offhand -

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff64e0df3 in region_xor (from_buf=0xa1c610 "Four score and seven", <incomplete sequence \305>, 
        to_buf=0xa24050 "Four score and seven", <incomplete sequence \305>, blocksize=10486252)
        at liberasurecode_rs_vand.c:350
    350     _to_buf[i] = _to_buf[i] ^ _from_buf[i];
    (gdb) l
    345   uint32_t *_to_buf = (uint32_t*)to_buf;
    346   int adj_blocksize = blocksize / 4;
    347   int trailing_bytes = blocksize % 4;
    348 
    349   for (i = 0; i < adj_blocksize; i++) {
    350     _to_buf[i] = _to_buf[i] ^ _from_buf[i];
    351   }
    352   
    353   for (i = blocksize-trailing_bytes; i < blocksize; i++) {
    354     to_buf[i] = to_buf[i] ^ from_buf[i];
    
    (gdb) p i
    $1 = 17388
    
    (gdb) p _to_buf[i]
    Cannot access memory at address 0xa35000
    
  6. Log in to comment