5fcf2c
From c8c367581c3333c38d07481e2ea8d81171403c81 Mon Sep 17 00:00:00 2001
5fcf2c
From: David Mitchell <davem@iabyn.com>
5fcf2c
Date: Mon, 26 Oct 2020 15:11:14 +0000
5fcf2c
Subject: [PATCH] PathTools/Cwd.xs: fix off-by-one in bsd_realpath()
5fcf2c
MIME-Version: 1.0
5fcf2c
Content-Type: text/plain; charset=UTF-8
5fcf2c
Content-Transfer-Encoding: 8bit
5fcf2c
5fcf2c
At the heart of this function is a loop which repeatedly finds the next
5fcf2c
component in the path, processes it, then chops that component off the
5fcf2c
front of the path by shifting the string to the start of the buffer;
5fcf2c
i.e. something like:
5fcf2c
5fcf2c
    while (remaining_len) {
5fcf2c
        s = strchr(remaining, '/')
5fcf2c
        ...
5fcf2c
        remaining_len -= s - remaining;
5fcf2c
        memmove(remaining, s, remaining_len + 1);
5fcf2c
    }
5fcf2c
5fcf2c
The problem is that the per-iteration decrement to remaining_len doesn't
5fcf2c
take account of the '/' character, so each iteration, remaining_len gets
5fcf2c
one more byte too big.
5fcf2c
5fcf2c
It turns out that this is harmless - it just means that more and more
5fcf2c
garbage characters after the trailing null byte get copied each time,
5fcf2c
but after each copy the path string is still well formed, with a
5fcf2c
trailing null in the right place. So just the random garbage after the
5fcf2c
null byte is different.
5fcf2c
5fcf2c
This commit fixes that.
5fcf2c
5fcf2c
Although really, it would be better to just increment the
5fcf2c
start-of-string pointer each time rather than shift the whole string
5fcf2c
each time.
5fcf2c
5fcf2c
Signed-off-by: Petr Písař <ppisar@redhat.com>
5fcf2c
---
5fcf2c
 dist/PathTools/Cwd.xs | 15 ++++++++++++---
5fcf2c
 1 file changed, 12 insertions(+), 3 deletions(-)
5fcf2c
5fcf2c
diff --git a/dist/PathTools/Cwd.xs b/dist/PathTools/Cwd.xs
5fcf2c
index 8662400e47..e7ecb3c6c1 100644
5fcf2c
--- a/dist/PathTools/Cwd.xs
5fcf2c
+++ b/dist/PathTools/Cwd.xs
5fcf2c
@@ -119,15 +119,24 @@ bsd_realpath(const char *path, char resolved[MAXPATHLEN])
5fcf2c
 
5fcf2c
             p = strchr(remaining, '/');
5fcf2c
             s = p ? p : remaining + remaining_len;
5fcf2c
+
5fcf2c
             if ((STRLEN)(s - remaining) >= (STRLEN)sizeof(next_token)) {
5fcf2c
                 errno = ENAMETOOLONG;
5fcf2c
                 return (NULL);
5fcf2c
             }
5fcf2c
             memcpy(next_token, remaining, s - remaining);
5fcf2c
             next_token[s - remaining] = '\0';
5fcf2c
-            remaining_len -= s - remaining;
5fcf2c
-            if (p != NULL)
5fcf2c
-                memmove(remaining, s + 1, remaining_len + 1);
5fcf2c
+
5fcf2c
+            /* shift first component off front of path, including '/' */
5fcf2c
+            if (p) {
5fcf2c
+                s++; /* skip '/' */
5fcf2c
+                remaining_len -= s - remaining;
5fcf2c
+                /* the +1 includes the trailing '\0' */
5fcf2c
+                memmove(remaining, s, remaining_len + 1);
5fcf2c
+            }
5fcf2c
+            else
5fcf2c
+                remaining_len = 0;
5fcf2c
+
5fcf2c
             if (resolved[resolved_len - 1] != '/') {
5fcf2c
                 if (resolved_len + 1 >= MAXPATHLEN) {
5fcf2c
                     errno = ENAMETOOLONG;
5fcf2c
-- 
5fcf2c
2.25.4
5fcf2c