xmlread.pp, tighten up checks while parsing the xml declaration:

* Hard limit of literal lengths: 3 on version, 30 on encoding name, 2 or 3 on standalone. Without this, a misplaced quote could cause excessive amount of processing, because input buffer is reloaded by small 3-char chunks at this time.
* Encoding validity is checked in-line, the very first illegal character aborts processing.

git-svn-id: trunk@13961 -
This commit is contained in:
sergei 2009-10-26 21:23:24 +00:00
parent 158afbb5b4
commit 461fde4ed0

View File

@ -883,7 +883,11 @@ begin
if (FBufEnd >= FBuf + Length(arg)) or Reload then if (FBufEnd >= FBuf + Length(arg)) or Reload then
Result := CompareMem(Pointer(arg), FBuf, Length(arg)*sizeof(WideChar)); Result := CompareMem(Pointer(arg), FBuf, Length(arg)*sizeof(WideChar));
if Result then if Result then
begin
Inc(FBuf, Length(arg)); Inc(FBuf, Length(arg));
if FBuf >= FBufEnd then
Reload;
end;
end; end;
{ TXMLDecodingSource } { TXMLDecodingSource }
@ -2018,10 +2022,16 @@ begin
FatalError('Unterminated processing instruction', -1); FatalError('Unterminated processing instruction', -1);
end; end;
const
verStr: array[Boolean] of WideString = ('1.0', '1.1');
procedure TXMLReader.ParseXmlOrTextDecl(TextDecl: Boolean); procedure TXMLReader.ParseXmlOrTextDecl(TextDecl: Boolean);
var var
TmpStr: WideString; TmpStr: WideString;
IsXML11: Boolean; IsXML11: Boolean;
Delim: WideChar;
buf: array[0..31] of WideChar;
I: Integer;
begin begin
SkipS(True); SkipS(True);
// [24] VersionInfo: optional in TextDecl, required in XmlDecl // [24] VersionInfo: optional in TextDecl, required in XmlDecl
@ -2029,18 +2039,26 @@ begin
begin begin
ExpectString('version'); ExpectString('version');
ExpectEq; ExpectEq;
SkipQuotedLiteral(TmpStr); SkipQuote(Delim);
IsXML11 := False; StoreLocation(FTokenStart);
if TmpStr = '1.1' then // Checking for bad chars is implied I := 0;
IsXML11 := True while (I < 3) and (FSource.FBuf^ <> Delim) do
else if TmpStr <> '1.0' then begin
{ should be no whitespace in these literals, but that isn't checked now } buf[I] := FSource.FBuf^;
Inc(I);
FSource.NextChar;
end;
if (I <> 3) or (buf[0] <> '1') or (buf[1] <> '.') or
((buf[2] <> '0') and (buf[2] <> '1')) then
FatalError('Illegal version number', -1); FatalError('Illegal version number', -1);
ExpectChar(Delim);
IsXML11 := buf[2] = '1';
if not TextDecl then if not TextDecl then
begin begin
if doc.InheritsFrom(TXMLDocument) then if doc.InheritsFrom(TXMLDocument) then
TXMLDocument(doc).XMLVersion := TmpStr; TXMLDocument(doc).XMLVersion := verStr[IsXML11]; // buf[0..2] works with FPC only
end end
else // parsing external entity else // parsing external entity
if IsXML11 and not FXML11 then if IsXML11 and not FXML11 then
@ -2055,13 +2073,22 @@ begin
begin begin
ExpectString('encoding'); ExpectString('encoding');
ExpectEq; ExpectEq;
SkipQuotedLiteral(TmpStr); SkipQuote(Delim);
I := 0;
if not IsValidXmlEncoding(TmpStr) then while (I < 30) and (FSource.FBuf^ <> Delim) and (FSource.FBuf^ < #127) and
FatalError('Illegal encoding name', -1); ((Char(ord(FSource.FBuf^)) in ['A'..'Z', 'a'..'z']) or
((I > 0) and (Char(ord(FSource.FBuf^)) in ['0'..'9', '.', '-', '_']))) do
begin
buf[I] := FSource.FBuf^;
Inc(I);
FSource.NextChar;
end;
if not CheckForChar(Delim) then
FatalError('Illegal encoding name', i);
SetString(TmpStr, buf, i);
if not FSource.SetEncoding(TmpStr) then // <-- Wide2Ansi conversion here if not FSource.SetEncoding(TmpStr) then // <-- Wide2Ansi conversion here
FatalError('Encoding ''%s'' is not supported', [TmpStr], -1); FatalError('Encoding ''%s'' is not supported', [TmpStr], i+1);
// getting here means that specified encoding is supported // getting here means that specified encoding is supported
// TODO: maybe assign the 'preferred' encoding name? // TODO: maybe assign the 'preferred' encoding name?
if not TextDecl and doc.InheritsFrom(TXMLDocument) then if not TextDecl and doc.InheritsFrom(TXMLDocument) then
@ -2076,11 +2103,13 @@ begin
begin begin
ExpectString('standalone'); ExpectString('standalone');
ExpectEq; ExpectEq;
SkipQuotedLiteral(TmpStr); SkipQuote(Delim);
if TmpStr = 'yes' then StoreLocation(FTokenStart);
if FSource.Matches('yes') then
FStandalone := True FStandalone := True
else if TmpStr <> 'no' then else if not FSource.Matches('no') then
FatalError('Only "yes" or "no" are permitted as values of "standalone"', -1); FatalError('Only "yes" or "no" are permitted as values of "standalone"', -1);
ExpectChar(Delim);
SkipS; SkipS;
end; end;