Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in png_convert_from_time_t (libpng1.6.37) #362

Closed
thientc opened this issue Feb 8, 2021 · 5 comments
Closed

Crash in png_convert_from_time_t (libpng1.6.37) #362

thientc opened this issue Feb 8, 2021 · 5 comments

Comments

@thientc
Copy link

thientc commented Feb 8, 2021

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

@benkasminbullock
Copy link
Contributor

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?

@thientc
Copy link
Author

thientc commented Feb 9, 2021

  • 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

@benkasminbullock
Copy link
Contributor

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.

@thientc
Copy link
Author

thientc commented Feb 9, 2021

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

png_convert_from_time_t.zip

@ctruta
Copy link
Member

ctruta commented Sep 13, 2022

Fixed in the master branch. Apologies for the delay, and many thanks for your report!

@ctruta ctruta closed this as completed Sep 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants