Heap Out-Of-Bounds write in purple_markup_linkify

Fabian Freyer mail at fabianfreyer.de
Sun Jun 6 08:50:43 EDT 2021


Hi there!

There is a heap-based out-of-bounds write in the following code snippet 
in purple_markup_linkify:

     /* strip off trailing periods */
     if (strlen(url_buf) > 0) {
         for (d = url_buf + strlen(url_buf) - 1; *d == '.'; d--, t--)
             *d = '\0';
     }


ASAN Log:
==1190==ERROR: AddressSanitizer: heap-buffer-overflow on address 
0xffff573410af at pc 0xffffa397e7a8 bp 0xfffffa586e30 sp 0xfffffa586e28
READ of size 1 at 0xffff573410af thread T0
     #0 0xffffa397e7a4 in purple_markup_linkify 
/workspaces/pidgin/pidgin/libpurple/util.c:2289:47
     #1 0x537c44 in LLVMFuzzerTestOneInput 
/workspaces/pidgin/pidgin/libpurple/harness.c:20:14
     #2 0x454cb0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char 
const*, unsigned long) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x454cb0)
     #3 0x454658 in fuzzer::Fuzzer::RunOne(unsigned char const*, 
unsigned long, bool, fuzzer::InputInfo*, bool*) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x454658)
     #4 0x455c4c in fuzzer::Fuzzer::MutateAndTestOne() 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x455c4c)
     #5 0x45670c in 
fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, 
fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x45670c)
     #6 0x449078 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned 
char const*, unsigned long)) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x449078)
     #7 0x468d58 in main 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x468d58)
     #8 0xffffa349d874 in __libc_start_main 
(/lib/aarch64-linux-gnu/libc.so.6+0x24874)
     #9 0x4244bc in _start 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x4244bc)

0xffff573410af is located 1 bytes to the left of 32-byte region 
[0xffff573410b0,0xffff573410d0)
allocated by thread T0 here:
     #0 0x50bd08 in realloc 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x50bd08)
     #1 0xffffa3e90ce4 in g_realloc 
(/lib/aarch64-linux-gnu/libglib-2.0.so.0+0x5ace4)
     #2 0xffffa3eae96c in g_string_insert_unichar 
(/lib/aarch64-linux-gnu/libglib-2.0.so.0+0x7896c)
     #3 0xffffa397e91c in purple_markup_linkify 
/workspaces/pidgin/pidgin/libpurple/util.c:2306:6
     #4 0x537c44 in LLVMFuzzerTestOneInput 
/workspaces/pidgin/pidgin/libpurple/harness.c:20:14
     #5 0x454cb0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char 
const*, unsigned long) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x454cb0)
     #6 0x454658 in fuzzer::Fuzzer::RunOne(unsigned char const*, 
unsigned long, bool, fuzzer::InputInfo*, bool*) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x454658)
     #7 0x455c4c in fuzzer::Fuzzer::MutateAndTestOne() 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x455c4c)
     #8 0x45670c in 
fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, 
fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x45670c)
     #9 0x449078 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned 
char const*, unsigned long)) 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x449078)
     #10 0x468d58 in main 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x468d58)
     #11 0xffffa349d874 in __libc_start_main 
(/lib/aarch64-linux-gnu/libc.so.6+0x24874)
     #12 0x4244bc in _start 
(/workspaces/pidgin/pidgin/libpurple/.libs/harness+0x4244bc)


Here, d can be decremented past the beginning of the buffer, leading to 
a nul byte being written before it, if it happens to be 2e.
This bug is very unlikely to be exploitable on little-endian-systems 
using the glibc ptmalloc allocator, as the byte overwritten is the MSB 
of the chunk’s size field, which is almost certainly zero. It may 
however be exploitable with ptmalloc on big-endian systems or systems 
using alternative allocators that don’t keep metadata between chunks 
such as musl’s mallocng, jemalloc, or the macOS zone allocator.

A patch that should fix the oob access is attached.

The bug was found by fuzzing purple_markup_linkify. Feel free to add the 
following fuzzer to libpurple’s OSS-Fuzz:

     #include <stdio.h>
     #include <stdlib.h>
     #include <stdint.h>

     #include "util.h"

     int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
         uint8_t *buf = malloc(Size + 1);
         buf[Size] = 0x0;
         memcpy(buf, Data, Size);
         char *ret = purple_markup_linkify(buf);
         free(ret);
         free(buf);
         return 0;
     }

This work is part of a collaborative effort between Thomas Roth 
<code at stacksmashing.net>, Dominik Maier <mail at dmnk.co>, and myself, 
Fabian Freyer <mail at fabianfreyer.de>.

This report is subject to a 14 day disclosure deadline, after which 
details will be shared publicly. This rather short timeline is chosen to 
prevent abuse in the light of the recent interest in exploitable pidgin 
vulnerabilities.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: purple_markup_linkify-oob.patch
URL: <https://lists.pidgin.im/private/security/attachments/20210606/58c544aa/attachment.ksh>


More information about the security mailing list