Author : Rainer Gerhards

librelp stack buffer overflow vulnerability (CVE-2018-1000140)

On Monday March 19th, 2018, the librelp development team was informed by the security team at lgtm.com (Semmle) about a critical security vulnerability in librelp. The vulnerability is a long-standing bug that exists since version 1.1.1 (2013-06-11). It affects the client certificate validation in TLS mode which can lead to a stack buffer overrun and thus remote code execution.

Users of librelp are strongly advised to upgrade their packages as a matter of urgency.

Affected packages and versions

  • librelp 1.2.14 down to 1.1.1

Disclosure process

The security team followed best practices when they notified the librelp development team, who subsequently validated their claim. As agreed, one of the researchers applied for a CVE but unfortunately made a mistake in the afternoon of March 20th, which lead to high-level information about the vulnerability becoming public via the Distributed Weakness Filing Project [1].


We have to assume that the vulnerability became publicly known at that point. The librelp team finalized a patch [2] on March 20th, and a new release of librelp was released on March, 21st. It is available in both source and binary form from the project’s package repository. Note that the patch commit message is intentionally vague so as not to attract additional attention while details of the vulnerability were being disclosed.

The vulnerability

The vulnerability is caused by a call to snprintf on line 1205 of tcp.c [3].

This coding pattern is dangerous, because snprintf returns the number of bytes that it would have written if the buffer had been big enough. Most notably, that number is not necessarily equal to the number of bytes that it actually wrote. It is a common mistake to assume that snprintf returns the number of bytes written. In certain situations and if the data provided to snprintf is controlled by an attacker, this can lead to a stack overflow and the potential to remotely execute code. The code analysis provided by lgtm.com detects potentially dangerous uses of snprintf in open source projects: https://lgtm.com/rules/1505913226124/

Unfortunately, librelp is indeed vulnerable. In order to exploit this vulnerability, an attacker needs to be able to connect to a TLS-enabled RELP logging interface provided by librelp (for example, as can be provided by rsyslog). The attacker then needs to supply an X.509 certificate containing more than 32KB of “subject alt names”. One of these strings needs to overlap the 32KB boundary. For example, if one of the strings starts 10 bytes before the end of the 32KB buffer but is 100 bytes long, then the loop in librelp’s tcp.c will write the first 10 bytes of the string to the buffer but still increment iAllNames by 100. On the next iteration of the loop, the next string will be written at a starting offset of 32KB + 90. An attacker can control the size of this “gap” by varying the length of the overlapping string and utilize it to control exactly which part of the stack they want to overwrite. In particular, this means that they can avoid overwriting the stack canary, which makes the vulnerability significantly easier to exploit.

The teams at librelp and lgtm.com have not yet released a proof-of-concept exploit for this vulnerability.

Severity and mitigation

In the opinion of the librelp/rsyslog development team:

  1. the vulnerability is unquestionably critical as it could lead to RCE
  2. depending on GnuTLS, it may be hard to actually exploit the vulnerability
  3. the severity is mitigated if security recommendations are followed

The use of GnuTLS

librelp uses GnuTLS for handling TLS connections. GnuTLS’s behaviour and handling of overly large fields therefore influences this vulnerability in librelp.

The maximum size of the name fields in question is specified in RFC5280 as follows:

Section 4.1:

SubjectAltName ::= GeneralNames
GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

 

Appendix B imposes the following “restriction”:

The construct “SEQUENCE SIZE (1..MAX) OF” appears in several ASN.1 constructs.  A valid ASN.1 sequence will have zero or more entries. The SIZE (1..MAX) construct constrains the sequence to have at least one entry.  MAX indicates that the upper bound is unspecified.
Implementations are free to choose an upper bound that suits their environment.

As such, much depends on the actual GnuTLS binary that is linked to librelp. If it imposes a limit of 32KB (or less), the vulnerability cannot be exploited. We are currently trying to understand the default behavior of GnuTLS in this regard and will update this advisory when we receive new information.

RFC5280 Sect. 4.2.1.6 imposes restrictions on which characters can be used inside the “subject alternative name”. Brief review indicates that some byte sequences are not permitted. If so, and if GnuTLS implements these validations, the ability of an attacker to inject arbitrary code is reduced, making it harder to craft a workable exploit.

Nevertheless, it should be assumed that GnuTLS does not provide any safeguards. Even if there are, and if those safeguards are enabled  by default, we have to consider the possibility of any checks being disabled in a specific binary.

Trusted networks

