Compare commits

...

2 Commits

Author SHA1 Message Date
bb3b36e162 fix: address config injection and SIGCHLD handling
- Sanitize account names to prevent GKeyFile config injection by
  blocking special characters like #, \n, and \r.
- Ensure GLib's SIGCHLD handler is initialized before forking
  external editors to prevent zombie processes.
- Add missing error check for OMEMO random key generation.
- Replace hardcoded console tab ID with a named constant.
- Log invalid JIDs safely to prevent potential null pointer issues.
2026-05-22 18:27:54 +00:00
adab585c09 fix(review): address PR #105 review follow-ups
All checks were successful
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Check spelling (pull_request) Successful in 18s
CI Code / Linux (debian) (pull_request) Successful in 4m45s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m56s
CI Code / Linux (arch) (pull_request) Successful in 5m39s
CI Code / Code Coverage (pull_request) Successful in 6m41s
- src/log.c: log_stderr_init no longer closes STDERR_FILENO immediately
  after dup2(). The previous 'close(dup_fd)' closed fd 2 because dup2
  returns newfd on success; the in-app stderr capture pipe was silently
  dead, dropping libstrophe/openssl error output. Close the original
  stderr_pipe[1] instead and remember that the write end now lives at
  STDERR_FILENO so _log_stderr_close stays correct.

- src/database_sqlite.c: NULL-check sqlite3_mprintf result before
  passing it to sqlite3_exec in the DbVersion bootstrap path.

- src/tools/editor.c: drop three orphan #includes (<fcntl.h>,
  <pthread.h>, <readline/readline.h>) left behind when 9b03e3a50
  removed the async-editor path.

- src/xmpp/jid.c: match the g_new0 allocation in jid_create with
  g_free in jid_destroy. Same behaviour on glibc but stops being a
  foot-gun under custom glib allocators.

Verified with ci-build.sh in Debian docker: all 4 configs pass
(644/0, 605/0, 605/0, 644/0 unit + 130/0 functional).
2026-05-21 15:40:25 +03:00
7 changed files with 26 additions and 10 deletions

View File

@@ -43,7 +43,8 @@ _sanitize_account_name(const char* const name)
gchar* sanitized = g_strdup(name);
gchar* p = sanitized;
while (*p) {
if (*p == '[' || *p == ']' || *p == '=') {
// GKeyFile special characters: [ ] = # \n \r
if (*p == '[' || *p == ']' || *p == '=' || *p == '#' || *p == '\n' || *p == '\r') {
*p = '_';
}
p++;

View File

@@ -232,6 +232,10 @@ _sqlite_init(ProfAccount* account)
auto_sqlite char* init_version_query = sqlite3_mprintf(
"INSERT INTO `DbVersion` (`version`) VALUES (%d) ON CONFLICT(`version`) DO NOTHING",
latest_version);
if (!init_version_query) {
log_error("OOM allocating initial DbVersion insert query");
goto out;
}
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, init_version_query, NULL, 0, &err_msg)) {
goto out;
}

View File

@@ -348,10 +348,11 @@ log_stderr_init(log_level_t level)
goto err_free;
}
int dup_fd = dup2(stderr_pipe[1], STDERR_FILENO);
if (dup_fd < 0)
if (dup2(stderr_pipe[1], STDERR_FILENO) < 0)
goto err_free;
close(dup_fd);
// fd 2 now owns the pipe write end; release the original.
close(stderr_pipe[1]);
stderr_pipe[1] = STDERR_FILENO;
stderr_level = level;
stderr_inited = 1;

View File

@@ -806,6 +806,10 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_
key_tag = gcry_malloc_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH);
key = gcry_random_bytes_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_IV_LENGTH, GCRY_VERY_STRONG_RANDOM);
if (!key) {
log_error("[OMEMO][SEND] cannot generate random key/IV");
goto out;
}
iv = key + AES128_GCM_KEY_LENGTH;
res = aes128gcm_encrypt(ciphertext, &ciphertext_len, tag, &tag_len, (const unsigned char* const)message, strlen(message), iv, key);

View File

@@ -9,14 +9,11 @@
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <fcntl.h>
#include <glib.h>
#include <errno.h>
#include <stdio.h> // necessary for readline
#include <readline/readline.h>
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include "config/files.h"
@@ -124,6 +121,12 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
ui_suspend();
// Ensure GLib's SIGCHLD handler is installed before forking to prevent
// zombie children if the editor is launched before the main loop starts.
GMainContext* main_ctx = g_main_context_default();
g_main_context_acquire(main_ctx);
g_main_context_release(main_ctx);
pid_t pid = fork();
if (pid == -1) {
log_error("[Editor] Failed to fork: %s", strerror(errno));

View File

@@ -55,6 +55,8 @@ static GTimeZone* tz;
static StatusBar* statusbar;
static WINDOW* statusbar_win;
#define CONSOLE_TAB_ID 10 // Console tab ID in status bar hash table
void _get_range_bounds(guint* start, guint* end, gboolean is_static);
static guint _status_bar_draw_time(guint pos);
static guint _status_bar_draw_maintext(guint pos);
@@ -157,7 +159,7 @@ void
status_bar_current(guint i)
{
if (i == 0) {
statusbar->current_tab = 10;
statusbar->current_tab = CONSOLE_TAB_ID;
} else {
statusbar->current_tab = i;
}

View File

@@ -32,6 +32,7 @@ Jid*
jid_create(const gchar* const str)
{
if (!jid_is_valid(str)) {
log_debug("[JID] invalid JID: '%s'", str ?: "(null)");
return NULL;
}
@@ -217,7 +218,7 @@ jid_destroy(Jid* jid)
g_free(jid->resourcepart);
g_free(jid->barejid);
g_free(jid->fulljid);
free(jid);
g_free(jid);
}
gboolean