Mercurial > hg > openttd
changeset 11277:15487697cc18 draft
(svn r15626) -Fix [FS#2698]: UTF8 string handling could cause buffer overruns.
author | rubidium <rubidium@openttd.org> |
---|---|
date | Fri, 06 Mar 2009 01:23:25 +0000 |
parents | 687950e794be |
children | d1a6e82f03c5 |
files | src/console.cpp src/fios.cpp src/network/core/packet.cpp src/saveload/oldloader.cpp src/saveload/saveload.cpp src/string.cpp src/string_func.h src/video/dedicated_v.cpp |
diffstat | 8 files changed, 37 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/console.cpp +++ b/src/console.cpp @@ -97,7 +97,7 @@ * characters and (when applicable) assign it to the console buffer */ str = strdup(string); str_strip_colours(str); - str_validate(str); + str_validate(str, str + strlen(str)); if (_network_dedicated) { fprintf(stdout, "%s\n", str);
--- a/src/fios.cpp +++ b/src/fios.cpp @@ -247,7 +247,7 @@ t = (t == NULL) ? filename : (t + 1); } strecpy(fios->title, t, lastof(fios->title)); - str_validate(fios->title); + str_validate(fios->title, lastof(fios->title)); return true; } @@ -292,7 +292,7 @@ fios->mtime = 0; strecpy(fios->name, d_name, lastof(fios->name)); snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name); - str_validate(fios->title); + str_validate(fios->title, lastof(fios->title)); } } closedir(dir); @@ -344,6 +344,7 @@ size_t read = fread(title, 1, last - title, f); assert(title + read <= last); title[read] = '\0'; + str_validate(title, last); FioFCloseFile(f); }
--- a/src/network/core/packet.cpp +++ b/src/network/core/packet.cpp @@ -237,6 +237,7 @@ { PacketSize pos; char *bufp = buffer; + const char *last = buffer + size - 1; /* Don't allow reading from a closed socket */ if (cs->HasClientQuit()) return; @@ -253,7 +254,7 @@ } this->pos = pos; - str_validate(bufp, allow_newlines); + str_validate(bufp, last, allow_newlines); } #endif /* ENABLE_NETWORK */
--- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -232,6 +232,7 @@ bool ret = VerifyOldNameChecksum(temp, len); temp[len - 2] = '\0'; // name is nul-terminated in savegame, but it's better to be sure + str_validate(temp, last); return ret; }
--- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -33,6 +33,7 @@ #include "../statusbar_gui.h" #include "../fileio_func.h" #include "../gamelog.h" +#include "../string_func.h" #include "table/strings.h" @@ -631,6 +632,7 @@ } ((char*)ptr)[len] = '\0'; // properly terminate the string + str_validate((char*)ptr, (char*)ptr + len); } }
--- a/src/string.cpp +++ b/src/string.cpp @@ -97,13 +97,27 @@ } -void str_validate(char *str, bool allow_newlines, bool ignore) +void str_validate(char *str, const char *last, bool allow_newlines, bool ignore) { + /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ + char *dst = str; - WChar c; - size_t len; + while (*str != '\0') { + size_t len = Utf8EncodedCharLen(*str); + /* If the character is unknown, i.e. encoded length is 0 + * we assume worst case for the length check. + * The length check is needed to prevent Utf8Decode to read + * over the terminating '\0' if that happens to be placed + * within the encoding of an UTF8 character. */ + if ((len == 0 && str + 4 > last) || str + len > last) break; - for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) { + WChar c; + len = Utf8Decode(&c, str); + /* It's possible to encode the string termination character + * into a multiple bytes. This prevents those termination + * characters to be skipped */ + if (c == '\0') break; + if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) { /* Copy the character back. Even if dst is current the same as str * (i.e. no characters have been changed) this is quicker than
--- a/src/string_func.h +++ b/src/string_func.h @@ -93,9 +93,15 @@ char *CDECL str_fmt(const char *str, ...); -/** Scans the string for valid characters and if it finds invalid ones, - * replaces them with a question mark '?' */ -void str_validate(char *str, bool allow_newlines = false, bool ignore = false); +/** + * Scans the string for valid characters and if it finds invalid ones, + * replaces them with a question mark '?' (if not ignored) + * @param str the string to validate + * @param last the last valid character of str + * @param allow_newlines whether newlines should be allowed or ignored + * @param ignore whether to ignore or replace with a question mark + */ +void str_validate(char *str, const char *last, bool allow_newlines = false, bool ignore = false); /** Scans the string for colour codes and strips them */ void str_strip_colours(char *str);