libarchive / libarchive

Multi-format archive and compression library

Home Page:http://www.libarchive.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Segmentation fault while reading a RAR file

eriklax opened this issue · comments

On Linux and FreeBSD, while reading a specific "RAR archive data, v4, os: Win32" file, and while not reading all data in all files (hence skipping over with archive_read_data_skip). When reaching a specific file in a archive this crash occurres.

Important! If not skipping file < 141, and reading all data, it does not crash

Backtrace:

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
0x00000008004b621f in memcpy () from /lib/libc.so.7
(gdb) bt
#0  0x00000008004b621f in memcpy () from /lib/libc.so.7
#1  0x00000008002db819 in copy_from_lzss_window_to_unp (a=0x80121a000, buffer=0x7fffffffe988, startpos=1280, length=-855)
    at /build/libarchive/libarchive/archive_read_support_format_rar.c:3102
#2  0x00000008002db642 in read_data_compressed (a=0x80121a000, buff=0x7fffffffe988, size=0x7fffffffe980, offset=0x7fffffffe978, looper=1)
    at /build/libarchive/libarchive/archive_read_support_format_rar.c:2204
#3  0x00000008002d8417 in archive_read_format_rar_read_data (a=0x80121a000, buff=0x7fffffffe988, size=0x7fffffffe980, offset=0x7fffffffe978)
    at /build/libarchive/libarchive/archive_read_support_format_rar.c:1130
#4  0x00000008002a1a82 in _archive_read_data_block (_a=0x80121a000, buff=0x7fffffffe988, size=0x7fffffffe980, offset=0x7fffffffe978)
    at /build/libarchive/libarchive/archive_read.c:986
#5  0x00000008003090f6 in archive_read_data_block (a=0x80121a000, buff=0x7fffffffe988, s=0x7fffffffe980, o=0x7fffffffe978) at /build/libarchive/libarchive/archive_virtual.c:161
#6  0x0000000000201c83 in main ()

ret = expand(a, &end);
if (ret != ARCHIVE_OK)
return (ret);

This expand() make the end go from

start = 1280 end = 1792
to
start = 1280 end = 425

Explaining the length=-855 from the gdb backtrace

#include <archive.h>
#include <archive_entry.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
	struct archive* archive = archive_read_new();
	archive_read_support_filter_all(archive);
	archive_read_support_format_all(archive);

	if (archive_read_open_filename(archive, argv[1], 10240) != ARCHIVE_OK)
		return 1;

	struct archive_entry *entry;
	const void *buff = NULL;
	size_t size = 0;
	off_t offset = 0;
	int r;

	size_t y = 0;
	while (++y)
	{
		int r = archive_read_next_header(archive, &entry);
		if (r != ARCHIVE_OK)
		{
			if (r == ARCHIVE_EOF)
				break;
			return 1;
		}

		if (archive_read_data_block(archive, &buff, &size, &offset) != ARCHIVE_OK)
			break;

		if (y < 141)
			continue;

		while ((r = archive_read_data_block(archive, &buff, &size, &offset)) == ARCHIVE_OK) // crashes here
			;
	}
	archive_read_free(archive);
	return 0;
}

I just ran into this issue last week as well. Making the change below to right after the expand()/if code seemed to fix crash:

-      rar->bytes_uncopied = end - start;
+      rar->bytes_uncopied = end > start ? end - start : 0;

but I don't know if that has any unintended side effect. Would be good to get an "official" fix.