CVE-2017-8891 (published 2017-05-10T16:29Z)

Dropbox Lepton 1.2.1 allows DoS (SEGV and application crash) via a malformed lepton file because the code does not ensure setup of a correct number of threads.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-1187
cwe_name: DEPRECATED: Use of Uninitialized Resource
description: This entry has been deprecated because it was a duplicate of CWE-908. All content has been transferred to CWE-908.
extended_description: 
            Prohibited
            This CWE has been deprecated.
            See description and name for possible suggestions of other CWEs to consider.
            
               
            
         
         

Fix information:
repo_url: https://github.com/dropbox/lepton
commit_details: repo_url: https://github.com/dropbox/lepton
author: Daniel Reiter Horn
author_date: 2017-04-04 23:58:01-07:00
msg: fix #87 : always check that threads_required set up the appropriate number of threads---fire off nop functions on unused threads for consistency
repository: repo_url: https://github.com/dropbox/lepton
repo_name: dropbox/lepton
description: Lepton is a tool and file format for losslessly compressing JPEGs by an average of 22%.
repo_language: C++
owner: dropbox
file_changes: filename: bitops.cc
change_type: ModificationType.MODIFY
diff: @@ -356,6 +356,7 @@ bounded_iostream::bounded_iostream(Sirikata::DecoderWriter *w,
     this->size_callback = size_callback;
     buffer_position = 0;
     byte_position = 0;
+    byte_bound = 0x7FFFFFFF;
     num_bytes_attempted_to_write = 0;
     set_bound(0);
 }
@@ -384,7 +385,7 @@ void bounded_iostream::close() {
     parent->Close();
 }
 
-unsigned int bounded_iostream::write_no_buffer(const void *from, size_t bytes_to_write) {
+uint32_t bounded_iostream::write_no_buffer(const void *from, size_t bytes_to_write) {
     //return iostream::write(from,tpsize,dtsize);
     std::pair<unsigned int, Sirikata::JpegError> retval;
     if (byte_bound != 0 && byte_position + bytes_to_write > byte_bound) {

programming_language: C++
filename: bitops.hh
change_type: ModificationType.MODIFY
diff: @@ -467,12 +467,12 @@ class bounded_iostream
     uint8_t buffer[buffer_size];
     uint32_t buffer_position;
     Sirikata::DecoderWriter *parent;
-    unsigned int byte_bound;
-    unsigned int byte_position;
-    unsigned int num_bytes_attempted_to_write;
+    uint32_t byte_bound;
+    uint32_t byte_position;
+    uint32_t num_bytes_attempted_to_write;
     Sirikata::JpegError err;
     std::function<void(Sirikata::DecoderWriter*, size_t)> size_callback;
-    unsigned int write_no_buffer( const void* from, size_t bytes_to_write );
+    uint32_t write_no_buffer( const void* from, size_t bytes_to_write );
 public:
 	bounded_iostream( Sirikata::DecoderWriter * parent,
                       const std::function<void(Sirikata::DecoderWriter*, size_t)> &size_callback,

programming_language: C++
filename: lepton_codec.cc
change_type: ModificationType.MODIFY
diff: @@ -275,6 +275,7 @@ CodingReturnValue LeptonCodec::ThreadState::vp8_decode_thread(unsigned int threa
     /* deserialize each block in planar order */
 
     dev_assert(luma_splits_.size() == 2); // not ready to do multiple work items on a thread yet
+    always_assert(luma_splits_.size() >= 2);
     int min_y = luma_splits_[0];
     int max_y = luma_splits_[1];
     while(true) {

programming_language: C++
filename: vp8_decoder.cc
change_type: ModificationType.MODIFY
diff: @@ -417,6 +417,7 @@ std::vector<ThreadHandoff> VP8ComponentDecoder::initialize_decoder_state(const U
 void VP8ComponentDecoder::flush() {
         mux_splicer.drain(mux_reader_);
 }
+namespace{void nop(){}}
 CodingReturnValue VP8ComponentDecoder::decode_chunk(UncompressedComponents * const colldata)
 {
     mux_splicer.init(spin_workers_);
@@ -455,14 +456,19 @@ CodingReturnValue VP8ComponentDecoder::decode_chunk(UncompressedComponents * con
     if (do_threading_) {
         for (unsigned int thread_id = 0; thread_id < NUM_THREADS; ++thread_id) {
             unsigned int cur_spin_worker = thread_id;
-            spin_workers_[cur_spin_worker].work
-                = std::bind(worker_thread,
-                            thread_state_[thread_id],
-                            thread_id,
-                            colldata,
-                            mux_splicer.thread_target,
-                            getWorker(cur_spin_worker),
-                            &send_to_actual_thread_state);
+            if (!thread_state_[thread_id]) {
+                spin_workers_[cur_spin_worker].work
+                    = &nop;
+            } else {
+                spin_workers_[cur_spin_worker].work
+                    = std::bind(worker_thread,
+                                thread_state_[thread_id],
+                                thread_id,
+                                colldata,
+                                mux_splicer.thread_target,
+                                getWorker(cur_spin_worker),
+                                &send_to_actual_thread_state);
+            }
             spin_workers_[cur_spin_worker].activate_work();
         }
         flush();

programming_language: C++
filename: boolreader.hh
change_type: ModificationType.MODIFY
diff: @@ -119,7 +119,9 @@ public:
             return;
         }
         size_t del = rope[0].second-rope[0].first;
-        memcpy(dest, rope[0].first, del);
+        if (del) {
+            memcpy(dest, rope[0].first, del);
+        }
         dest += del;
         size -=del;
         if (size) {

programming_language: C++