Hello maintainers!
Using tar and building it with the UBSAN sanitizer I have found a
runtime error in the short_read() function. Running tar with the -xjSv
and --to-stdout arguments and passing a file with specific data
to stdin, an out-of-bounds error occurs.
The problem is that inside the short_read() function we offset the
buffer[] field of the block union by a status value. However since the
buffer field in this union is 512 bytes long, offsetting it by a larger
number of bytes (> 512) will result in an out-of-bounds error.
Here is the stacktrace:
buffer.c:965:31: runtime error: index 4096 out of bounds for type
'char[512]'
#0 0x5a34251b9b02 in short_read /tar\/src/buffer.c:965:31
#1 0x5a34251b35bf in _gnu_flush_read /tar\/src/buffer.c:1884:2
#2 0x5a3425183802 in gnu_flush_read /tar\/src/buffer.c:1892:3
#3 0x5a3425177953 in flush_read /tar\/src/buffer.c:1990:3
#4 0x5a3425176781 in flush_archive /tar\/src/buffer.c:1043:7
#5 0x5a34251745e8 in find_next_block /tar\/src/buffer.c:619:7
#6 0x5a34251863a7 in _open_archive /tar\/src/buffer.c:859:7
#7 0x5a3425183556 in open_archive /tar\/src/buffer.c:2005:3
#8 0x5a34254415f9 in read_and /tar\/src/list.c:180:3
#9 0x5a34256e4cfa in main /tar\/src/tar.c:2894:7
#10 0x71ccc825f09a in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2409a) (BuildId:
79cd7beb3903a9b34e306f52a988d970e13524a6)
#11 0x5a342512a599 in _start (/tar\/src/tar+0x12a599) (BuildId:
f24c97bc1198bcffea19f758ad64f65536cfb420)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior buffer.c:965:31
Since the buffer[] in the block union is the first field, we can offset
the pointer to the union rather than the members.
This diff fixes the error for me:
diff --git a/src/buffer.c b/src/buffer.c
index 1cdeffc6..e2106159 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -962,7 +962,7 @@ short_read (idx_t status)
idx_t left; /* bytes left */
char *more; /* pointer to next byte to read */
- more = record_start->buffer + status;
+ more = ((char *) record_start) + status;
left = record_size - status;
if (left && left % BLOCKSIZE == 0
Steps to reproduce:
1. Build project with UBSAN sanitizer
2. Create a file, that contains information, like this:
echo -e
s"\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\xf8\xc4\x0b\x97\x00\x00\x74\xfb\x84\xca\x10\x00\x30\x40\x00\x7f\x80\x00\x04\x66\x00\x9e\x00\x00\x00\x80\x08\x20\x00\x75\x0d\x53\xf4\x8d\xaa\x00\x1a\x64\xd3\x20\x92\xa7\x94\x0c\x87\xa8\x34\x34\x15\xfa\x93\x42\x0c\x30\x01\x23\x48\xc4\xda\x00\x00\x00\x00\x81\x94\x30\x30\x30\x30\x0a\x8e\x02\x91\x7f\x00\xb9\xd1\xd9\xe0\x21\x30\x1f\x12\x23\x61\x49\xb0\xe0\x54\x4d\x52\xb6\x2e\x30\x8e\x57\x6b\xc9\x24\x1f\x8b\x62\x05\x80"
> crash
3. Run tar as follows:
cat crash | ./src/tar -xjSv --to-stdout
4. Get an ubsan error