Skip to content

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

Closed
@sanjeevk001

Description

@sanjeevk001

bsdtar: 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)

What other files were involved?
To trigger the bug, use the the crashing input file crash_file_1 (unzip crash-file.zip).
crash-file.zip

============
Command to reproduce the bug using valgrind:
$ valgrind -v ./bsdtar -t -f crash_file_1

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions