From fbeb553b73cab7ee91bb9b352e1b13cc4e10339a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 3 Jul 2026 09:00:41 +1000 Subject: [PATCH] util1: fix clean_fname ".." collapse off-by-one After the backward walk, s points at the first char of the prior component and s[-1] is its leading '/', so the boundary test must read s[-1] (not *s) and t must reset to s (not s+1). The old off-by-one left CFN_COLLAPSE_DOT_DOT_DIRS dead for all multi-component and absolute paths. The peer-traversal guard CFN_REFUSE_DOT_DOT_DIRS is checked first and is unaffected, so this is a normalization-correctness fix, not a traversal hole. Reported-by: Leonid Bugaev --- util1.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/util1.c b/util1.c index 8c9c0070..c4672c43 100644 --- a/util1.c +++ b/util1.c @@ -1085,9 +1085,14 @@ int clean_fname(char *name, int flags) while (s > limit && s[-1] != '/') s--; - /* If found prior '/', or we reached the start, adjust t. */ - if (s != t - 1 && (s <= name || *s == '/')) { - t = (s == name) ? name : s + 1; + /* If found prior '/', or we reached the start, adjust t. + * After the backward walk, s points at the first char of the + * prior component and s[-1] is its leading '/' -- so test + * s[-1] (not *s) and reset t to s (not s+1) to actually drop + * the component; the old off-by-one left CFN_COLLAPSE_DOT_DOT_DIRS + * dead for multi-component and absolute paths. */ + if (s != t - 1 && (s <= name || s[-1] == '/')) { + t = (s == name) ? name : s; f += 2; continue; }