From dd9de4250f7dc9601ab30e1f5f2bbcc9b1a1c950 Mon Sep 17 00:00:00 2001 From: Daniel Markstedt Date: Fri, 8 May 2026 23:08:11 +0200 Subject: [PATCH] CVE-2026-44076: netatalk: fix Spotlight volume path shell quoting Reported-by: @00redbeer Signed-off-by: Daniel Markstedt --- etc/netatalk/netatalk.c | 113 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/etc/netatalk/netatalk.c b/etc/netatalk/netatalk.c index 991ac8138..d105255ef 100644 --- a/etc/netatalk/netatalk.c +++ b/etc/netatalk/netatalk.c @@ -87,26 +87,113 @@ static bool service_running(pid_t pid) } #ifdef WITH_SPOTLIGHT +static bstring quote_gvariant_string(const char *str) +{ + bstring quoted = bfromcstr("\""); + + if (quoted == NULL) { + return NULL; + } + + for (const unsigned char *p = (const unsigned char *)str; *p; p++) { + int rc; + + switch (*p) { + case '\\': + rc = bcatcstr(quoted, "\\\\"); + break; + + case '"': + rc = bcatcstr(quoted, "\\\""); + break; + + case '\n': + rc = bcatcstr(quoted, "\\n"); + break; + + case '\r': + rc = bcatcstr(quoted, "\\r"); + break; + + case '\t': + rc = bcatcstr(quoted, "\\t"); + break; + + default: + rc = bconchar(quoted, (char) * p); + break; + } + + if (rc != BSTR_OK) { + bdestroy(quoted); + return NULL; + } + } + + if (bconchar(quoted, '"') != BSTR_OK) { + bdestroy(quoted); + return NULL; + } + + return quoted; +} + +static bstring quote_shell_arg(const char *str) +{ + bstring quoted = bfromcstr("'"); + + if (quoted == NULL) { + return NULL; + } + + for (const char *p = str; *p; p++) { + int rc; + + if (*p == '\'') { + rc = bcatcstr(quoted, "'\\''"); + } else { + rc = bconchar(quoted, *p); + } + + if (rc != BSTR_OK) { + bdestroy(quoted); + return NULL; + } + } + + if (bconchar(quoted, '\'') != BSTR_OK) { + bdestroy(quoted); + return NULL; + } + + return quoted; +} + /*! Set indexers to index all our volumes */ static int set_sl_volumes(void) { EC_INIT; const struct vol *volumes, *vol; - struct bstrList *vollist = bstrListCreate(); + struct bstrList *vollist = NULL; int sysret; - bstring sep = bfromcstr(", "); - bstring volnamelist = NULL, cmd = NULL; + bstring sep = NULL, volnamelist = NULL, gvariant = NULL, shellarg = NULL; + bstring cmd = NULL; + EC_NULL_LOG(vollist = bstrListCreate()); + EC_NULL_LOG(sep = bfromcstr(", ")); EC_NULL_LOG(volumes = getvolumes()); for (vol = volumes; vol; vol = vol->v_next) { if (vol->v_flags & AFPVOL_SPOTLIGHT) { - bstring volnamequot = bformat("'%s'", vol->v_path); + bstring volnamequot = quote_gvariant_string(vol->v_path); + EC_NULL_LOG(volnamequot); if (vollist->qty == vollist->mlen && bstrListAlloc(vollist, vollist->qty + 1) != BSTR_OK) { LOG(log_error, logtype_default, "set_sl_volumes: failed to initialize indexing for %s", bdata(volnamequot)); + bdestroy(volnamequot); + EC_FAIL; } vollist->entry[vollist->qty] = volnamequot; @@ -115,9 +202,15 @@ static int set_sl_volumes(void) } volnamelist = bjoin(vollist, sep); + EC_NULL_LOG(volnamelist); + gvariant = bformat("[%s]", bdata(volnamelist)); + EC_NULL_LOG(gvariant); + shellarg = quote_shell_arg(bdata(gvariant)); + EC_NULL_LOG(shellarg); cmd = bformat("gsettings set " INDEXER_DBUS_NAME - " index-recursive-directories \"[%s]\"", - bdata(volnamelist) ? bdata(volnamelist) : ""); + " index-recursive-directories %s", + bdata(shellarg)); + EC_NULL_LOG(cmd); LOG(log_debug, logtype_sl, "set_sl_volumes: %s", bdata(cmd)); sysret = system(bdata(cmd)); @@ -157,6 +250,14 @@ static int set_sl_volumes(void) bdestroy(sep); } + if (gvariant) { + bdestroy(gvariant); + } + + if (shellarg) { + bdestroy(shellarg); + } + if (vollist) { bstrListDestroy(vollist); }