aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2018-05-29 18:11:42 +0200
committerCorinna Vinschen <corinna@vinschen.de>2018-05-29 18:23:14 +0200
commit35998fc2fa6cbb7d761f6d88346246bd3627552b (patch)
treed442b0ffd7abe9f1325b03facc13543586f4c904 /winsup
parent7d00a5e320db60b462be5b330fc1358f706add76 (diff)
downloadnewlib-35998fc2fa6cbb7d761f6d88346246bd3627552b.zip
newlib-35998fc2fa6cbb7d761f6d88346246bd3627552b.tar.gz
newlib-35998fc2fa6cbb7d761f6d88346246bd3627552b.tar.bz2
Cygwin: normalize_win32_path: Avoid buffer underruns
Thanks to Ken Harris <Ken.Harris@mathworks.com> for the diagnosis. When backing up tail to handle a "..", the code only checked that it didn't underrun the destination buffer while removing path components. It did *not* take into account that the first backslash in the path had to be kept intact. Example path to trigger the problem: "C:\A..\..\..\B' Fix this by moving the dst pointer to the first backslash so subsequent tests cannot underrun this position. Also make sure that we always *have* a backslash. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/path.cc33
1 files changed, 25 insertions, 8 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 94f4e88..3c4dd30 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1336,6 +1336,7 @@ int
normalize_win32_path (const char *src, char *dst, char *&tail)
{
const char *src_start = src;
+ const char *dst_start = dst;
bool beg_src_slash = isdirsep (src[0]);
tail = dst;
@@ -1370,27 +1371,43 @@ normalize_win32_path (const char *src, char *dst, char *&tail)
src += 2;
}
}
+ dst = tail;
+ /* If backslash is missing in src, add one. */
+ if (!isdirsep (src[0]))
+ *tail++ = '\\';
}
- if (tail == dst)
+ if (tail == dst_start)
{
if (isdrive (src))
- /* Always convert drive letter to uppercase for case sensitivity. */
- *tail++ = cyg_toupper (*src++);
+ {
+ /* Always convert drive letter to uppercase for case sensitivity. */
+ *tail++ = cyg_toupper (*src++);
+ *tail++ = *src++;
+ dst = tail;
+ /* If backslash is missing in src, add one. */
+ if (!isdirsep (src[0]))
+ *tail++ = '\\';
+ }
else if (*src != '/')
{
if (beg_src_slash)
- tail += cygheap->cwd.get_drive (dst);
- else if (!cygheap->cwd.get (dst, 0))
- return get_errno ();
- else
+ dst = (tail += cygheap->cwd.get_drive (dst));
+ else if (cygheap->cwd.get (dst, 0))
{
tail = strchr (tail, '\0');
if (tail[-1] != '\\')
*tail++ = '\\';
+ dst = tail - 1;
}
+ else
+ return get_errno ();
}
}
+ /* At this point dst points to the first backslash, even if it only gets
+ written in the first iteration of the following loop. Backing up to
+ handle ".." components can not underrun that border (thus avoiding
+ subsequent buffer underruns with fatal results). */
while (*src)
{
/* Strip duplicate /'s. */
@@ -1442,7 +1459,7 @@ normalize_win32_path (const char *src, char *dst, char *&tail)
if (tail > dst + 1 && tail[-1] == '.' && tail[-2] == '\\')
tail--;
*tail = '\0';
- debug_printf ("%s = normalize_win32_path (%s)", dst, src_start);
+ debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
return 0;
}