uriparser / uriparser

:hocho: Strictly RFC 3986 compliant URI parsing and handling library written in C89; moved from SourceForge to GitHub

Home Page:https://uriparser.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Integer underflow on "uriToStringCharsRequired()"

jinhojun opened this issue · comments

While we are testing libxspf application, we found crash-inducing input and it turned out that the cause may arise from uriparser library. Please check the below report.

libxspf (1.2.0) and uriparser

Vulntype: Interger underflow

Affected component(s)

uriparser project (uriToStringCharsRequiredA function)

and then it affects

libxspf project(makeUriString function),

Attack vector(s)

Adversary sends crafted movie playlist file and victim opens it with media player which is using libxspf library (such as VLC player).

Suggested description of the vulnerability for use in the CVE

makeUriString() function from Xspf class trusts the return values (i.e., int* charsRequired) from uriparser library; thus assumes positive value.

However, "uriparser" library's uriToStringCharsRequired() functions returns negative value on crafted URI string such as "http://example.co@" (actually the function should return NULL).

Due to this integer underflow, the code meets crash with heap alloction failure.

  • libxspf
    XML_Char * makeUriString(UriUri const & uri) {
            XML_Char * uriString;
            int charsRequired;            
            if (uriToStringCharsRequired(&uri, &charsRequired) != URI_SUCCESS) {
                    // the uriparse should have return NULL!
                    return NULL;
            }
            charsRequired++;
            // negative value are inserted to charsRequired (e.g., 0xffffffffff9e5331)
            // allocator error here!
            uriString = new XML_Char[charsRequired];  
            if (uriToString(uriString, &uri, charsRequired, NULL) != URI_SUCCESS) {
                    delete [] uriString;
                    return NULL;
            }
            return uriString;
    }

Discoverer

Jinho Jung (jinho.jung@gatech.edu, Georgia Institute of Technology)

Reference

N/A

Additional Information

  1. PoC:
    https://ffs.gtisc.gatech.edu/download/ca3502e783138c47/#WQ_4uRrb_CSkyHvA5fpJMg

  2. How to reproduce

we use example application from libxspf

  1. find read.cpp file and modify the file name to PoC's
  2. compile and run the read program
  1. Another reproduce
  1. provide bad uri "http://example.co@" to uriToStringCharsRequired()
  2. the function should not return URI_SUCCESS
    ==> but it assigns negative value on charsRequired

Hi Jinho,

thanks for the report — I appreciate it! 👍
I'll get back to you on this when I had a chance at a closer look.

Best, Sebastian

Hi!

I had a chance at a first closer look now. What I found:

  • When I parse text http://example.co@ using uriParseUriW and then call uriToStringCharsRequiredW on the result I get 18 as expected. This is for code on Git master, i.e. 51bdd9a.

  • While http://example.co@ might look bad, it is a well-formed URI according to RFC 3986:
    host is present but empty, user info is example.co. It can be seen at https://tools.ietf.org/html/rfc3986#appendix-A where this is the relevant excerpt from the ABNF grammar:

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part     = "//" authority path-abempty
authority     = [ userinfo "@" ] host [ ":" port ]
host          = IP-literal / IPv4address / reg-name
reg-name      = *( unreserved / pct-encoded / sub-delims )

For our case we get:

scheme = "http"
userinfo = "example.co"
host = reg-name = ""
  • I am not sure which read.cpp you are referring to. I cannot find the code above in libxspf's examples/read/read.cpp.

  • The PoC link of Firefox Send says This link has expired.

Please help me understand the issue in detail.

Thanks for the checking.

  1. the read.cpp is from here:
    https://github.com/ezdev128/libxspf/blob/master/examples/read/read.cpp

I found the problem while taking a look at the libxspf project. The application utilizes uriparser.

  1. PoC File upload again:
    https://gts3.org/~jjung/poc/uriparser/poc_200207

Thanks for the checking.

1. the `read.cpp` is from here:
   https://github.com/ezdev128/libxspf/blob/master/examples/read/read.cpp

