From 7a137f03539181ef47cad0610e871470b1cfd0ab Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 22 Oct 2024 16:09:31 +0300 Subject: [PATCH] syslog: Don't allow blocking when in signal handler Blocking while running a signal handler is not advisable, instead write the log string character by character. There is also a potential for a deadlock, as discussed in #6618 Note: querying for rtcb->sigdeliver is not 100% ideal, as it only tells _if_ a signal handler has been queued, not if it is running. However, it makes syslog safe / usable which is a debug feature anyhow. --- drivers/syslog/syslog_write.c | 39 ++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/syslog/syslog_write.c b/drivers/syslog/syslog_write.c index 2573384050..f8d8ae739f 100644 --- a/drivers/syslog/syslog_write.c +++ b/drivers/syslog/syslog_write.c @@ -37,6 +37,43 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: syslog_safe_to_block + * + * Description: + * Check if it is safe to block for write. If not, the write defaults to a + * non-blocking method. + * + * Input Parameters: + * None. + * + * Returned Value: + * true if it is safe to block; false otherwise. + * + ****************************************************************************/ + +static bool syslog_safe_to_block(void) +{ + FAR const struct tcb_s *rtcb; + + /* It's not safe to block in interrupts or when executing the idle loop */ + + if (up_interrupt_context() || sched_idletask()) + { + return false; + } + + /* It's not safe to block if a signal is being delivered */ + + rtcb = nxsched_self(); + if (rtcb->sigdeliver != NULL) + { + return false; + } + + return true; +} + /**************************************************************************** * Name: syslog_default_write * @@ -59,7 +96,7 @@ static ssize_t syslog_default_write(FAR const char *buffer, size_t buflen) { size_t nwritten; - if (up_interrupt_context() || sched_idletask()) + if (!syslog_safe_to_block()) { #ifdef CONFIG_SYSLOG_INTBUFFER if (up_interrupt_context())