gettext-tiny icon indicating copy to clipboard operation
gettext-tiny copied to clipboard

TODO: fuzzing

Open rofl0r opened this issue 7 years ago • 7 comments

as now gettext-tiny supports quite a lot or almost all features of .po files, we should run some stress-tests with afl-fuzz, paired with asan so out-of-bounds reads get caught. better we do that before a release so no CVEs get filed :)

rofl0r avatar May 06 '17 16:05 rofl0r

Hi, I'm not familiar with the .po "lifecycle" (creation, modifying, usage, etc). My understanding is you feed a source file (test.c) into one of the programs and it spits out a .po file. Is that basically it? I'd be glad to help fuzz if you can provide a few example inputs, outputs, and any other programs that may be required (glue code to make the library read from a file, etc)

rwhitworth avatar May 17 '17 17:05 rwhitworth

yeah, however we do not bother with creation of .po files, we just make .mo files from it. a good candidate for testing is for example the tarball of coreutils, which ships a ton of .po files.

Mar 26 05:08:59 <redacted>    in coreutils, all the .gmo files are already built
Mar 26 05:09:16 <redacted>    you need to delete them if you want to test msgfmt
Mar 26 05:09:52 <redacted>    ~/x-prefix/i486/src/build/coreutils/coreutils-8.20/po $ make de.gmo 
Mar 26 05:09:52 <redacted>    rm -f de.gmo && /bin/msgfmt -c --statistics --verbose -o de.gmo de.po
Mar 26 05:09:52 <redacted>    No Statistics available.

that's basically it. :) there are a lot of other release tarballs that ship .po files, like vim, irssi, etc, but i think any of them is good enough to create a small test corpus. thanks for considering to help !

rofl0r avatar May 17 '17 20:05 rofl0r

@xhebox : do you know off the top of your head a package that ships .po files which use rarely used features like fuzzy marks and msg-ctx ?

rofl0r avatar May 17 '17 20:05 rofl0r

@rofl0r the instructions were very helpful. See https://github.com/rwhitworth/gettext-tiny-fuzz

Valgrind output from a few of the inputs (not exhaustive):

