Subject: Re: Fixes a crash in the Haiku font driver for daemon mode
From: Kyle Ambroff-Kao <[email-masked]>
To: [email-masked]
Cc: Kyle Ambroff-Kao <[email-masked]>
Date: Wed, 02 Apr 2025 23:39:44 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Kyle Ambroff-Kao <[email-masked]> writes:
> Tags: patch
>
> Fix use-after-free bug in the Haiku font driver
>
> * src/haikufont.c: Set objects freed with haikufont_close to NULL so
>   they will not be reused, which seems to happen in daemon mode when all
>   frames have been closed and fonts are garbage collected.
>
> In GNU Emacs 30.1 (build 2, amd64-portbld-freebsd15.0, GTK+ Version
> 3.24.48, cairo version 1.18.2)
> System Description: 15.0-CURRENT
>
> Configured using:
>  'configure --disable-build-details --localstatedir=/var --without-gconf
>  --without-libsystemd --without-selinux --with-x --enable-acl
>  --with-cairo --with-dbus --with-gif --with-gnutls --with-gsettings
>  --with-x-toolkit=gtk3 --with-harfbuzz --with-jpeg
>  --with-file-notification=kqueue --with-lcms2 --without-m17n-flt
>  --without-imagemagick --with-mailutils --with-modules
>  --with-native-compilation=aot --with-sound=oss --without-libotf
>  --without-pgtk --with-png --with-toolkit-scroll-bars --with-sqlite3
>  --with-rsvg --with-threads --with-tiff --with-tree-sitter --with-webp
>  --without-xft --with-xim --with-xml2 --with-xpm --without-xwidgets
>  --x-libraries=/usr/local/lib --x-includes=/usr/local/include
>  --prefix=/usr/local --mandir=/usr/local/share/man
>  --disable-silent-rules --infodir=/usr/local/share/emacs/info/
>  --build=amd64-portbld-freebsd15.0 'CFLAGS=-O2 -pipe
>  -fstack-protector-strong -Wl,-rpath=/usr/local/lib/gcc13 -isystem
>  /usr/local/include -fno-strict-aliasing ' 'CPPFLAGS=-isystem
>  /usr/local/include' 'LDFLAGS= -fstack-protector-strong
>  -Wl,-rpath=/usr/local/lib/gcc13 -L/usr/local/lib/gcc13 -L/usr/local/lib
>  ''
>
> [2. text/patch; haiku-font-double-free.diff]...

This fixes double-free bug in Emacs daemon mode on Haiku. To reproduce:

1. Start emacs with "emacs --daemon"
2. Create a new frame with "emacsclient -c" and then close it.
3. Create a new frame with "emacsclient -c"

Step 3 will cause the Emacs daemon to crash.

  KERN: debug_server: Thread 3616 entered the debugger: Debugger call:
  `tried to free 0xb960bc9fd0 which points at page 232 which is not an
  allocation first page'

The backtrace from Emacs:
   heap_free(void*) + 0x35 
   BFont_close + 0x4d 
   haikufont_close(font*) + 0x29 (/Code/emacs/src/haikufont.c:893)
   sweep_vectors(void) + 0x1af (/Code/emacs/src/alloc.c:3242)
   garbage_collect(void) + 0x7b3 (/Code/emacs/src/alloc.c:7247)
   Ffuncall(ptrdiff_t, Lisp_Object*) + 0x194 (/Code/emacs/src/eval.c:3084)
   internal_condition_case_n(*, ptrdiff_t, Lisp_Object*, Lisp_Object, *)
   + 0x6c (/Code/emacs/src/eval.c:1699)
   safe_funcall(ptrdiff_t, Lisp_Object*) + 0x50 (/Code/emacs/src/eval.c:3114)
   map_keymap_canonical(Lisp_Object,map_keymap_function_t,Lisp_Object,void*)
   + 0x2b (/Code/emacs/src/keymap.c:608)
   ...

It appears that the BFont has already been closed. I think that the
driver is holding on to the pointer to the freed BFont
(into->be_font). This patch addresses this by setting be_font to NULL so
that this pointer will not be freed again.

The same thing applies to info->metrics and info->glyphs, since just
making this change to be_font wasn't enough to avoid crashes.

With this patch I can open and close as many frames as I want without
crashing.

I don't totally understand the interactions here, and I see there are
similar bugs in other font drivers with different workarounds. For
example, in Bug#16069 which I found from xfont.c:xfont_close, it seems
like there is an attempt to just not free the fonts when GC is invoked.

I think the solution in this patch seems a little simpler, but possibly
means that the fonts are initialized every time the frame count goes
from 0 to 1 or more instead of just once for the life of the daemon.