dropbox / lepton

Lepton is a tool and file format for losslessly compressing JPEGs by an average of 22%.
https://blogs.dropbox.com/tech/2016/07/lepton-image-compression-saving-22-losslessly-from-images-at-15mbs/
Apache License 2.0
5.01k stars 355 forks source link

Vulnerabilities found #110

Closed fCorleone closed 6 years ago

fCorleone commented 6 years ago

A vulnerability has been found when using lepton. The input file is displayed at here: https://github.com/fCorleone/fuzz_programs/blob/master/lepton/input.jpg The command line to run the program is : ./lepton inputfile I built this program using afl-g++ and with ASAN mode. And the program crash with that input file. The information said the program throw a short read float exception. So I used gdb to find what exactly happened, I found this:

#0  0x00007ffff7bcb269 in raise (sig=8) at ../sysdeps/unix/sysv/linux/pt-raise.c:35
#1  0x0000000000442252 in validateAndCompress (reader=0x7fffffffe0d4, writer=0x7fffffffe0d8, header=..., 
    header_size=2, start_byte=0, end_byte=0, validation_exit_code=0x7fffffffe200, lepton_data=0x7fffffffe270, 
    argc=2, argv=0x7fffffffe5e8, is_permissive=false, is_socket=false, permissive_jpeg_return=0x0)
    at src/lepton/validation.cc:171
#2  0x0000000000420fc7 in process_file (reader=0x0, writer=0x0, max_file_size=0, force_zlib0=false)
    at src/lepton/jpgcoder.cc:1607
#3  0x000000000041e830 in app_main (argc=2, argv=0x7fffffffe5e8) at src/lepton/jpgcoder.cc:946
#4  0x0000000000441b95 in main (argc=2, argv=0x7fffffffe5e8) at src/lepton/main.cc:17

And I checked validation.cc:171.

158     while (waitpid(encode_pid, &status, 0) < 0 && errno == EINTR) {} // wait on encode
159     if (WIFEXITED(status)) {
160         int exit_code = WEXITSTATUS(status);
161         if (exit_code != 0) {
(gdb) 
162             if (is_permissive) {
163                 return ValidationContinuation::EVALUATE_AS_PERMISSIVE;
164             }
165             exit(exit_code);
166         }
167     } else if (WIFSIGNALED(status)) {
168         if (is_permissive) {
169             return ValidationContinuation::EVALUATE_AS_PERMISSIVE;
170         }
171         raise(WTERMSIG(status));
(gdb) 
172     }

I found the crash may happen at a child process , so I changed the fork mode to follow the execution of child process, and I found :

#0  0x000000000048bb36 in ProbabilityTables<false, (BlockType)2>::compute_lak_vec(long long __vector(2), long long __vector(2), long long __vector(2), long long __vector(2), int const*) (coeffs_x_low=..., coeffs_x_high=..., 
    coeffs_a_low=..., indirect_coeffs_a_high=..., 
    icos_deq=0x858b80 <ProbabilityTablesBase::icos_idct_edge_8192_dequantized_x_+608>)
    at ./src/vp8/model/model.hh:939
#1  0x000000000048985b in ProbabilityTables<false, (BlockType)2>::compute_lak_horizontal (
    this=0x858708 <midright>, context=..., band=3) at ./src/vp8/model/model.hh:995
#2  0x00000000004872d8 in ProbabilityTables<false, (BlockType)2>::update_coefficient_context8_horiz (
    this=0x858708 <midright>, coefficient=3 '\003', block=..., num_nonzeros_x=1 '\001')
    at ./src/vp8/model/model.hh:406
#3  0x0000000000482cec in encode_one_edge<false, (BlockType)2, true, VPXBoolWriter> (context=..., encoder=..., 
    probability_tables=..., num_nonzeros_7x7=1 '\001', est_eob=2 '\002', pt=...) at src/vp8/encoder/encoder.cc:92
#4  0x000000000047c13d in encode_edge<false, (BlockType)2, VPXBoolWriter> (context=..., encoder=..., 
    probability_tables=..., num_nonzeros_7x7=1 '\001', eob_x=2 '\002', eob_y=1 '\001', pt=...)
    at src/vp8/encoder/encoder.cc:172
#5  0x0000000000476ee0 in serialize_tokens<false, (BlockType)2, VPXBoolWriter> (context=..., encoder=..., 
    probability_tables=..., pt=...) at src/vp8/encoder/encoder.cc:286
#6  0x000000000045fff9 in VP8ComponentEncoder<VPXBoolReader>::process_row<ProbabilityTables<false, (BlockType)2>, ProbabilityTables<true, (BlockType)2>, ProbabilityTables<false, (BlockType)2>, VPXBoolWriter> (pt=..., 
    left_model=..., middle_model=..., right_model=..., curr_y=1, colldata=0x858200 <colldata>, context=..., 
    bool_encoder=...) at src/lepton/vp8_encoder.cc:147
