#1106293 usbguard-notifier: Crashes with "terminate called after throwing an instance of 'std::runtime_error'"

Package:
usbguard-notifier
Source:
usbguard-notifier
Description:
user-friendly notifications for usbguard
Submitter:
Jan
Date:
2025-07-03 13:53:01 UTC
Severity:
normal
#1106293#5
Date:
2025-05-22 16:22:28 UTC
From:
To:
Dear Maintainer,

after launching `usbguard-notifier` it runs fine. When I connect a USB-C hub to machine, however,
a few notifications do appear (as expected) but `usbguard-notifier` crashes with

terminate called after throwing an instance of 'std::runtime_error'
  what():  Failed to show notification


This behaviour is reproducible reliably on my KDE-based system. I tried running in GDB, following
https://wiki.debian.org/HowToGetABacktrace to get debug information. But these seem to be
missing for the relevant source file.


Excerpt from the GDB session:

terminate called after throwing an instance of 'std::runtime_error'
  what():  Failed to show notification
[Thread 0x7fffeffff6c0 (LWP 3429811) exited]

Thread 5 "usbguard-notifi" received signal SIGABRT, Aborted.
[Switching to Thread 0x7fffef7fe6c0 (LWP 3429812)]
Download failed: Invalid argument.  Continuing without source file ./nptl/./nptl/pthread_kill.c.
__pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
warning: 44     ./nptl/pthread_kill.c: No such file or directory
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
#1  0x00007ffff709e9ff in __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
#2  0x00007ffff7049cc2 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff70324ac in __GI_abort () at ./stdlib/abort.c:73
#4  0x00007ffff72a1a3d in __gnu_cxx::__verbose_terminate_handler () at ../../../../src/libstdc++-v3/libsupc++/vterminate.cc:95
#5  0x00007ffff72b344a in __cxxabiv1::__terminate (handler=<optimized out>) at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48
#6  0x00007ffff72a15e9 in std::terminate () at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:58
#7  0x00007ffff72b36c8 in __cxxabiv1::__cxa_throw (obj=<optimized out>, tinfo=0x7ffff7456eb8 <typeinfo for std::runtime_error>, dest=0x7ffff72c85e0 <std::runtime_error::~runtime_error()>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:98
#8  0x00005555555588a5 in usbguardNotifier::Notifier::sendDevicePresenceNotification (this=this@entry=0x7fffffffda40, info=...) at src/Notifier.cpp:176
#9  0x000055555555aa2b in usbguardNotifier::Notifier::sendDevicePresenceCountdownCallback (this=0x7fffffffda40, id=46) at src/Notifier.cpp:140
#10 0x00007ffff72e1224 in std::execute_native_thread_routine (__p=0x7fffe8101410) at ../../../../../src/libstdc++-v3/src/c++11/thread.cc:104
#11 0x00007ffff709cb7b in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:448
#12 0x00007ffff711a7b8 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
(gdb) up 8
Download failed: Invalid argument.  Continuing without source file ./src/Notifier.cpp.
#8  0x00005555555588a5 in usbguardNotifier::Notifier::sendDevicePresenceNotification (this=this@entry=0x7fffffffda40, info=...) at src/Notifier.cpp:176
warning: 176    src/Notifier.cpp: No such file or directory
(gdb) l
171     in src/Notifier.cpp


and a disassembly of the area where the crash was triggered


(gdb) set print asm-demangle on
(gdb) disassemble /s
[...]
   0x000055555555887c <-6644>:  mov    0x278(%rsp),%rax
   0x0000555555558884 <-6636>:  sub    %fs:0x28,%rax
   0x000055555555888d <-6627>:  jne    0x5555555588c5 <usbguardNotifier::Notifier::sendDevicePresenceNotification(usbguardNotifier::Notifier::DevicePresenceInfo&)-6571>
   0x000055555555888f <-6625>:  mov    0xc712(%rip),%rdx        # 0x555555564fa8
   0x0000555555558896 <-6618>:  mov    0xc733(%rip),%rsi        # 0x555555564fd0
   0x000055555555889d <-6611>:  mov    %rbp,%rdi
   0x00005555555588a0 <-6608>:  call   0x555555558330 <__cxa_throw@plt>
