From 6aed28b40a0410ec47d40c8c7296d8d10bae7576 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Fri, 13 Jul 2018 11:16:33 -0700 Subject: [PATCH] Sanitize POP bcache paths. Protect against bcache directory path traversal for UID values. Thanks for Jeriko One for the bug report and patch, which this commit is based upon. --- pop.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/pop.c b/pop.c index d9d95fbe..288166de 100644 --- a/pop.c +++ b/pop.c @@ -40,6 +40,25 @@ #define HC_FEXT "hcache" /* extension for hcache as POP lacks paths */ #endif +/** + * cache_id - Make a message-cache-compatible id + * @param id POP message id + * @retval ptr Sanitised string + * + * The POP message id may contain '/' and other awkward characters. + * + * @note This function returns a pointer to a static buffer. + */ +static const char *cache_id(const char *id) +{ + static char clean[SHORT_STRING]; + + strfcpy (clean, id, sizeof(clean)); + mutt_sanitize_filename (clean, 1); + + return clean; +} + /* write line to file */ static int fetch_message (char *line, void *file) { @@ -205,7 +224,7 @@ static int msg_cache_check (const char *id, body_cache_t *bcache, void *data) /* message not found in context -> remove it from cache * return the result of bcache, so we stop upon its first error */ - return mutt_bcache_del (bcache, id); + return mutt_bcache_del (bcache, cache_id (id)); } #ifdef USE_HCACHE @@ -355,7 +374,7 @@ static int pop_fetch_headers (CONTEXT *ctx) * - if we also have a body: read * - if we don't have a body: new */ - bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0; + bcached = mutt_bcache_exists (pop_data->bcache, cache_id (ctx->hdrs[i]->data)) == 0; ctx->hdrs[i]->old = 0; ctx->hdrs[i]->read = 0; if (hcached) @@ -531,7 +550,7 @@ static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno) unsigned short bcache = 1; /* see if we already have the message in body cache */ - if ((msg->fp = mutt_bcache_get (pop_data->bcache, h->data))) + if ((msg->fp = mutt_bcache_get (pop_data->bcache, cache_id (h->data)))) return 0; /* @@ -578,7 +597,7 @@ static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno) M_PROGRESS_SIZE, NetInc, h->content->length + h->content->offset - 1); /* see if we can put in body cache; use our cache as fallback */ - if (!(msg->fp = mutt_bcache_put (pop_data->bcache, h->data, 1))) + if (!(msg->fp = mutt_bcache_put (pop_data->bcache, cache_id (h->data), 1))) { /* no */ bcache = 0; @@ -624,7 +643,7 @@ static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno) * portion of the headers, those required for the main display. */ if (bcache) - mutt_bcache_commit (pop_data->bcache, h->data); + mutt_bcache_commit (pop_data->bcache, cache_id (h->data)); else { cache->index = h->index; @@ -704,7 +723,7 @@ static int pop_sync_mailbox (CONTEXT *ctx, int *index_hint) snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno); if ((ret = pop_query (pop_data, buf, sizeof (buf))) == 0) { - mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data); + mutt_bcache_del (pop_data->bcache, cache_id (ctx->hdrs[i]->data)); #if USE_HCACHE mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen); #endif -- 2.18.0