Regarding the mitigation of the severity of this vulnerability: users are strongly advised not to expose logging port like syslog TCP and RELP to a public network; these ports are best firewalled to make them available only on a dedicated network. If that advice is followed, the risk is significantly reduced to already-compromised systems on a trusted network.

However, some logs-as-a-service providers do expose RELP on the public Internet. The rsyslog team has been in touch with and/or reviewed documentation for leading providers. Those we checked either do not expose RELP at all or do not support TLS with RELP, and are therefore not at risk.

Credit

  • Bas van Schaik; lgtm.com / Semmle
  • Kevin Backhouse; lgtm.com / Semmle

References

[1] https://docs.google.com/spreadsheets/d/1PlDOsZ4Q36JU4Dz9zyBB2F3814dScppCRCe1muCT7JI
[2] https://github.com/rsyslog/librelp/commit/2cfe657672636aa5d7d2a14cfcb0a6ab9d1f00cf
[3] Affected line in tcp.c (ibrelp version 1.2.14): https://github.com/rsyslog/librelp/blob/532aa362f0f7a8d037505b0a27a1df452f9bac9e/src/tcp.c#L1205

 

 

librelp 1.2.15

librelp 1.2.15 [download]

This new release of librelp provides several bugfixes and can be built on Solaris and AIX.

For more details, please take a look at the changelog below.

———————————————————————-
– made build on Solaris again
– made build on AIX
  Thanks to Philippe Duveau for providing the patches
– bugfix: invalid handling of snprintf() return code
– bugfix: invalid assert predicate
  an assert could change status variable due to typo, so in debug
  mode processing could fail.
  thanks to github user KatMisato for alerting us
  fixes https://github.com/rsyslog/librelp/issues/66
– some code cleanup
– bugfix: error message on open error was truncated
  The “connection already open” error message when trying to open
  an already open connection was truncated due to too-small size
  specified.
  Thanks to rsyslog forum user AlanR for the problem report.


sha256sum: a931832d9056660feee76d52195b21d4e9e06d5ec8e96b26af44e998529da999

New Logo Selected

The rsyslog community selected a new logo! The winner is logo 1, also shown here to the right. That logo won with an overwhelming majority, and lead the polls on the mailing list, our original logo selection post as well as a dedicated poll we created for easier and anonymous voting.

The logo was originally contributed in 2014 by “robert s”, whom unfortunately I am no longer able to contact. While before we never officially adopted it, it went into widespread use and is already often used to represent rsyslog. So in a sense the now-official selection let’s us keep consistent.

We are glad to have the community decision. I am right now implementing the new logo all over rsyslog web spaces. It will also be available via the rsyslog website github project (PR just created).

Many thanks to all who voted. It was a pleasant experience for us. This may have also set stage for future polls on different topics.

librelp 1.2.14

librelp 1.2.14 [download]

This new release of librelp provides an API extension: add relpSrvSetMaxDataSize().

For more details, please take a look at the changelog below.

———————————————————————-
Version 1.2.14 – 2017-05-29
– API extension: add relpSrvSetMaxDataSize()
  Thanks to Nathan Brown for the patch.


sha256sum: 11f6241a4336358a33bfdadd43ef299e8258db0a5243d0c164499c6b85ae5955 

LibLogging 1.0.6 released

liblogging 1.0.6 [download]

We have released liblogging 1.0.6.

This release mostly provides fixes for different issues, like a small memory leak, build detection for journal libraries and many more. For full details, see the changelog below.

sha256sum: 338c6174e5c8652eaa34f956be3451f7491a4416ab489aef63151f802b00bf93

—————————————————————————-
v1.0.6 2017-03-06
– fix small memory leaks in libstdlog
  each open/close leaked a couple of bytes; this was no problem, except if
  they were called very often. However, it was a problem when using memory
  debuggers, which rightfully complained.
– fix BSD build
– enhancement:  sigsafe_printf now recognizes the “j” length modifier
  Thanks to David A. Bright for implementing this
– fix: build_file_line and build_syslog_frame call the __stdlog_print_*
  functions incorrectly
  Change these functions so that they call the __stdlog_print_* functions
  with the correct buffer size.
  see also: https://github.com/rsyslog/liblogging/issues/33
  Thanks to David A. Bright for the patch.
– Implement a STDLOG_PID option
  … to specify that each log message should be tagged with the process
  identifier as well as the ident.
  Thanks to David A. Bright for implementing this
– bugfix: potentialSEGV in the stdlog_sigsafe_string formatter
  if NULL pointer was passed in
  Thanks to David A. Bright for the patch
– bugfix: stdlog_sigsafe_printf mis-handles an int or unsigned int
  Thanks to David A. Bright for the patch
