From 26d38779e47984381eea38225c6ba8062d3d3dbb Mon Sep 17 00:00:00 2001 From: Ge-org Brohammer Date: Fri, 28 Aug 2026 13:28:34 +0200 Subject: [PATCH] realtek: Fix use-after-free of the SSM error in completion handlers fp_verify_ssm_done(), fp_enroll_ssm_done(), fp_init_ssm_done() and fp_delete_ssm_done() each overwrite the GError they are given: if (fpi_ssm_get_error (ssm)) error = fpi_ssm_get_error (ssm); An SSM completion callback is handed an owned copy of the error -- fpi-ssm.c takes a g_error_copy() before invoking the callback -- whereas fpi_ssm_get_error() is documented as (transfer none), and the machine's own error is freed by the fpi_ssm_free() that immediately follows the callback. Since every fpi_device_*_complete() takes the error as (transfer full), these handlers leak the copy they own and hand the consumer a pointer that is freed moments later. The consumer is then left reading a dangling GError. For fprintd that is fatal: it logs error->message and dies with a general protection fault inside strlen(), taking the session's authentication daemon with it. kernel: traps: fprintd[67901] general protection fault ip:7fcef3b6429c sp:7ffd5f4128a8 error:0 in libc.so.6 #0 __strlen_evex () #3 g_vasprintf () at ../glib/gprintf.c:342 #5 g_strdup_vprintf () at ../glib/gstrfuncs.c:515 #9 delete_enrolled_fingers (user=... "ge-org", finger=FP_FINGER_RIGHT_INDEX) at ../src/device.c:2420 local_error = 0x563c2628bcb0 The assignment is redundant even where it is not harmful, because the error passed to the callback is already a copy of the machine's error; using it directly is both correct and sufficient. fpi_ssm_dup_error() is available for callers that do need an owned copy. No other driver in the tree assigns the borrowed SSM error this way. Reproduced on a Realtek 2541:fa03 (Minisforum AI X1 Pro 470) by enrolling a finger while a template was already present in on-chip storage, which takes the delete path shown above. The same driver bug reaches fprintd a second way, via fp_enroll_ssm_done() -> fpi_device_enroll_complete() -> fprintd's enroll_cb(). --- libfprint/drivers/realtek/realtek.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libfprint/drivers/realtek/realtek.c b/libfprint/drivers/realtek/realtek.c index d207c286..2c5ce06d 100644 --- a/libfprint/drivers/realtek/realtek.c +++ b/libfprint/drivers/realtek/realtek.c @@ -909,9 +909,6 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) fp_info ("Verify complete!"); - if (fpi_ssm_get_error (ssm)) - error = fpi_ssm_get_error (ssm); - if (error && error->domain == FP_DEVICE_RETRY) { if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) @@ -936,9 +933,6 @@ fp_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) fp_info ("Enrollment complete!"); - if (fpi_ssm_get_error (ssm)) - error = fpi_ssm_get_error (ssm); - if (error) { fpi_device_enroll_complete (dev, NULL, error); @@ -958,9 +952,6 @@ fp_init_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) fp_info ("Init complete!"); - if (fpi_ssm_get_error (ssm)) - error = fpi_ssm_get_error (ssm); - fpi_device_open_complete (dev, error); self->task_ssm = NULL; } @@ -972,9 +963,6 @@ fp_delete_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) fp_info ("Delete print complete!"); - if (fpi_ssm_get_error (ssm)) - error = fpi_ssm_get_error (ssm); - fpi_device_delete_complete (dev, error); self->task_ssm = NULL; }