Fossil SCM
Fix a use-after-free bug in handling of nested inline footnotes. The bug was discovered by fuzzing with <code>'-fsanitize=fuzzer,undefined,address -DFOSSIL_FUZZ'</code> appended to <var>TCCFLAGS</var> in Makefile.in. It's noteworthy that the <code>',undefined,address'</code> part was essential to find the bug (otherwise just 'double-free' was reported). Many thanks to Stephan for documenting the fuzzing procedures and support.
Commit
31e5df5fa2c6443f71f02b064e988e242579ee1fe406df3307ae373f6beba6c9
Parent
7209593814810f1…
2 files changed
+2
-2
+3
-2
+2
-2
| --- Makefile.in | ||
| +++ Makefile.in | ||
| @@ -46,11 +46,11 @@ | ||
| 46 | 46 | |
| 47 | 47 | CFLAGS = @CFLAGS@ |
| 48 | 48 | CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ |
| 49 | 49 | LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ |
| 50 | 50 | BCCFLAGS = @CPPFLAGS@ $(CFLAGS) |
| 51 | -TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H | |
| 51 | +TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H -fsanitize=fuzzer -DFOSSIL_FUZZ | |
| 52 | 52 | INSTALLDIR = $(DESTDIR)@prefix@/bin |
| 53 | 53 | USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ |
| 54 | 54 | SQLITE3_SRC.2 = @SQLITE3_SRC.2@ |
| 55 | 55 | SQLITE3_OBJ.2 = @SQLITE3_OBJ.2@ |
| 56 | 56 | SQLITE3_SHELL_SRC.2 = @SQLITE3_SHELL_SRC.2@ |
| @@ -61,11 +61,11 @@ | ||
| 61 | 61 | # SQLITE3_SHELL_SRC: |
| 62 | 62 | # 0=src/shell.c, 1=src/shell-see.c, 2=$(SQLITE3_SHELL_SRC.2) |
| 63 | 63 | USE_LINENOISE = @USE_LINENOISE@ |
| 64 | 64 | USE_MMAN_H = @USE_MMAN_H@ |
| 65 | 65 | USE_SEE = @USE_SEE@ |
| 66 | -APPNAME = fossil | |
| 66 | +APPNAME = fossil-fuzz | |
| 67 | 67 | |
| 68 | 68 | .PHONY: all tags |
| 69 | 69 | |
| 70 | 70 | include $(SRCDIR)/main.mk |
| 71 | 71 | |
| 72 | 72 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -46,11 +46,11 @@ | |
| 46 | |
| 47 | CFLAGS = @CFLAGS@ |
| 48 | CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ |
| 49 | LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ |
| 50 | BCCFLAGS = @CPPFLAGS@ $(CFLAGS) |
| 51 | TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H |
| 52 | INSTALLDIR = $(DESTDIR)@prefix@/bin |
| 53 | USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ |
| 54 | SQLITE3_SRC.2 = @SQLITE3_SRC.2@ |
| 55 | SQLITE3_OBJ.2 = @SQLITE3_OBJ.2@ |
| 56 | SQLITE3_SHELL_SRC.2 = @SQLITE3_SHELL_SRC.2@ |
| @@ -61,11 +61,11 @@ | |
| 61 | # SQLITE3_SHELL_SRC: |
| 62 | # 0=src/shell.c, 1=src/shell-see.c, 2=$(SQLITE3_SHELL_SRC.2) |
| 63 | USE_LINENOISE = @USE_LINENOISE@ |
| 64 | USE_MMAN_H = @USE_MMAN_H@ |
| 65 | USE_SEE = @USE_SEE@ |
| 66 | APPNAME = fossil |
| 67 | |
| 68 | .PHONY: all tags |
| 69 | |
| 70 | include $(SRCDIR)/main.mk |
| 71 | |
| 72 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -46,11 +46,11 @@ | |
| 46 | |
| 47 | CFLAGS = @CFLAGS@ |
| 48 | CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ |
| 49 | LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ |
| 50 | BCCFLAGS = @CPPFLAGS@ $(CFLAGS) |
| 51 | TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H -fsanitize=fuzzer -DFOSSIL_FUZZ |
| 52 | INSTALLDIR = $(DESTDIR)@prefix@/bin |
| 53 | USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ |
| 54 | SQLITE3_SRC.2 = @SQLITE3_SRC.2@ |
| 55 | SQLITE3_OBJ.2 = @SQLITE3_OBJ.2@ |
| 56 | SQLITE3_SHELL_SRC.2 = @SQLITE3_SHELL_SRC.2@ |
| @@ -61,11 +61,11 @@ | |
| 61 | # SQLITE3_SHELL_SRC: |
| 62 | # 0=src/shell.c, 1=src/shell-see.c, 2=$(SQLITE3_SHELL_SRC.2) |
| 63 | USE_LINENOISE = @USE_LINENOISE@ |
| 64 | USE_MMAN_H = @USE_MMAN_H@ |
| 65 | USE_SEE = @USE_SEE@ |
| 66 | APPNAME = fossil-fuzz |
| 67 | |
| 68 | .PHONY: all tags |
| 69 | |
| 70 | include $(SRCDIR)/main.mk |
| 71 | |
| 72 |
+3
-2
| --- src/markdown.c | ||
| +++ src/markdown.c | ||
| @@ -2777,11 +2777,11 @@ | ||
| 2777 | 2777 | /* inline notes may get appended to rndr.notes.all while rendering */ |
| 2778 | 2778 | while(1){ |
| 2779 | 2779 | struct footnote *aNotes; |
| 2780 | 2780 | const int N = COUNT_FOOTNOTES( allNotes ); |
| 2781 | 2781 | |
| 2782 | - /* make a shallow copy of `origin` */ | |
| 2782 | + /* make a shallow copy of `allNotes` */ | |
| 2783 | 2783 | blob_truncate(notes,0); |
| 2784 | 2784 | blob_appendb(notes, allNotes); |
| 2785 | 2785 | aNotes = CAST_AS_FOOTNOTES(notes); |
| 2786 | 2786 | qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort); |
| 2787 | 2787 | |
| @@ -2795,13 +2795,14 @@ | ||
| 2795 | 2795 | if( x->bRndred || !x->nUsed ) continue; |
| 2796 | 2796 | assert( x->iMark > 0 ); |
| 2797 | 2797 | assert( blob_size(&x->text) ); |
| 2798 | 2798 | blob_truncate(tmp,0); |
| 2799 | 2799 | |
| 2800 | - /* `origin` may be altered and extended through this call */ | |
| 2800 | + /* `allNotes` may be altered and extended through this call */ | |
| 2801 | 2801 | parse_inline(tmp, &rndr, blob_buffer(&x->text), blob_size(&x->text)); |
| 2802 | 2802 | |
| 2803 | + x = CAST_AS_FOOTNOTES(allNotes) + j; | |
| 2803 | 2804 | blob_truncate(&x->text,0); |
| 2804 | 2805 | blob_appendb(&x->text, tmp); |
| 2805 | 2806 | x->bRndred = 1; |
| 2806 | 2807 | } |
| 2807 | 2808 | } |
| 2808 | 2809 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -2777,11 +2777,11 @@ | |
| 2777 | /* inline notes may get appended to rndr.notes.all while rendering */ |
| 2778 | while(1){ |
| 2779 | struct footnote *aNotes; |
| 2780 | const int N = COUNT_FOOTNOTES( allNotes ); |
| 2781 | |
| 2782 | /* make a shallow copy of `origin` */ |
| 2783 | blob_truncate(notes,0); |
| 2784 | blob_appendb(notes, allNotes); |
| 2785 | aNotes = CAST_AS_FOOTNOTES(notes); |
| 2786 | qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort); |
| 2787 | |
| @@ -2795,13 +2795,14 @@ | |
| 2795 | if( x->bRndred || !x->nUsed ) continue; |
| 2796 | assert( x->iMark > 0 ); |
| 2797 | assert( blob_size(&x->text) ); |
| 2798 | blob_truncate(tmp,0); |
| 2799 | |
| 2800 | /* `origin` may be altered and extended through this call */ |
| 2801 | parse_inline(tmp, &rndr, blob_buffer(&x->text), blob_size(&x->text)); |
| 2802 | |
| 2803 | blob_truncate(&x->text,0); |
| 2804 | blob_appendb(&x->text, tmp); |
| 2805 | x->bRndred = 1; |
| 2806 | } |
| 2807 | } |
| 2808 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -2777,11 +2777,11 @@ | |
| 2777 | /* inline notes may get appended to rndr.notes.all while rendering */ |
| 2778 | while(1){ |
| 2779 | struct footnote *aNotes; |
| 2780 | const int N = COUNT_FOOTNOTES( allNotes ); |
| 2781 | |
| 2782 | /* make a shallow copy of `allNotes` */ |
| 2783 | blob_truncate(notes,0); |
| 2784 | blob_appendb(notes, allNotes); |
| 2785 | aNotes = CAST_AS_FOOTNOTES(notes); |
| 2786 | qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort); |
| 2787 | |
| @@ -2795,13 +2795,14 @@ | |
| 2795 | if( x->bRndred || !x->nUsed ) continue; |
| 2796 | assert( x->iMark > 0 ); |
| 2797 | assert( blob_size(&x->text) ); |
| 2798 | blob_truncate(tmp,0); |
| 2799 | |
| 2800 | /* `allNotes` may be altered and extended through this call */ |
| 2801 | parse_inline(tmp, &rndr, blob_buffer(&x->text), blob_size(&x->text)); |
| 2802 | |
| 2803 | x = CAST_AS_FOOTNOTES(allNotes) + j; |
| 2804 | blob_truncate(&x->text,0); |
| 2805 | blob_appendb(&x->text, tmp); |
| 2806 | x->bRndred = 1; |
| 2807 | } |
| 2808 | } |
| 2809 |