I cannot find any of the makeUriString code quoted above in there or even something similar. Is this the correct link for the code you tested?

1. PoC File upload again:
   https://gts3.org/~jjung/poc/uriparser/poc_200207

When I run this file against the read example I get this error output, no crash:

# ./examples/read/example_read 
Error 8 at (line 5, column 39): 'Content of 'http://xspf.org/ns/0/ location' is not a valid URI.'
Error 8 at (line 12, column 0): 'Content of 'http://xspf.org/ns/0/ track' must be whitespace or child elements, not text.'
Track
        Album: -
        Annotation: 'song'
        Creator: 'Lein'
        Duration: '271066'
        Identifier: 0 entries
        Image: 'file:///tmp/tmp.1Q2l4i6fcC/libxspf/http.com/images/P/B000002J0B.01.MZZZZZZZ.jpg'
        Info: 'http://example.co@'
        Links: 0 entries
        Locations: 0 entries
        Metas: 0 entries
        Title: 'Nr'
        TrackNum: -

Error 8 at (line 28, column 0): 'Content of 'http://xspf.org/ns/0/ trackList' must be whitespace or child elements, not text.'

What am I missing?

I just double check all processes to reproduce the crash and still find problem.

  1. install uriparser (compiled from github source)
  2. compile libxspf
  • in my environment, I changed line 235 (PORT_GETCWD ==> getcwd) and added #include <unistd.h to avoid compilation error (libxspf/examples/read/read.cpp)
  1. download poc_200207 file and overwrite as playlist.xspf
  2. run example_read
 ./example_read 
Error 8 at (line 5, column 39): 'Content of 'http://xspf.org/ns/0/ location' is not a valid URI.'
Error 8 at (line 12, column 0): 'Content of 'http://xspf.org/ns/0/ track' must be whitespace or child elements, not text.'
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
[1]    24214 abort (core dumped)  ./example_read x
* Environment
- OS release
Ubuntu 18.04.4 LTS

- Kernel
Linux jjung-900X5L 5.3.0-40-generic #32~18.04.1-Ubuntu SMP Mon Feb 3 14:05:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

I cannot confirm any bad allocations or bad memory access, only a memory leak. Here's what I did in precise detail:

# cd "$(mktemp -d)"
# git clone --depth 1 https://github.com/uriparser/uriparser/
# cd uriparser/
# git rev-parse HEAD
51bdd9a3cb70c9020715cfe883f606cd5b995b7a
# ./configure -DCMAKE_INSTALL_PREFIX="$PWD"/../prefix/ -DCMAKE_C_COMPILER=clang-9 -DCMAKE_CXX_COMPILER=clang++-9 CMAKE_C_FLAGS='-O1 -g -fsanitize=address -fno-omit-frame-pointer' -DCMAKE_CXX_FLAGS='-O1 -g -fsanitize=address -fno-omit-frame-pointer' LDFLAGS='-fsanitize=address' -DURIPARSER_BUILD_DOCS=OFF && make install
# cd ..
# git clone --depth 1 https://github.com/ezdev128/libxspf/
# cd libxspf/
# git rev-parse HEAD
ba71431e24293510c44d6581e2c05b901a372880
# wget https://gist.githubusercontent.com/hartwork/fa2bf3ebfbaed32f405e7f267c1a9e5b/raw/2d1fc7f7b6ac6cea533cac3574ed4a5385779342/libxspf-1-2-compile.patch
# patch -p1 < libxspf-1-2-compile.patch
# autoreconf -i -f && PKG_CONFIG_PATH="$PWD"/../prefix/lib64/pkgconfig/ ./configure CC=clang-9 CXX=clang++-9 CFLAGS='-O1 -g -fsanitize=address -fno-omit-frame-pointer' CXXFLAGS='-O1 -g -fsanitize=address -fno-omit-frame-pointer' LDFLAGS='-fsanitize=address' --disable-test && make
# wget -Oplaylist.xspf https://gts3.org/~jjung/poc/uriparser/poc_200207
# LD_LIBRARY_PATH="$PWD"/../prefix/lib64/ ./examples/read/example_read
Error 8 at (line 5, column 39): 'Content of 'http://xspf.org/ns/0/ location' is not a valid URI.'
Error 8 at (line 12, column 0): 'Content of 'http://xspf.org/ns/0/ track' must be whitespace or child elements, not text.'
Track
        Album: -
        Annotation: 'song'
        Creator: 'Lein'
        Duration: '271066'
        Identifier: 0 entries
        Image: 'file:///tmp/tmp.rje08pzEEs/libxspf/http.com/images/P/B000002J0B.01.MZZZZZZZ.jpg'
        Info: 'http://example.co@'
        Links: 0 entries
        Locations: 0 entries
        Metas: 0 entries
        Title: 'Nr'
        TrackNum: -