=> 0x00005555555588a5 <-6603>:  endbr64


I can provide a compressed transcript of the full GDB session if you consider that useful.


Best regards,
Jan

#1106293#10
Date:
2025-06-07 15:28:47 UTC
From:
To:
Hello,
might this be a similar issue like in this bug [1].

The source is browsable in [2].
But more interesting would be why n.show() returns false,
e.g. which function is in [3] getting called?

There was also once a similar upstream bug reported,
unfortunately abandoned by the opener. [4]

I am not sure if source code should get automatically downloaded.
But one can also download it manually with `apt source usbguard-notifier`,
and telling gdb to use that directory with `directory /path/to/source/usbguard-notifier`.

Kind regards,
Bernhard


[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1028363

[2] https://sources.debian.org/src/usbguard-notifier/0.1.0-3/src/Notifier.cpp/#L176

[3] https://sources.debian.org/src/usbguard-notifier/0.1.0-3/src/NotifyWrapper.cpp/#L72

[4] https://github.com/Cropi/usbguard-notifier/issues/64

#1106293#15
Date:
2025-06-20 17:05:58 UTC
From:
To:
Sorry for the delay. I've been away from my system for some time.

I doubt it since I do get notifications sometimes. My feeling is that it crashes after the last notification when there are multiple in a row.

My current workaround is `while :; do usbguard-notifier > /dev/null; date; done` where `date` is only there so I know when it crashed.

Indeed.

Thanks. I'll give that a try.


Regards, Jan

#1106293#20
Date:
2025-06-25 17:56:15 UTC
From:
To:
Downloading the source archives and setting `directory` appropriately in GDB, I traced this bug further. Unfortunately, usbguard-notifier spawns one thread per event which makes debugging a bit non-linear and cumbersome.

After two or three more wrappers, `notify_notification_show` [4] gets called, which in turn calls `g_dbus_proxy_call_sync` and tests its return value. So I added a breakpoint there

```
break 'libnotify/notification.c':1230
commands
print result
cont
end
```

and for one of the parallel threads the result is indeed `$4 = (GVariant *) 0x0`. I'll follow up when I find more time. Just wanted to document the current progress.


[4] https://sources.debian.org/src/libnotify/0.8.6-1/libnotify/notification.c/#L1122


Regards, Jan

#1106293#25
Date:
2025-06-25 19:04:35 UTC
From:
To:
Sorry for spamming but this was bothering me so I continued looking into it.

So I instrumented GDB to change this. Due to the multi threading, I had to allocate a pool of memory right at the program start. (GDB fails if you have it call a function and some other thread runs into a breakpoint.)

GDB script:
```
set breakpoint pending on

break main
commands
set $MEM=(GError***)((void * (*) (size_t)) malloc) (100*sizeof(GError))
cont
end

break 'libnotify/notification.c':1124
commands
set error=&$MEM[$_thread]
set *error=0
cont
end

break 'libnotify/notification.c':1230 if !result

run
```

Extremely hacky but works :-D

Once the last breakpoint does trigger, I can finally examine the error reported by libnotifier

```(gdb) print **error
$4 = {domain = 182, code = 36,
  message = 0x7fffe4007750 "GDBus.Error:org.freedesktop.Notifications.Error.ExcessNotificationGeneration: Created too many similar notifications in quick succession"}
```

This makes sense and explains why the bug never triggers when you connect a simple device. A USB hub, on the other hand, comprises multiple USB devices even when none are connected to it yet.

So a possible fix would be to use a limiter, distributing the messages over time. Or even better, to actually check the error from libnotifier, wait some (configurable?) time and try again.


Regards, Jan

#1106293#30
Date:
2025-07-03 13:52:01 UTC
From:
To:
Regards, Jan