# HG changeset patch # User rubidium # Date 2014-04-25 21:29:54 # Node ID c7541491a0722b9342144d98b2a2a2f6048056ab # Parent 1c6c3407d8095117bc7436d897cbda5cd59ed5ea (svn r26514) -Fix: rewrite link-in-tar handling so it doesn't use strncpy and it doesn't overrun its buffers anymore diff --git a/src/fileio.cpp b/src/fileio.cpp --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -851,29 +851,38 @@ bool TarScanner::AddFile(const char *fil 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; - } + char *next = strchr(pos, PATHSEPCHAR); + if (next == NULL) { + next = pos + strlen(pos); + } else { + /* Terminate the substring up to the path separator character. */ + *next++= '\0'; + } - /* 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; + 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 --- 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