==2208800== Memcheck, a memory error detector
==2208800== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2208800== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==2208800== Command: ../msgfmt -c -o /tmp/test.gmo id:000000,sig:06,src:000001,op:flip1,pos:0
==2208800==
==2208800== Conditional jump or move depends on uninitialised value(s)
==2208800==    at 0x446966: __linkin_atfork (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x425243: ptmalloc_init.part.7 (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x42558D: malloc_hook_ini (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4684C2: _dl_get_origin (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4471DE: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2208800==
==2208800== Conditional jump or move depends on uninitialised value(s)
==2208800==    at 0x4215B9: _int_free (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2208800==
==2208800== Conditional jump or move depends on uninitialised value(s)
==2208800==    at 0x42161F: _int_free (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2208800==
==2208800== Use of uninitialised value of size 8
==2208800==    at 0x403D3F: main (msgfmt.c:481)
==2208800==
==2208800== Conditional jump or move depends on uninitialised value(s)
==2208800==    at 0x416EF2: raise (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4170B7: abort (in /root/gettext-tiny/msgfmt)
==2208800==    by 0x4061F1: poparser_feed_line (poparser.c:201)
==2208800==    by 0x4036A6: process (msgfmt.c:432)
==2208800==    by 0x405174: main (msgfmt.c:558)
==2208800==
==2208800==
==2208800== HEAP SUMMARY:
==2208800==     in use at exit: 0 bytes in 0 blocks
==2208800==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2208800==
==2208800== All heap blocks were freed -- no leaks are possible
==2208800==
==2208800== For counts of detected and suppressed errors, rerun with: -v
==2208800== Use --track-origins=yes to see where uninitialised values come from
==2208800== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)
==2755569== Memcheck, a memory error detector
==2755569== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2755569== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==2755569== Command: ../msgfmt -c -o /tmp/test.gmo id:000040,sig:06,src:000024+000085,op:splice,rep:32
==2755569==
==2755569== Conditional jump or move depends on uninitialised value(s)
==2755569==    at 0x446966: __linkin_atfork (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x425243: ptmalloc_init.part.7 (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x42558D: malloc_hook_ini (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4684C2: _dl_get_origin (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4471DE: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2755569==
==2755569== Conditional jump or move depends on uninitialised value(s)
==2755569==    at 0x4215B9: _int_free (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2755569==
==2755569== Conditional jump or move depends on uninitialised value(s)
==2755569==    at 0x42161F: _int_free (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2755569==
==2755569== Use of uninitialised value of size 8
==2755569==    at 0x403D3F: main (msgfmt.c:481)
==2755569==
==2755569== Conditional jump or move depends on uninitialised value(s)
==2755569==    at 0x4432A7: __strstr_sse2_unaligned (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x405B24: get_type_and_start (poparser.c:46)
==2755569==    by 0x405B24: poparser_feed_line (poparser.c:175)
==2755569==    by 0x4036A6: process (msgfmt.c:432)
==2755569==    by 0x405174: main (msgfmt.c:558)
==2755569==
==2755569== Conditional jump or move depends on uninitialised value(s)
==2755569==    at 0x416EF2: raise (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4170B7: abort (in /root/gettext-tiny/msgfmt)
==2755569==    by 0x4061F1: poparser_feed_line (poparser.c:201)
==2755569==    by 0x4036A6: process (msgfmt.c:432)
==2755569==    by 0x405174: main (msgfmt.c:558)
==2755569==
==2755569==
==2755569== HEAP SUMMARY:
==2755569==     in use at exit: 0 bytes in 0 blocks
==2755569==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2755569==
==2755569== All heap blocks were freed -- no leaks are possible
==2755569==
==2755569== For counts of detected and suppressed errors, rerun with: -v
==2755569== Use --track-origins=yes to see where uninitialised values come from
==2755569== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
==2936624== Memcheck, a memory error detector
==2936624== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2936624== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==2936624== Command: ../msgfmt -c -o /tmp/test.gmo id:000030,sig:11,src:000005,op:havoc,rep:8
==2936624==
==2936624== Conditional jump or move depends on uninitialised value(s)
==2936624==    at 0x446966: __linkin_atfork (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x425243: ptmalloc_init.part.7 (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x42558D: malloc_hook_ini (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4684C2: _dl_get_origin (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4471DE: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2936624==
==2936624== Conditional jump or move depends on uninitialised value(s)
==2936624==    at 0x4215B9: _int_free (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2936624==
==2936624== Conditional jump or move depends on uninitialised value(s)
==2936624==    at 0x42161F: _int_free (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x461EDC: fillin_rpath (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4624E2: _dl_init_paths (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x4476B4: _dl_non_dynamic_init (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x448257: __libc_init_first (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x407445: (below main) (in /root/gettext-tiny/msgfmt)
==2936624==
==2936624== Use of uninitialised value of size 8
==2936624==    at 0x403D3F: main (msgfmt.c:481)
==2936624==
==2936624== Conditional jump or move depends on uninitialised value(s)
==2936624==    at 0x4221EF: _int_malloc (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x424D05: calloc (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x403544: process (msgfmt.c:422)
==2936624==    by 0x405174: main (msgfmt.c:558)
==2936624==
==2936624== Conditional jump or move depends on uninitialised value(s)
==2936624==    at 0x4215B9: _int_free (in /root/gettext-tiny/msgfmt)
==2936624==    by 0x401B49: process_line_callback (msgfmt.c:366)
==2936624==    by 0x405F1A: poparser_feed_line (poparser.c:191)
==2936624==    by 0x4036A6: process (msgfmt.c:432)
==2936624==    by 0x405174: main (msgfmt.c:558)
==2936624==
==2936624== Invalid read of size 4
==2936624==    at 0x403985: process (msgfmt.c:459)
==2936624==    by 0x405174: main (msgfmt.c:558)
==2936624==  Address 0x4 is not stack'd, malloc'd or (recently) free'd
==2936624==
==2936624==
==2936624== Process terminating with default action of signal 11 (SIGSEGV)
==2936624==  Access not within mapped region at address 0x4
==2936624==    at 0x403985: process (msgfmt.c:459)
==2936624==    by 0x405174: main (msgfmt.c:558)
==2936624==  If you believe this happened as a result of a stack
==2936624==  overflow in your program's main thread (unlikely but
==2936624==  possible), you can try to increase the size of the
==2936624==  main thread stack using the --main-stacksize= flag.
==2936624==  The main thread stack size used in this run was 8388608.
==2936624==
==2936624== HEAP SUMMARY:
==2936624==     in use at exit: 0 bytes in 0 blocks
==2936624==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2936624==
==2936624== All heap blocks were freed -- no leaks are possible
==2936624==
==2936624== For counts of detected and suppressed errors, rerun with: -v
==2936624== Use --track-origins=yes to see where uninitialised values come from
==2936624== ERROR SUMMARY: 17 errors from 9 contexts (suppressed: 0 from 0)

rwhitworth avatar May 18 '17 02:05 rwhitworth

cool, thanks a lot! will you keep the repo with the crash-testcases on your profile for a while?

rofl0r avatar May 18 '17 19:05 rofl0r

Yeah, they'll be up for at least a month. Eventually I'll consolidate all my fuzzing repos to keep my repo list clean, but it'll be a while.

Let me know if I can be of further assistance. I'll be glad to test again after changes are made to help verify.

rwhitworth avatar May 19 '17 00:05 rwhitworth

@rofl0r from krita, the most complex and biggest single translation file i guess.

==2796== Memcheck, a memory error detector
==2796== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.G
==2796== Command: msgfmt -o a krita.po
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x40929B: memchr (memchr.c:19)
==2796==    by 0x40981C: twoway_strstr (strstr.c:101)
==2796==    by 0x4029FB: get_type_and_start (poparser.c:20)
==2796==    by 0x4030F5: poparser_feed_line (poparser.c:175)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x409427: strchrnul (strchrnul.c:21)
==2796==    by 0x409347: strchr (strchr.c:7)
==2796==    by 0x40075D: sysdep_transform (msgfmt.c:162)
==2796==    by 0x4014BA: process_line_callback (msgfmt.c:301)
==2796==    by 0x403274: poparser_feed_line (poparser.c:191)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x409427: strchrnul (strchrnul.c:21)
==2796==    by 0x409347: strchr (strchr.c:7)
==2796==    by 0x40999B: strstr (strstr.c:145)
==2796==    by 0x4029FB: get_type_and_start (poparser.c:20)
==2796==    by 0x4030F5: poparser_feed_line (poparser.c:175)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x409427: strchrnul (strchrnul.c:21)
==2796==    by 0x409347: strchr (strchr.c:7)
==2796==    by 0x40999B: strstr (strstr.c:145)
==2796==    by 0x402CBC: get_type_and_start (poparser.c:46)
==2796==    by 0x4030F5: poparser_feed_line (poparser.c:175)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x409427: strchrnul (strchrnul.c:21)
==2796==    by 0x409347: strchr (strchr.c:7)
==2796==    by 0x40999B: strstr (strstr.c:145)
==2796==    by 0x402D71: get_type_and_start (poparser.c:56)
==2796==    by 0x4030F5: poparser_feed_line (poparser.c:175)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x4094FC: strlen (strlen.c:15)
==2796==    by 0x402E01: get_length_and_convert (poparser.c:71)
==2796==    by 0x4031CE: poparser_feed_line (poparser.c:184)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x4094FC: strlen (strlen.c:15)
==2796==    by 0x402E01: get_length_and_convert (poparser.c:71)
==2796==    by 0x4032AF: poparser_feed_line (poparser.c:193)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x405714: __malloc0 (malloc.c:375)
==2796==    by 0x401B46: process (msgfmt.c:421)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x405714: __malloc0 (malloc.c:375)
==2796==    by 0x401B66: process (msgfmt.c:422)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x405714: __malloc0 (malloc.c:375)
==2796==    by 0x401B92: process (msgfmt.c:423)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x405714: __malloc0 (malloc.c:375)
==2796==    by 0x401BAE: process (msgfmt.c:424)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x4094FC: strlen (strlen.c:15)
==2796==    by 0x40160E: process_line_callback (msgfmt.c:320)
==2796==    by 0x403274: poparser_feed_line (poparser.c:191)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x400A4B: writemsg (msgfmt.c:207)
==2796==    by 0x4018B4: process_line_callback (msgfmt.c:351)
==2796==    by 0x403274: poparser_feed_line (poparser.c:191)
==2796==    by 0x401C56: process (msgfmt.c:432)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Syscall param writev(vector[...]) points to uninitialised byte(s)
==2796==    at 0x40A944: __syscall3 (syscall_arch.h:29)
==2796==    by 0x40A944: __stdio_write (__stdio_write.c:15)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401DCA: process (msgfmt.c:456)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796==  Address 0x4000134 is in the brk data segment 0x4000000-0x4063fff
==2796== 
==2796== Syscall param writev(vector[...]) points to uninitialised byte(s)
==2796==    at 0x40A944: __syscall3 (syscall_arch.h:29)
==2796==    by 0x40A944: __stdio_write (__stdio_write.c:15)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401E66: process (msgfmt.c:460)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796==  Address 0x4000110 is in the brk data segment 0x4000000-0x4063fff
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x406399: __fwritex (fwrite.c:10)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401EAF: process (msgfmt.c:462)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Syscall param writev(vector) points to uninitialised byte(s)
==2796==    at 0x40A944: __syscall3 (syscall_arch.h:29)
==2796==    by 0x40A944: __stdio_write (__stdio_write.c:15)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401EAF: process (msgfmt.c:462)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796==  Address 0xffeff29f8 is on thread 1's stack
==2796==  in frame #0, created by __stdio_write (syscall_arch.h:5)
==2796== 
==2796== Syscall param writev(vector[...]) points to uninitialised byte(s)
==2796==    at 0x40A944: __syscall3 (syscall_arch.h:29)
==2796==    by 0x40A944: __stdio_write (__stdio_write.c:15)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401EAF: process (msgfmt.c:462)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796==  Address 0x4000114 is in the brk data segment 0x4000000-0x4063fff
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x40A94F: __stdio_write (__stdio_write.c:16)
==2796==    by 0x4064FA: fwrite (fwrite.c:33)
==2796==    by 0x401EAF: process (msgfmt.c:462)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== Conditional jump or move depends on uninitialised value(s)
==2796==    at 0x4064FE: fwrite (fwrite.c:35)
==2796==    by 0x401EAF: process (msgfmt.c:462)
==2796==    by 0x40291B: main (msgfmt.c:558)
==2796== 
==2796== 
==2796== HEAP SUMMARY:
==2796==     in use at exit: 0 bytes in 0 blocks
==2796==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2796== 
==2796== All heap blocks were freed -- no leaks are possible
==2796== 
==2796== For counts of detected and suppressed errors, rerun with: -v
==2796== Use --track-origins=yes to see where uninitialised values come from
==2796== ERROR SUMMARY: 55338 errors from 20 contexts (suppressed: 0 from 0)

So, we got segfault examples in gettext-tiny-fuzz? I'll look in to them this week.. :)

xhebox avatar May 19 '17 05:05 xhebox