Crash in png_convert_from_time_t (libpng1.6.37)
thientc opened this issue ยท 5 comments
Hello libpng team,
This bug was found by FUTAG - a program for automated generating fuzz-targets of libraries (a product of Ivannikov Institute for System Programming of the Russian Academy of Sciences - https://www.ispras.ru/). Thanks to following colleagues: Tran Chi Thien (thientc@ispras.ru) and Shamil Kurmangaleev(kursh@ispras.ru).
Product version: libpng1.6.37
Environment: Ubuntu 18.04
Reprocedure:
Compile fuzz-target generated by FUTAG with libFuzzer:
//fuzz-target of png_convert_from_time_t
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include<png.h>extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if(Size < sizeof(png_time) + sizeof(time_t)) return 0;
uint8_t * pos = (uint8_t *) Data;png_timep ptime = (png_timep) malloc(sizeof(png_time)); memset( ptime, 0, sizeof(ptime)); memcpy(ptime, pos, sizeof(png_time)); pos += sizeof(png_time); time_t ttime = {0}; memcpy(&ttime, pos, sizeof(time_t)); png_convert_from_time_t(ptime, ttime); free( (png_timep) ptime); return 0;
}
Compile script:
clang++ -g -fsanitize=fuzzer,undefined,address png_convert_from_time_t.cc libpng16.so
AddressSanitizer Debug result:
AddressSanitizer:DEADLYSIGNAL
==28273==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000014 (pc 0x7f44491d3860 bp 0x7ffdb5d18a30 sp 0x7ffdb5d18898 T0)
==28273==The signal is caused by a READ memory access.
==28273==Hint: address points to the zero page.
#0 0x7f44491d3860 in png_convert_from_struct_tm /home/futag/libs4test/libpng-1.6.37/pngwrite.c:476
#1 0x7f44491d38b1 in png_convert_from_time_t /home/futag/libs4test/libpng-1.6.37/pngwrite.c:492
#2 0x546d72 in LLVMFuzzerTestOneInput /home/futag/install_libs/libpng/___png_convert_from_time_t_png_timep_time_t/png_convert_from_time_t.cc:19:5
#3 0x444dc6 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:562
#4 0x44c7f8 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:472
#5 0x44e14c in fuzzer::Fuzzer::MutateAndTestOne() /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:709
#6 0x450ee7 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocatorfuzzer::SizedFile >&) /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:846
#7 0x435ce9 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:900
#8 0x41ed92 in main /home/futag/futag/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20
#9 0x7f4448201bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310
#10 0x41ede9 in _start (/home/futag/install_libs/libpng/___png_convert_from_time_t_png_timep_time_t/a.out+0x41ede9)AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/futag/libs4test/libpng-1.6.37/pngwrite.c:476 in png_convert_from_struct_tm
==28273==ABORTING
Analysis:
Function png_convert_from_time_t call function png_convert_from_struct_tm, in which lack of checking input value ttime->tm_year:
ptime->year = (png_uint_16)(1900 + ttime->tm_year);
The code in question calls gmtime
with your time_t
value which seems to be just a zero. It looks like your gmtime
then returned a NULL pointer. I looked at the gmtime manual on FreeBSD but it doesn't note that gmtime can return a null pointer.
- What operating system are you using?
- Is the NULL return value of gmtime documented in the manual page of your OS?
- If you remove all of the code except the following lines,
time_t ttime = {0};
memcpy(&ttime, pos, sizeof(time_t));
png_convert_from_time_t(ptime, ttime);
does the error still occur?
- What operating system are you using?
It's in the first post: Ubuntu 18.04
- Is the NULL return value of gmtime documented in the manual page of your OS?
http://manpages.ubuntu.com/manpages/bionic/man3/ctime.3.html
The gmtime() function converts the calendar time timep to broken-down time representation,
expressed in Coordinated Universal Time (UTC). It may return NULL when the year does not
fit into an integer.
png_convert_from_time_t(png_timep ptime, time_t ttime)
{
struct tm *tbuf;png_debug(1, "in png_convert_from_time_t");
tbuf = gmtime(&ttime);
png_convert_from_struct_tm(ptime, tbuf);
}
In png_convert_from_time_t, gmtime returns NULL, this dues to crash in next fuction png_convert_from_struct_tm
It looks like there needs to be a check for NULL pointers within png_convert_from_time_t
for the sake of Ubuntu. Is it possible you can supply the value of pos
here so that we have a way to reproduce the bug on Ubuntu systems? It's not clear what value of LLVMFuzzerTestOneInput
caused the crash.
You can get these values to test on Ubuntu:
png_timep ptime; ptime->year = 0; ptime->month = 0; ptime->day = 0; ptime->hour = 0; ptime->minute = 0; ptime->second = 0; time_t ttime = 8319119876378817395; png_convert_from_time_t(ptime, ttime);
Fixed in the master branch. Apologies for the delay, and many thanks for your report!