mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 22:28:56 +00:00
(svn r15626) -Fix [FS#2698]: UTF8 string handling could cause buffer overruns.
This commit is contained in:
parent
c3a7e6b693
commit
86ca408d46
@ -97,7 +97,7 @@ void IConsolePrint(ConsoleColour colour_code, const char *string)
|
||||
* 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);
|
||||
|
@ -247,7 +247,7 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length)
|
||||
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 @@ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc
|
||||
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 @@ static void GetFileTitle(const char *file, char *title, const char *last)
|
||||
size_t read = fread(title, 1, last - title, f);
|
||||
assert(title + read <= last);
|
||||
title[read] = '\0';
|
||||
str_validate(title, last);
|
||||
FioFCloseFile(f);
|
||||
}
|
||||
|
||||
|
@ -237,6 +237,7 @@ void Packet::Recv_string(char *buffer, size_t size, bool allow_newlines)
|
||||
{
|
||||
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 @@ void Packet::Recv_string(char *buffer, size_t size, bool allow_newlines)
|
||||
}
|
||||
this->pos = pos;
|
||||
|
||||
str_validate(bufp, allow_newlines);
|
||||
str_validate(bufp, last, allow_newlines);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
@ -232,6 +232,7 @@ static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, u
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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 @@ static void SlString(void *ptr, size_t length, VarType conv)
|
||||
}
|
||||
|
||||
((char*)ptr)[len] = '\0'; // properly terminate the string
|
||||
str_validate((char*)ptr, (char*)ptr + len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,13 +97,27 @@ char *CDECL str_fmt(const char *str, ...)
|
||||
}
|
||||
|
||||
|
||||
void str_validate(char *str, bool allow_newlines, bool ignore)
|
||||
void str_validate(char *str, const char *last, bool allow_newlines, bool ignore)
|
||||
{
|
||||
char *dst = str;
|
||||
WChar c;
|
||||
size_t len;
|
||||
/* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */
|
||||
|
||||
char *dst = str;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
|
||||
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
|
||||
|
@ -93,9 +93,15 @@ int CDECL seprintf(char *str, const char *last, const char *format, ...);
|
||||
|
||||
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);
|
||||
|
@ -235,7 +235,7 @@ static void DedicatedHandleKeyInput()
|
||||
break;
|
||||
}
|
||||
}
|
||||
str_validate(input_line);
|
||||
str_validate(input_line, lastof(input_line));
|
||||
|
||||
IConsoleCmdExec(input_line); // execute command
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user