weidai11 / cryptopp

free C++ class library of cryptographic schemes
https://cryptopp.com
Other
4.66k stars 1.47k forks source link

Poly1305 null pointer passed as argument 1 #1253

Closed minerva32 closed 6 months ago

minerva32 commented 6 months ago

Operating system and version (Ubuntu 18.04) version of the Crypto++ library (Crypto++ 8.8.0)

I got some unusual output from the fuzzer. Tried to analyze what this was.

Successfully executed: ./ChaCha20-Poly1305_id:012769,sync:afl0,src:012806
Output: INFO: Seed: 3188957293
INFO: Loaded 1 modules   (309231 inline 8-bit counters): 309231 [0x44cabf9, 0x45163e8),
INFO: Loaded 1 PC tables (309231 PCs): 309231 [0x45163e8,0x49ce2d8),
../fuzzer: Running 1 inputs 1 time(s) each.
Running: ./ChaCha20-Poly1305_id:012769,sync:afl0,src:012806
poly1305.cpp:159:15: runtime error: null pointer passed as argument 1, which is declared to never be null
/usr/include/string.h:43:28: note: nonnull attribute specified here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior poly1305.cpp:159:15 in
Executed ./ChaCha20-Poly1305_id:012769,sync:afl0,src:012806 in 213 ms
***
*** NOTE: fuzzing was not performed, you have only
***       executed the target code on a fixed set of inputs.
***

Code I tried to reproduce. Assigned byte* mac = nullptr;

#include "cryptlib.h"
#include "chachapoly.h"
#include "filters.h"
#include "files.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    const byte pt[] = {
        0x4c,0x61,0x64,0x69,0x65,0x73,0x20,0x61,0x6e,0x64,0x20,0x47,0x65,0x6e,0x74,0x6c,
        0x65,0x6d,0x65,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x6c,0x61,0x73,
        0x73,0x20,0x6f,0x66,0x20,0x27,0x39,0x39,0x3a,0x20,0x49,0x66,0x20,0x49,0x20,0x63,
        0x6f,0x75,0x6c,0x64,0x20,0x6f,0x66,0x66,0x65,0x72,0x20,0x79,0x6f,0x75,0x20,0x6f,
        0x6e,0x6c,0x79,0x20,0x6f,0x6e,0x65,0x20,0x74,0x69,0x70,0x20,0x66,0x6f,0x72,0x20,
        0x74,0x68,0x65,0x20,0x66,0x75,0x74,0x75,0x72,0x65,0x2c,0x20,0x73,0x75,0x6e,0x73,
        0x63,0x72,0x65,0x65,0x6e,0x20,0x77,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20,0x69,
        0x74,0x2e
    };

    const byte aad[] = {
        0x50,0x51,0x52,0x53,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7
    };

    const byte key[] = {
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
    };

    const byte iv[] = {
        0x07,0x00,0x00,0x00,                      // Common
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47   // IV
    };

    byte ct[sizeof(pt)], rt[sizeof(ct)];
    byte* mac = nullptr;

    ChaCha20Poly1305::Encryption enc;
    enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    enc.EncryptAndAuthenticate(ct, mac, sizeof(mac), iv, sizeof(iv), aad, sizeof(aad), pt, sizeof(pt));

    std::cout << "Plain: ";
    StringSource(pt, sizeof(pt), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    std::cout << "Cipher: ";
    StringSource(ct, sizeof(ct), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    std::cout << "MAC: ";
    StringSource(mac, sizeof(mac), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    ChaCha20Poly1305::Decryption dec;
    dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    dec.DecryptAndVerify(rt, mac, sizeof(mac), iv, sizeof(iv), aad, sizeof(aad), ct, sizeof(ct));

    std::cout << "Recover: ";
    StringSource(rt, sizeof(rt), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    return 0;
}

This is how I compiled.

g++ -fsanitize=address -g main.cpp -o main -L/opt/homebrew/opt/cryptopp/lib -lcryptopp
./main

This is the result of Address Sanitizer.

AddressSanitizer:DEADLYSIGNAL
=================================================================
==71557==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000105721fd0 bp 0x00016b22a2f0 sp 0x00016b229aa0 T0)
==71557==The signal is caused by a WRITE memory access.
==71557==Hint: address points to the zero page.
    #0 0x105721fd0 in __sanitizer::internal_memmove(void*, void const*, unsigned long)+0xd0 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x69fd0)
    #1 0x104ca5548 in (anonymous namespace)::Poly1305_HashFinal(unsigned int*, unsigned int*, unsigned char*, unsigned long) poly1305.cpp:159
    #2 0x104ca5ed4 in non-virtual thunk to CryptoPP::Poly1305TLS_Base::TruncatedFinal(unsigned char*, unsigned long) poly1305.cpp
    #3 0x104c21960 in CryptoPP::ChaCha20Poly1305_Base::AuthenticateLastFooterBlock(unsigned char*, unsigned long) chachapoly.cpp:93
    #4 0x104c1d2f0 in CryptoPP::AuthenticatedSymmetricCipherBase::TruncatedFinal(unsigned char*, unsigned long) authenc.cpp:175
    #5 0x104bd6fa8 in main main.cpp:41
    #6 0x18a7bd054  (<unknown module>)

==71557==Register values:
 x[0] = 0x0000000000000000   x[1] = 0x000000016b22a308   x[2] = 0x0000000000000008   x[3] = 0x0000000000000008  
 x[4] = 0x0000000000000001   x[5] = 0x0000000000000001   x[6] = 0x0000000052b8fd53   x[7] = 0x138c753591b28b92  
 x[8] = 0x0000000000000008   x[9] = 0x000000016b22a310  x[10] = 0x0000000000000000  x[11] = 0xfffffffffffffff8  
x[12] = 0x0000000000000000  x[13] = 0x0000000000000000  x[14] = 0x0000000000000000  x[15] = 0x0000000000000000  
x[16] = 0x00000001056d25dc  x[17] = 0x0000000000000000  x[18] = 0x0000000000000000  x[19] = 0x0000000000000008  
x[20] = 0x000000016b22a308  x[21] = 0x0000000000000000  x[22] = 0x0000000000000000  x[23] = 0x000000016b22b3a0  
x[24] = 0x0000000106185aa8  x[25] = 0xffffffffffffffc7  x[26] = 0x0000000000000000  x[27] = 0x0000000000000000  
x[28] = 0x0000000000000000     fp = 0x000000016b22a2f0     lr = 0x00000001056d26bc     sp = 0x000000016b229aa0  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x69fd0) in __sanitizer::internal_memmove(void*, void const*, unsigned long)+0xd0
noloader commented 6 months ago

mac is a buffer, not a NULL ptr. See https://www.cryptopp.com/docs/ref/class_authenticated_symmetric_cipher.html#a6078f8888fd8686c6de52091c63ae95d.

And sizeof(mac) is wrong. sizeof(mac) returns the size of the pointer, which is probably 8, and not the size of a null buffer, which is 0.