– build system: auto-detect presence of journal libraries
  simplifies build for most users. Many complained on mailing list
  about missing journal dependency. Now by default we disable it if
  the libs are not found, what usually is the right thing to do.

librelp 1.2.13

librelp 1.2.13 [download]

This new release of librelp provides only a few changes and cleanups.The biggest change is that librelp now builds on BSD.

For more details, please take a look at the changelog below.

———————————————————————-
Version 1.2.13 – 2017-02-20
– make build under BSD
– bugfix: duplicated lines after server reconnect
  Thanks to Hervé for the patch.

sha256sum: 38df3ca7feba55850602bbefe3ac3c035e7666691d46b8bfbff1f1a4c774c0c7 

librelp 1.2.12

librelp 1.2.12 [download]

This new release of librelp provides a few changes and cleanups. It provides an API enhancement to permit to set a connection timeout and it has some dynamic tests added to allow the use of rsyslog to test librelp.

For more details, please take a look at the changelog below.

———————————————————————-
Version 1.2.12 – 2016-07-07
– API enhancement: permit to set connection timeout
  Thanks to Nathan Brown for the patch.
– cleanup: replace deprecated GnuTLS data types by current ones
– CI improvements: added dynamic tests
  we now use the rsyslog testbench to do dynamic librelp tests. This
  currently happens only under Travis CI.

sha256sum: 0355730524f7b20bed1b85697296b6ce57ac593ddc8dddcdca263da71dee7bd7 

librelp 1.2.11

librelp 1.2.11 [download]

This new release of librelp is mostly a bugfixing release that fixes several issues, especially a potential segfault. The new version also has an API enhancement that adds a configurable connection timeout.

For more details, please take a look at the changelog below.

———————————————————————-
Version 1.2.11 – 2016-06-22
– bugfix: do not accept more than one “open” verb on a connection
  closes https://github.com/rsyslog/librelp/issues/37
– bugfix: potential segfault when high-numbered fd is used in sender
  When a fd (socket) with value >= 1024 was used by the client sender
  process, the library could segfault in select(). This depended a bit
  on the platform.
  This patch solves the issue by replacing the select() call with
  poll(). Note that we do not changed to epoll(), because
  (a) we only wait on a single fd
  (b) poll() is more portable
  closes https://github.com/rsyslog/librelp/issues/38
– bugfix: make librelp not run in thight loop when out of sockets
  If the process can no longer accept new connections (via accept)
  because it has reached its file handle maximum, librelp runs in
  a thight loop until either the client connection request is aborted
  or a file handle becomes available.
  This happens due to the fact that we get event notifications on
  connection requests. As we can’t satisfy it, we librelp always
  retries. Unfortunately, there is no socket call to cancel a
  connection request, so we cannot push the client request out.
  An alternative solution would be to close and re-open the
  listening socket, but in that case it is uncertain if we ever can
  re-aquire a socket (an easy DoS). So the best thing we can
  probably do is delay retries a bit. We must be careful, however,
  not to use a too long delay, as that would also affect other
  connections. We could address that problem via a dedicated thread
  for the listening process, but librelp is designed so that it can
  be used by callers with any threading library and threading model,
  and that would violate this design principle.
  Judging the alternatives, a slight delay probably is the best
  solution, especially as the situation is uncommon and will hopefully
  not last too long. This patch implements that solution.
  closes https://github.com/rsyslog/librelp/issues/34
– bugfix: flush the current recv frame if it exists if the client
  session is restarting
  Thanks to Nate Brown for the patch.
– API enhancement: add configurable connection timeout
  Thanks to Nate Brown for the patch.

sha256sum: 84de48f46caba0106d8853af572aa7b625c82dfbcf5f7cd13d2e57cce786e929

librelp 1.2.10

librelp 1.2.10 [download]

This new release of librelp fixes a problem with sending large buffers, improves sender/receiver code and enables compatibility with older versions of GnuTLS.

———————————————————————-
Version 1.2.10 – 2016-03-30
– make compatible with older versions of GnuTLS which require
  libgcrypt
– improve example sender/receiver code
  Thanks to Chris Pilkington for the patches.
– bugfix: Send full buffers after connection re-establishing
  When sending large buffers it’s possible that only part of buffer data
  will be transferred before connection is closed. Then on connection
  re-establishing librelp thinks part of buffer is already sent and
  transfers only remaining part. Remote side then is not be able to parse
  such message and always closes the connection.
  Thanks to github user cellscape for the patch.


sha256sum: 6c80eed5e29061d2cce35408ae43ddaee354edc27c1076eabec6da4eaecdcc72

Scroll to top