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>
This commit is contained in:
Corinna Vinschen 2018-05-29 18:11:42 +02:00
parent 7d00a5e320
commit 35998fc2fa
1 changed files with 25 additions and 8 deletions

View File

@ -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++);
*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;
}