libarchive / libarchive

Multi-format archive and compression library

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SAST: Possible size_t underflow when calling the `archive_write_get_bytes_per_block` function

ljavorsk opened this issue · comments

The archive_write_get_bytes_per_block function can return a negative value if the archive_check_magic fails. This will result in having this value assigned to bpb variable (e.g. in file libarchive/archive_write_add_filter_zstd.c:367).
Since the value will underflow the size_t it will be a very big number and the if condition bpb > bs will be true, thus assigning bpb to bs.
Then assigning data->out.size = bs; and lastly allocating the unwanted size of the memory data->out.dst = (unsigned char *)malloc(data->out.size);

I'm not an expert on libarchive internals, but I assume this could result in overusing the memory.

This problem occurs in every usage of archive_write_get_bytes_per_block function.

If archive_check_magic fails, it's already a programming error in the caller. The entire point of that function and its calls is to sanity check the archive state.

Alright, so, will it terminate the program when the programming error is in the caller before the allocations I pointed out?

Looking at the code, I believe the check for the archive_check_magic fail is missing. If it fails and returns a negative value, it won't be detected and the behaviour is undefined.

Changing the size_t bs = ZSTD_CStreamOutSize(), bpb; to ssize_t bs = ZSTD_CStreamOutSize(), bpb; and then having an if condition to check if the bpb < 0 would catch this error and terminate the program.

archive_check_magic is a macro that will return with ARCHIVE_FATAL on error conditions. As I said, any code path that triggers this is already UB and the only point of the macro is trying to fail more gracefully. It's normally checked at the entry point of all major functions, but in some cases the return value doesn't fit very well. For the open/bid functions, the caller already has ensured this unless some other form of memory corruption happens.

Sorry for the spam of the changing commits. I believe this could detect the error right after it occurs and return the ARCHIVE_FATAL

I don't think archive_check_magic can ever fail when called from archive_write_get_bytes_per_block in these cases. If you think it can, could you please explain?

However, I don't see any protection against someone mistakenly setting the bytes-per-block value to zero or a negative value. We should probably change set_bytes_per_block to do nothing if given a value less than one, and change get_bytes_per_block to return 1 if the bytes-per-block value is less than 1.

@kientzle Does this new PR make better sense to you? #2206

As the PR was merged, we can close this issue