Error 8 at (line 28, column 0): 'Content of 'http://xspf.org/ns/0/ trackList' must be whitespace or child elements, not text.'

=================================================================
==16704==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 80 byte(s) in 1 object(s) allocated from:
    #0 0x4c2e3d in operator new[](unsigned long) /var/tmp/portage/sys-libs/compiler-rt-sanitizers-9.0.1/work/compiler-rt/lib/asan/asan_new_delete.cc:102:3
    #1 0x7f6adf239f60 in Xspf::Toolbox::(anonymous namespace)::makeUriString(UriUriStructA const&) /tmp/tmp.rje08pzEEs/libxspf/src/XspfToolbox.cpp:209:14
    #2 0x7f6adf2395b5 in Xspf::Toolbox::(anonymous namespace)::allocTransformUri(char const*, char const*, bool) /tmp/tmp.rje08pzEEs/libxspf/src/XspfToolbox.cpp:262:31
    #3 0x7f6adf22ea96 in Xspf::XspfReader::handleEndFour(char const*) /tmp/tmp.rje08pzEEs/libxspf/src/XspfReader.cpp:1931:30
    #4 0x7f6adf22f49c in Xspf::XspfReader::handleEnd(char const*) /tmp/tmp.rje08pzEEs/libxspf/src/XspfReader.cpp:2074:9
    #5 0x7f6adf120a2c  (/usr/lib64/libexpat.so.1+0xba2c)

Direct leak of 19 byte(s) in 1 object(s) allocated from:
    #0 0x4c2e3d in operator new[](unsigned long) /var/tmp/portage/sys-libs/compiler-rt-sanitizers-9.0.1/work/compiler-rt/lib/asan/asan_new_delete.cc:102:3
    #1 0x7f6adf239f60 in Xspf::Toolbox::(anonymous namespace)::makeUriString(UriUriStructA const&) /tmp/tmp.rje08pzEEs/libxspf/src/XspfToolbox.cpp:209:14
    #2 0x7f6adf2395b5 in Xspf::Toolbox::(anonymous namespace)::allocTransformUri(char const*, char const*, bool) /tmp/tmp.rje08pzEEs/libxspf/src/XspfToolbox.cpp:262:31
    #3 0x7f6adf22ea0d in Xspf::XspfReader::handleEndFour(char const*) /tmp/tmp.rje08pzEEs/libxspf/src/XspfReader.cpp:1943:29
    #4 0x7f6adf22f49c in Xspf::XspfReader::handleEnd(char const*) /tmp/tmp.rje08pzEEs/libxspf/src/XspfReader.cpp:2074:9
    #5 0x7f6adf120a2c  (/usr/lib64/libexpat.so.1+0xba2c)

SUMMARY: AddressSanitizer: 99 byte(s) leaked in 2 allocation(s).

I reproduced with these commands:

$ cd "$(mktemp -d)"
$ git clone https://github.com/uriparser/uriparser/
$ cd uriparser/
$ ./configure -DURIPARSER_BUILD_DOCS=OFF -DURIPARSER_BUILD_TESTS=OFF
$ make && sudo make install
$ cd ..

