bsdtar: An error in archive_wstring_append_from_mbs() (archive_string.c) allows out-of-bounds read memory access and subsequently cause a crash

Bug #1851867 reported by Sanjeev Das
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Libarchive
New
Undecided
Unassigned
libarchive (Ubuntu)
New
Undecided
Unassigned

Bug Description

Description:

An error in archive_wstring_append_from_mbs() (archive_string.c) triggers an out-of-bounds read memory access that results into a crash, via a specially crafted archive file. This bug was found using our custom fuzzer.

Basic Information:
Version of libarchive: libarchive-3.4.0, libarchive-3.4.1dev
How you obtained it: build from source
libarchive-3.4.0.tar.gz (https://www.libarchive.org/)
libarchive-3.4.1dev (https://github.com/libarchive/libarchive)
Tested operating system and version: Linux 4.15.0-65-generic x86_64
Tested compilers versions: gcc (version 7.4.0) and clang (version 6.0.0-1ubuntu2)

============
Command to reproduce the bug using valgrind:

$ valgrind -v ./bsdtar -t -f crash_file_1 (in the attachment)

Output (partial):

bsdtar: (null)
bsdtar: Error exit delayed from previous errors.

HEAP SUMMARY:
     in use at exit: 0 bytes in 0 blocks
   total heap usage: 89 allocs, 89 frees, 285,279 bytes allocated

 All heap blocks were freed -- no leaks are possible

 ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)

 2 errors in context 1 of 1:
 Invalid read of size 1
    at 0x5081825: utf8_internal_loop_single (loop.c:427)
    by 0x5081825: __gconv_transform_utf8_internal (skeleton.c:563)
    by 0x5116B12: mbrtowc (mbrtowc.c:86)
    by 0x14D998: archive_wstring_append_from_mbs (archive_string.c:622)
    by 0x14E19B: archive_mstring_get_wcs (archive_string.c:3941)
    by 0x116EF5: archive_entry_pathname_w (archive_entry.c:586)
    by 0x148297: zip_read_local_file_header (archive_read_support_format_zip.c:1038)
    by 0x1487EC: archive_read_format_zip_streamable_read_header (archive_read_support_format_zip.c:3083)
    by 0x11E1AB: _archive_read_next_header2 (archive_read.c:658)
    by 0x11E2FE: _archive_read_next_header (archive_read.c:696)
    by 0x112725: read_archive (read.c:260)
    by 0x112E1F: tar_mode_t (read.c:94)
    by 0x1114C6: main (bsdtar.c:913)
  Address 0x5490f47 is 0 bytes after a block of size 167 alloc'd
    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    by 0x14A6E3: archive_string_ensure (archive_string.c:314)
    by 0x14A78A: archive_string_append (archive_string.c:203)
    by 0x14DF0D: archive_strncat_l (archive_string.c:1980)
    by 0x14E4C5: archive_strncpy_l (archive_string.c:1944)
    by 0x14E4C5: archive_mstring_copy_mbs_len_l (archive_string.c:4153)
    by 0x147D95: zip_read_local_file_header (archive_read_support_format_zip.c:995)
    by 0x1487EC: archive_read_format_zip_streamable_read_header (archive_read_support_format_zip.c:3083)
    by 0x11E1AB: _archive_read_next_header2 (archive_read.c:658)
    by 0x11E2FE: _archive_read_next_header (archive_read.c:696)
    by 0x112725: read_archive (read.c:260)
    by 0x112E1F: tar_mode_t (read.c:94)

 ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)

---------------------------------------------------------------

Possible cause:

In archive_wstring_append_from_mbs() (archive_string.c):

int archive_wstring_append_from_mbs(struct archive_wstring *dest,
    const char *p, size_t len){
    ...
    const char *mbs = p;
    ...
    while (*mbs && mbs_length > 0) {
    ...
    ...
    r = mbrtowc(wcs, mbs, wcs_length, &shift_state);
    ...
    if (r == (size_t)-1 || r == (size_t)-2) {
   ret_val = -1;
   if (errno == EILSEQ) {
    ++mbs;
    --mbs_length;
    continue;
   } else
    break;
  }
    ...
    ...
    }
}

mbrtowc() function is called with the following parameter values: wcs_length = 3, mbs_length = 1, mbs = 0x7ffff6a43ffe "\212".
r = mbrtowc(wcs, mbs, wcs_length, &shift_state);

Here, "mbs" has a length of 1 byte, while, mbrtowc() tends to read 3 bytes (wcs_length = 3), thus resulting into memory out of bounds read.
The program crashes due to memory access violation, which can cause denial of service.

The values {wcs_length = 3, mbs_length = 1} are reached, if return value of mbrtowc() is r = -1 or r = -2 in the previous iteration of the while loop. "mbs" pointer increases (++mbs), and "mbs_length" length decreases (--mbs_length), but wcs_length remains constant (3 bytes in this case).

------------------------------------------------

ProblemType: Bug
DistroRelease: Ubuntu 16.04
Package: bsdtar 3.1.2-11ubuntu0.16.04.7
ProcVersionSignature: Ubuntu 4.4.0-166.195-generic 4.4.194
Uname: Linux 4.4.0-166-generic x86_64
NonfreeKernelModules: openafs nvidia_uvm nvidia_drm nvidia_modeset nvidia
ApportVersion: 2.20.1-0ubuntu2.21
Architecture: amd64
CurrentDesktop: Unity
Date: Fri Nov 8 11:58:45 2019
SourcePackage: libarchive
UpgradeStatus: No upgrade log present (probably fresh install)

Revision history for this message
Sanjeev Das (sanjeevk001) wrote :
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.