#7  0x000000000045dfa4 in VP8ComponentEncoder<VPXBoolReader>::process_row_range<VPXBoolWriter> (this=0x8cbd20, 
    thread_id=0, colldata=0x858200 <colldata>, min_y=0, max_y=10, stream=0x7fffffffd310, 
    bool_encoder=0x7fffffffd710, num_nonzeros=0x7fffffffcf70) at src/lepton/vp8_encoder.cc:363
#8  0x000000000045d5eb in VP8ComponentEncoder<VPXBoolReader>::threaded_encode_inner<VPXBoolWriter> (
    this=0x8cbd20, colldata=0x858200 <colldata>, str_out=0x8cbd00, selected_splits=0x8cd240, 
    num_selected_splits=1, bool_encoder=0x7fffffffd710, stream=0x7fffffffd310) at src/lepton/vp8_encoder.cc:491
#9  0x000000000045cb61 in VP8ComponentEncoder<VPXBoolReader>::vp8_full_encoder (this=0x8cbd20, 
    colldata=0x858200 <colldata>, str_out=0x8cbd00, selected_splits=0x8cd240, num_selected_splits=1, 
    use_ans_encoder=false) at src/lepton/vp8_encoder.cc:566
---Type <return> to continue, or q <return> to quit---
#10 0x000000000045d0c3 in VP8ComponentEncoder<VPXBoolReader>::encode_chunk (this=0x8cbd20, 
    input=0x858200 <colldata>, output=0x8cbd00, selected_splits=0x8cd240, num_selected_splits=1)
    at src/lepton/vp8_encoder.cc:81
#11 0x000000000042a969 in write_ujpg (row_thread_handoffs=std::vector of length 6, capacity 6 = {...}, 
    jpeg_file_raw_bytes=0x0) at src/lepton/jpgcoder.cc:4070
#12 0x000000000043cc80 in std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)>::__call<bool, , 0ul, 1ul>(std::tuple<>&&, std::_Index_tuple<0ul, 1ul>) (this=0x8de800, 
    __args=<unknown type in /home/mfc_fuzz/lepton/lepton, CU 0x54dac, DIE 0x9308c>)
    at /usr/include/c++/5/functional:1074
#13 0x000000000043aba7 in std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)>::operator()<, bool>() (this=0x8de800)
    at /usr/include/c++/5/functional:1133
#14 0x00000000004384c6 in std::_Function_handler<bool (), std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)> >::_M_invoke(std::_Any_data const&) (__functor=...) at /usr/include/c++/5/functional:1857
#15 0x0000000000435236 in std::function<bool ()>::operator()() const (this=0x7fffffffe300)
    at /usr/include/c++/5/functional:2267
#16 0x0000000000422fba in execute(std::function<bool ()> const&) (function=...) at src/lepton/jpgcoder.cc:2053
#17 0x0000000000421e23 in process_file (reader=0x0, writer=0x0, max_file_size=0, force_zlib0=false)
    at src/lepton/jpgcoder.cc:1836
#18 0x000000000041e830 in app_main (argc=2, argv=0x7fffffffe5e8) at src/lepton/jpgcoder.cc:946
#19 0x0000000000441b95 in main (argc=2, argv=0x7fffffffe5e8) at src/lepton/main.cc:17

I believe there is a problem to be solved.

fCorleone commented 6 years ago

Another issue has been found. The situation is same as the above one. The input image file has been put at : https://github.com/fCorleone/fuzz_programs/blob/master/lepton/input2.jpg

#0  0x000000000048b51e in ProbabilityTables<false, (BlockType)0>::compute_lak_vec(long long __vector(2), long long __vector(2), long long __vector(2), long long __vector(2), int const*) (coeffs_x_low=...,
    coeffs_x_high=..., coeffs_a_low=..., indirect_coeffs_a_high=..., 
    icos_deq=0x858c80 <ProbabilityTablesBase::icos_idct_edge_8192_dequantized_y_+96>)
    at ./src/vp8/model/model.hh:939
#1  0x0000000000488b79 in ProbabilityTables<false, (BlockType)0>::compute_lak_vertical (
    this=0x8586de <top+6>, context=..., band=24) at ./src/vp8/model/model.hh:1012
#2  0x00000000004869d0 in ProbabilityTables<false, (BlockType)0>::update_coefficient_context8_vert (
    this=0x8586de <top+6>, coefficient=24 '\030', block=..., num_nonzeros_x=2 '\002')
    at ./src/vp8/model/model.hh:414
#3  0x0000000000480e5e in encode_one_edge<false, (BlockType)0, false, VPXBoolWriter> (context=..., 
    encoder=..., probability_tables=..., num_nonzeros_7x7=1 '\001', est_eob=1 '\001', pt=...)
    at src/vp8/encoder/encoder.cc:96