$ git clone https://github.com/ezdev128/libxspf/
$ cd libxspf/
$ wget https://gts3.org/~jjung/poc/uriparser/libxspf-getcwd.patch
$ patch -p1 < libxspf-getcwd.patch
$ ./configure
$ make
$ cd examples/read
$ wget -Oplaylist.xspf https://gts3.org/~jjung/poc/uriparser/poc_200207
$ ./example_read
  • OS release
    Ubuntu 18.04.4 LTS

I have tried to reproduce the issue with Ubuntu 18.04.4 now using the Dockerfile inlined below based on your script — it doesn't crash. Does this crash for you?

FROM ubuntu:18.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get --yes --no-install-recommends dist-upgrade && \
    apt-get install --yes --no-install-recommends \
        build-essential \
        ca-certificates \
        cmake \
        file \
        git \
        libexpat-dev \
        libtool \
        lsb-release \
        pkg-config \
        wget

RUN git clone https://github.com/uriparser/uriparser && \
    git clone https://github.com/ezdev128/libxspf

RUN cd libxspf/examples/read && \
    wget -Oplaylist.xspf https://gts3.org/~jjung/poc/uriparser/poc_200207

RUN cd uriparser/ && \
    ./configure -DURIPARSER_BUILD_DOCS=OFF -DURIPARSER_BUILD_TESTS=OFF && \
    make && make install

RUN cd libxspf/ && \
    wget https://gts3.org/~jjung/poc/uriparser/libxspf-getcwd.patch && \
    patch -p1 < libxspf-getcwd.patch

RUN cd libxspf/ && \
    ./configure --disable-test && \
    make

RUN lsb_release -a

RUN cd libxspf/examples/read && \
    { LD_LIBRARY_PATH=/usr/local/lib ./example_read || echo $? ; }

Also, could you provide the output of:

  • ldd ./example_read
  • gdb -batch -ex run -ex bt --args ./example_read

The output of the latter potentially benefits from a re-build with CFLAGS=-g CXXFLAGS=-g to get line numbers and function names rather than hex addresses.

Thank you!

I will try Docker when I am available. This is the quick result.

  • ldd
	linux-vdso.so.1 (0x00007ffd2d1f2000)
	libxspf.so.4 => /usr/local/lib/libxspf.so.4 (0x00007f5cda46b000)
	liburiparser.so.1 => /usr/lib/x86_64-linux-gnu/liburiparser.so.1 (0x00007f5cda250000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5cd9ec7000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5cd9caf000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5cd98be000)
	libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f5cd968c000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5cd92ee000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5cda8a0000)
  • gdb
