mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-05 21:42:47 -05:00
Limit the number of combining chars per terminal cell.
The previous unlimited system was nicely general, but unfortunately meant you could easily DoS a PuTTY-based terminal by sending a printing character followed by an endless stream of identical combining chars. (In fact, due to accidentally-quadratic linked list management, you'd DoS it by using up all the CPU even before you got the point of making it allocate all the RAM.) The new limit is chosen to be 32, more or less arbitrarily. Overlong sequences of combining characters are signalled by turning the whole character cell into U+FFFD REPLACEMENT CHARACTER.
This commit is contained in:
52
terminal.c
52
terminal.c
@ -199,6 +199,8 @@ static void cc_check(termline *line)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void clear_cc(termline *line, int col);
|
||||
|
||||
/*
|
||||
* Add a combining character to a character cell.
|
||||
*/
|
||||
@ -209,7 +211,49 @@ static void add_cc(termline *line, int col, unsigned long chr)
|
||||
assert(col >= 0 && col < line->cols);
|
||||
|
||||
/*
|
||||
* Start by extending the cols array if the free list is empty.
|
||||
* Don't add combining characters at all to U+FFFD REPLACEMENT
|
||||
* CHARACTER. (Partly it's a slightly incoherent idea in the first
|
||||
* place; mostly, U+FFFD is what we generate if a cell already has
|
||||
* too many ccs, in which case we want it to be a fixed point when
|
||||
* further ccs are added.)
|
||||
*/
|
||||
if (line->chars[col].chr == 0xFFFD)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Walk the cc list of the cell in question to find its current
|
||||
* end point.
|
||||
*/
|
||||
size_t ncc = 0;
|
||||
int origcol = col;
|
||||
while (line->chars[col].cc_next) {
|
||||
col += line->chars[col].cc_next;
|
||||
if (++ncc >= CC_LIMIT) {
|
||||
/*
|
||||
* There are already too many combining characters in this
|
||||
* character cell. Change strategy: throw out the entire
|
||||
* chain and replace the main character with U+FFFD.
|
||||
*
|
||||
* (Rationale: extrapolating from UTR #36 section 3.6.2
|
||||
* suggests the principle that it's better to substitute
|
||||
* U+FFFD than to _ignore_ input completely. Also, if the
|
||||
* user copies and pastes an overcombined character cell,
|
||||
* this way it will clearly indicate that we haven't
|
||||
* reproduced the writer's original intentions, instead of
|
||||
* looking as if it was the _writer's_ fault that the 33rd
|
||||
* cc is missing.)
|
||||
*
|
||||
* Per the code above, this will also prevent any further
|
||||
* ccs from being added to this cell.
|
||||
*/
|
||||
clear_cc(line, origcol);
|
||||
line->chars[origcol].chr = 0xFFFD;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend the cols array if the free list is empty.
|
||||
*/
|
||||
if (!line->cc_free) {
|
||||
int n = line->size;
|
||||
@ -229,12 +273,6 @@ static void add_cc(termline *line, int col, unsigned long chr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now walk the cc list of the cell in question.
|
||||
*/
|
||||
while (line->chars[col].cc_next)
|
||||
col += line->chars[col].cc_next;
|
||||
|
||||
/*
|
||||
* `col' now points at the last cc currently in this cell; so
|
||||
* we simply add another one.
|
||||
|
Reference in New Issue
Block a user