CVE-2023-40032: NULL Pointer Dereference (CWE-476)
value: libvips is a demand-driven, horizontally threaded image processing library. A specially crafted SVG input can cause libvips versions 8.14.3 or earlier to segfault when attempting to parse a malformed UTF-8 character. Users should upgrade to libvips version 8.14.4 (or later) when processing untrusted input.

CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 5.5
Published: 2023-09-11T19:15Z
Repository: https://github.com/libvips/libvips
Language: Other
Files changed: ChangeLog, libvips/foreign/svgload.c
Commit date: 2023-08-13 15:48:54 +0200
Commit message: svgload: fix null-pointer dereference (#3604)

`g_utf8_find_next_char()` might return NULL when called with a
non-NULL second argument, indicating that the end of the string
has been reached.
Diff: diff --git a/ChangeLog b/ChangeLog
index e47ee86bb..b7544219e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
+TBD 8.14.4
+
+- fix null-pointer dereference during svgload [kleisauke]
+
 20/7/23 8.14.3
 
 - fix ICC handling of greyscale images with a incompatible profile [kleisauke]
 - fix use-after-free during tiff pyramid save [kleisauke]
 - fix vips7 PNG load and save when using libspng [jcupitt]
diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c
index 94072581d..aefd412ed 100644
--- a/libvips/foreign/svgload.c
+++ b/libvips/foreign/svgload.c
@@ -143,11 +143,11 @@ vips_foreign_load_svg_zfree( void *opaque, void *ptr )
 #endif /*HANDLE_SVGZ*/
 
 /* Find a utf-8 substring within the first len_bytes (not characters). 
  *
  *   - case-insensitive
- *   - needle must be zero-terminated, but hackstack need not be
+ *   - needle must be zero-terminated, but haystack need not be
  *   - haystack can be null-terminated
  *   - if haystack is shorter than len bytes, that'll end the search 
  *   - if we hit invalid utf-8, we return NULL
  */
 static const char *
@@ -189,24 +189,36 @@ vips_utf8_strcasestr( const char *haystack_start, const char *needle_start,
 				a == (gunichar) -2 ||
 				b == (gunichar) -1 ||
 				b == (gunichar) -2 )
                                 return( NULL );
 
-                        /* End of haystack. There can't be a complete needle
-                         * anywhere.
+                        /* Disallow codepoint U+0000 as it's a nul byte.
+                         * This is redundant with GLib >= 2.63.0, see:
+                         * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/967
                          */
+#if !GLIB_CHECK_VERSION( 2, 63, 0 )
                         if( a == (gunichar) 0 )
                                 return( NULL );
+#endif
 
                         /* Mismatch.
                          */
                         if( g_unichar_tolower( a ) != g_unichar_tolower( b ) )
                                 break;
 
                         haystack_char = 
 				g_utf8_find_next_char( haystack_char, 
 					haystack_start + len_bytes );
+
+                        /* End of haystack. There can't be a complete needle
+                         * anywhere.
+                         */
+                        if( haystack_char == NULL )
+                                return( NULL );
+
+                        /* needle_char will never be NULL.
+                         */
                         needle_char = 
 				g_utf8_find_next_char( needle_char, NULL );
                 }
 
                 if( i == needle_len )

Vulnerable code:  *   - needle must be zero-terminated, but hackstack need not be
                        /* End of haystack. There can't be a complete needle
                         * anywhere.
Fixed code: TBD 8.14.4

- fix null-pointer dereference during svgload [kleisauke]

 *   - needle must be zero-terminated, but haystack need not be
                        /* Disallow codepoint U+0000 as it's a nul byte.
                         * This is redundant with GLib >= 2.63.0, see:
                         * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/967
#if !GLIB_CHECK_VERSION( 2, 63, 0 )
#endif

                        /* End of haystack. There can't be a complete needle
                         * anywhere.
                         */
                        if( haystack_char == NULL )
                                return( NULL );

                        /* needle_char will never be NULL.
                         */