Error 8 at (line 5, column 39): 'Content of 'http://xspf.org/ns/0/ location' is not a valid URI.'
Error 8 at (line 12, column 0): 'Content of 'http://xspf.org/ns/0/ track' must be whitespace or child elements, not text.'
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff7037801 in __GI_abort () at abort.c:79
#2  0x00007ffff768c957 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7692ab6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff7692af1 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff7692d24 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007ffff769329c in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff7bc57bb in Xspf::Toolbox::(anonymous namespace)::makeUriString (uri=...) at src/XspfToolbox.cpp:209
#8  Xspf::Toolbox::(anonymous namespace)::allocTransformUri (sourceUri=sourceUri@entry=0x55555576d0c0 "http://example.co@", baseUri=0x55555576d040 "file:///tmp/tmp.wyuAGRnNeI/libxspf/examples/read/playlist.xspf", addOrRemoveBase=addOrRemoveBase@entry=true) at src/XspfToolbox.cpp:262
#9  0x00007ffff7bc5a7a in Xspf::Toolbox::makeAbsoluteUri (sourceUri=sourceUri@entry=0x55555576d0c0 "http://example.co@", baseUri=<optimized out>) at src/XspfToolbox.cpp:275
#10 0x00007ffff7bbef93 in Xspf::XspfReader::makeAbsoluteUri (this=this@entry=0x7fffffffdd30, sourceUri=sourceUri@entry=0x55555576d0c0 "http://example.co@") at src/XspfReader.cpp:555
#11 0x00007ffff7bbfbe8 in Xspf::XspfReader::handleEndFour (this=this@entry=0x7fffffffdd30) at src/XspfReader.cpp:1943
#12 0x00007ffff7bc2ae6 in Xspf::XspfReader::handleEnd (this=0x7fffffffdd30, fullName=0x55555576c4d0 "http://xspf.org/ns/0/ info") at src/XspfReader.cpp:2074
#13 0x00007ffff6dcfe28 in ?? () from /lib/x86_64-linux-gnu/libexpat.so.1
#14 0x00007ffff6dd0bfc in ?? () from /lib/x86_64-linux-gnu/libexpat.so.1
#15 0x00007ffff6dce823 in ?? () from /lib/x86_64-linux-gnu/libexpat.so.1
#16 0x00007ffff6dcf50b in ?? () from /lib/x86_64-linux-gnu/libexpat.so.1
#17 0x00007ffff6dd30ed in XML_ParseBuffer () from /lib/x86_64-linux-gnu/libexpat.so.1
#18 0x00007ffff7bc1bd4 in Xspf::XspfReader::parseFile (this=0x7fffffffdd30, filename=<optimized out>, callback=<optimized out>, baseUri=<optimized out>) at src/XspfReader.cpp:619
#19 0x00005555555559f6 in main () at examples/read/read.cpp:263

I found the problem. My machine previously installed liburiparser1 before the test.

After I purge the library, I don't see the error message anymore.

To produce the error, please install liburiparser1 thru APT manager.

I found the problem. My machine previously installed liburiparser1 before the test.

After I purge the library, I don't see the error message anymore.

Yes, because this line in ldd

liburiparser.so.1 => /usr/lib/x86_64-linux-gnu/liburiparser.so.1 (0x00007f5cda250000)

…indicates that:

  • libxspf was linked against uriparser from Ubuntu, likely version 0.8.4-1, not the manual install to /usr/local/
  • uriparser of Git master does not trigger this problem — awesome!

There is a pile of changes including security fixes that Ubuntu bionic does not ship with 0.8.4-1, see this this part of Changelog.
Here's the full Dockerfile to reproduce the crash case with Ubuntu 18.04 / uriparser 0.8.4-1:

FROM ubuntu:18.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get --yes --no-install-recommends dist-upgrade && \
    apt-get install --yes --no-install-recommends \
        build-essential \
        ca-certificates \
        cmake \
        file \
        gdb \
        git \
        libexpat-dev \
        libtool \
        liburiparser-dev \
        lsb-release \
        pkg-config \
        wget

RUN git clone https://github.com/ezdev128/libxspf

RUN cd libxspf/examples/read && \
    wget -Oplaylist.xspf https://gts3.org/~jjung/poc/uriparser/poc_200207

RUN cd libxspf/ && \
    wget https://gts3.org/~jjung/poc/uriparser/libxspf-getcwd.patch && \
    patch -p1 < libxspf-getcwd.patch

RUN cd libxspf/ && \
    ./configure --disable-test && \
    make

RUN lsb_release -a

RUN cd libxspf/examples/read && \
    LD_LIBRARY_PATH=../../.libs/ gdb -batch -ex run -ex bt --args ./.libs/example_read

Changing ubuntu:18.04 to debian:buster "fixes" the problem.
(Reminds me of https://blog.hartwork.org/posts/why-i-recommend-debian-over-ubuntu-by-now/ .)

I'll close this issue as already fixed then.

Thanks for taking care of the issue thoroughly.

I will test with the dev head version later.

For the record, the official libxspf sources at https://gitlab.xiph.org/xiph/libxspf have been updated with the fixes mentioned above and a bit more. So libxspf should now compile out of the box, again.