#4  0x0000000000479f74 in encode_edge<false, (BlockType)0, VPXBoolWriter> (context=..., encoder=..., 
    probability_tables=..., num_nonzeros_7x7=1 '\001', eob_x=1 '\001', eob_y=1 '\001', pt=...)
    at src/vp8/encoder/encoder.cc:178
#5  0x00000000004756c4 in serialize_tokens<false, (BlockType)0, VPXBoolWriter> (context=..., 
    encoder=..., probability_tables=..., pt=...) at src/vp8/encoder/encoder.cc:286
#6  0x000000000045eabb in VP8ComponentEncoder<VPXBoolReader>::process_row<ProbabilityTables<false, (BlockType)0>, ProbabilityTables<false, (BlockType)0>, ProbabilityTables<false, (BlockType)0>, VPXBoolWriter>
    (pt=..., left_model=..., middle_model=..., right_model=..., curr_y=0, colldata=0x858200 <colldata>, 
    context=..., bool_encoder=...) at src/lepton/vp8_encoder.cc:126
#7  0x000000000045dd7c in VP8ComponentEncoder<VPXBoolReader>::process_row_range<VPXBoolWriter> (
    this=0x8cbd20, thread_id=0, colldata=0x858200 <colldata>, min_y=0, max_y=10, stream=0x7fffffffd300, 
    bool_encoder=0x7fffffffd700, num_nonzeros=0x7fffffffcf60) at src/lepton/vp8_encoder.cc:298
#8  0x000000000045d5eb in VP8ComponentEncoder<VPXBoolReader>::threaded_encode_inner<VPXBoolWriter> (
    this=0x8cbd20, colldata=0x858200 <colldata>, str_out=0x8cbd00, selected_splits=0x8cd240, 
    num_selected_splits=1, bool_encoder=0x7fffffffd700, stream=0x7fffffffd300)
---Type <return> to continue, or q <return> to quit---
    at src/lepton/vp8_encoder.cc:491
#9  0x000000000045cb61 in VP8ComponentEncoder<VPXBoolReader>::vp8_full_encoder (this=0x8cbd20, 
    colldata=0x858200 <colldata>, str_out=0x8cbd00, selected_splits=0x8cd240, num_selected_splits=1, 
    use_ans_encoder=false) at src/lepton/vp8_encoder.cc:566
#10 0x000000000045d0c3 in VP8ComponentEncoder<VPXBoolReader>::encode_chunk (this=0x8cbd20, 
    input=0x858200 <colldata>, output=0x8cbd00, selected_splits=0x8cd240, num_selected_splits=1)
    at src/lepton/vp8_encoder.cc:81
#11 0x000000000042a969 in write_ujpg (row_thread_handoffs=std::vector of length 6, capacity 6 = {...}, 
    jpeg_file_raw_bytes=0x0) at src/lepton/jpgcoder.cc:4070
#12 0x000000000043cc80 in std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)>::__call<bool, , 0ul, 1ul>(std::tuple<>&&, std::_Index_tuple<0ul, 1ul>) (this=0x8de800, 
    __args=<unknown type in /home/mfc_fuzz/lepton/lepton, CU 0x54dac, DIE 0x9308c>)
    at /usr/include/c++/5/functional:1074
#13 0x000000000043aba7 in std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)>::operator()<, bool>() (this=0x8de800) at /usr/include/c++/5/functional:1133
#14 0x00000000004384c6 in std::_Function_handler<bool (), std::_Bind<bool (*(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*))(std::vector<ThreadHandoff, std::allocator<ThreadHandoff> >, std::vector<unsigned char, Sirikata::JpegAllocator<unsigned char> >*)> >::_M_invoke(std::_Any_data const&) (__functor=...)
    at /usr/include/c++/5/functional:1857
#15 0x0000000000435236 in std::function<bool ()>::operator()() const (this=0x7fffffffe2f0)
    at /usr/include/c++/5/functional:2267
#16 0x0000000000422fba in execute(std::function<bool ()> const&) (function=...)
    at src/lepton/jpgcoder.cc:2053
#17 0x0000000000421e23 in process_file (reader=0x0, writer=0x0, max_file_size=0, force_zlib0=false)
    at src/lepton/jpgcoder.cc:1836
#18 0x000000000041e830 in app_main (argc=2, argv=0x7fffffffe5d8) at src/lepton/jpgcoder.cc:946
#19 0x0000000000441b95 in main (argc=2, argv=0x7fffffffe5d8) at src/lepton/main.cc:17
danielrh commented 6 years ago

Doesn't seem like a vulnerability here, since the alternative is to just exit with an unsupported jpeg message instead of getting an exception raised.