diff options
author | rubidium <rubidium@openttd.org> | 2014-04-25 21:29:54 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2014-04-25 21:29:54 +0000 |
commit | 5ef2042819ea612a50b6ba01411cc9b083e34096 (patch) | |
tree | 122f71354001aff8dbda4d047d4f9ec06f2492cc | |
parent | 08eeec15bed443e5c6c0e6cd58f44c604b7aca09 (diff) | |
download | openttd-5ef2042819ea612a50b6ba01411cc9b083e34096.tar.xz |
(svn r26514) -Fix: rewrite link-in-tar handling so it doesn't use strncpy and it doesn't overrun its buffers anymore
-rw-r--r-- | src/fileio.cpp | 51 | ||||
-rw-r--r-- | src/safeguards.h | 2 |
2 files changed, 31 insertions, 22 deletions
diff --git a/src/fileio.cpp b/src/fileio.cpp index 4ef4f1f93..a72950bc7 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -851,29 +851,38 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha char *pos = link; while (*pos != '\0') { - char *next = strchr(link, PATHSEPCHAR); - if (next == NULL) next = pos + strlen(pos); - - /* Skip '.' (current dir) */ - if (next != pos + 1 || pos[0] != '.') { - if (next == pos + 2 && pos[0] == '.' && pos[1] == '.') { - /* level up */ - if (dest[0] == '\0') { - DEBUG(misc, 1, "Ignoring link pointing outside of data directory: %s -> %s", name, link); - break; - } - - /* Truncate 'dest' after last PATHSEPCHAR. - * This assumes that the truncated part is a real directory and not a link. */ - destpos = strrchr(dest, PATHSEPCHAR); - if (destpos == NULL) destpos = dest; - } else { - /* Append at end of 'dest' */ - if (destpos != dest) *(destpos++) = PATHSEPCHAR; - strncpy(destpos, pos, next - pos); // Safe as we do '\0'-termination ourselves - destpos += next - pos; + char *next = strchr(pos, PATHSEPCHAR); + if (next == NULL) { + next = pos + strlen(pos); + } else { + /* Terminate the substring up to the path separator character. */ + *next++= '\0'; + } + + if (strcmp(pos, ".") == 0) { + /* Skip '.' (current dir) */ + } else if (strcmp(pos, "..") == 0) { + /* level up */ + if (dest[0] == '\0') { + DEBUG(misc, 1, "Ignoring link pointing outside of data directory: %s -> %s", name, link); + break; } + + /* Truncate 'dest' after last PATHSEPCHAR. + * This assumes that the truncated part is a real directory and not a link. */ + destpos = strrchr(dest, PATHSEPCHAR); + if (destpos == NULL) destpos = dest; *destpos = '\0'; + } else { + /* Append at end of 'dest' */ + if (destpos != dest) destpos = strecpy(destpos, PATHSEP, lastof(dest)); + destpos = strecpy(destpos, pos, lastof(dest)); + } + + if (destpos >= lastof(dest)) { + DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename); + fclose(f); + return false; } pos = next; diff --git a/src/safeguards.h b/src/safeguards.h index d2b388721..12d704879 100644 --- a/src/safeguards.h +++ b/src/safeguards.h @@ -36,7 +36,7 @@ /* Use strecpy instead. */ #define strcpy SAFEGUARD_DO_NOT_USE_THIS_METHOD -//#define strncpy SAFEGUARD_DO_NOT_USE_THIS_METHOD +#define strncpy SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use strecat instead. */ #define strcat SAFEGUARD_DO_NOT_USE_THIS_METHOD |