[PATCH] Prevent khtml from crashing when parsing a badly formed css file

Matthew Cope mccope at googlemail.com
Sun Mar 29 17:02:42 BST 2009


Hi list,

Below is a proposed patch to fix bug 167318 (+ 5 duplicates).

The patch is based on CSSParser.cpp from the qt-copy version of Webkit.

Please can someone familiar with khtml check it and give comments, or if it is 
appropriate apply it.

Thanks

Matt.

p.s. please CC me as I'm not subscribed to the list.

Ref: https://bugs.kde.org/show_bug.cgi?id=167318

Patch follows below (also attached as a file in case it gets mangled):


diff -upr kdelibs/khtml/css/cssparser.cpp kdelibs-
bug167318/khtml/css/cssparser.cpp
--- kdelibs/khtml/css/cssparser.cpp	2009-03-14 11:27:16.000000000 +0000
+++ kdelibs-bug167318/khtml/css/cssparser.cpp	2009-03-15 13:31:48.000000000 
+0000
@@ -144,15 +144,25 @@ unsigned int CSSParser::defaultNamespace
         return anyNamespace;
 }
 
-void CSSParser::runParser(int length)
+void CSSParser::setupParser(const char *prefix, const DOMString &string, const 
char *suffix)
 {
-    // the flex scanner sometimes give invalid reads for any
-    // smaller padding - try e.g. css/invalid-rules-005.html
-    data[length-1] = 0;
-    data[length-2] = 0;
-    data[length-3] = 0;
-    data[length-4] = 0;
-    data[length-5] = ' ';
+    int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
+
+    free(data);
+
+    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
+    for (unsigned i = 0; i < strlen(prefix); i++)
+        data[i] = prefix[i];
+
+    memcpy(data + strlen(prefix), string.unicode(), string.length()*sizeof( 
unsigned short));
+
+    unsigned start = strlen(prefix) + string.length();
+    unsigned end = start + strlen(suffix);
+    for (unsigned i = start; i < end; i++)
+        data[i] = suffix[i - start];
+
+    data[length - 1] = 0;
+    data[length - 2] = 0;
 
     yyTok = -1;
     block_nesting = 0;
@@ -160,28 +170,22 @@ void CSSParser::runParser(int length)
     yyleng = 0;
     yytext = yy_c_buf_p = data;
     yy_hold_char = *yy_c_buf_p;
-
-    CSSParser *old = currentParser;
-    currentParser = this;
-    cssyyparse( this );
-    currentParser = old;
-    boundLocalNames.clear();
 }
 
 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string 
)
 {
     styleElement = sheet;
 
-    int length = string.length() + 5;
-    if (data) 
-        free( data );
-    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
-    memcpy( data, string.unicode(), string.length()*sizeof( unsigned short) 
);
+    setupParser("", string, "");
 
 #ifdef CSS_DEBUG
     kDebug( 6080 ) << ">>>>>>> start parsing style sheet";
 #endif
-    runParser(length);
+    CSSParser* old = currentParser;
+    currentParser = this;
+    cssyyparse( this );
+    currentParser = old;
+    boundLocalNames.clear();
 #ifdef CSS_DEBUG
     kDebug( 6080 ) << "<<<<<<< done parsing style sheet";
 #endif
@@ -193,18 +197,14 @@ void CSSParser::parseSheet( CSSStyleShee
 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const 
DOM::DOMString &string )
 {
     styleElement = sheet;
+    
+    setupParser("@-khtml-rule{", string, "} ");
 
-    const char khtml_rule[] = "@-khtml-rule{";
-    int length = string.length() + 6 + strlen(khtml_rule);
-    assert( !data );
-    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
-    for ( unsigned int i = 0; i < strlen(khtml_rule); i++ )
-        data[i] = khtml_rule[i];
-    memcpy( data + strlen( khtml_rule ), string.unicode(), 
string.length()*sizeof( unsigned short) );
-    // qDebug("parse string = '%s'", QString::fromRawData( (const QChar 
*)data, length ).toLatin1().constData() );
-    data[length-6] = '}';
-
-    runParser(length);
+    CSSParser* old = currentParser;
+    currentParser = this;
+    cssyyparse(this);
+    currentParser = old;
+    boundLocalNames.clear();
 
     CSSRuleImpl *result = rule;
     rule = 0;
@@ -234,21 +234,17 @@ bool CSSParser::parseValue( DOM::CSSStyl
 
     styleElement = declaration->stylesheet();
 
-    const char khtml_value[] = "@-khtml-value{";
-    int length = string.length() + 6 + strlen(khtml_value);
-    assert( !data );
-    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
-    for ( unsigned int i = 0; i < strlen(khtml_value); i++ )
-        data[i] = khtml_value[i];
-    memcpy( data + strlen( khtml_value ), string.unicode(), 
string.length()*sizeof( unsigned short) );
-    // qDebug("parse string = '%s'", QString::fromRawData( (const QChar 
*)data, length ).toLatin1().constData() );
-    data[length-6] = '}';
+    setupParser("@-khtml-value{", string, "} ");
 
     id = _id;
     important = _important;
-
-    runParser(length);
-
+    
+    CSSParser* old = currentParser;
+    currentParser = this;
+    cssyyparse(this);
+    currentParser = old;
+    boundLocalNames.clear();
+    
     delete rule;
     rule = 0;
 
@@ -271,16 +267,13 @@ bool CSSParser::parseDeclaration( DOM::C
 
     styleElement = declaration->stylesheet();
 
-    const char khtml_decls[] = "@-khtml-decls{";
-    int length = string.length() + 6 + strlen(khtml_decls);
-    assert( !data );
-    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
-    for ( unsigned int i = 0; i < strlen(khtml_decls); i++ )
-        data[i] = khtml_decls[i];
-    memcpy( data + strlen( khtml_decls ), string.unicode(), 
string.length()*sizeof( unsigned short) );
-    data[length-6] = '}';
+    setupParser("@-khtml-decls{", string, "} ");
 
-    runParser(length);
+    CSSParser* old = currentParser;
+    currentParser = this;
+    cssyyparse(this);
+    currentParser = old;
+    boundLocalNames.clear();
 
     delete rule;
     rule = 0;
@@ -304,17 +297,13 @@ bool CSSParser::parseMediaQuery(DOM::Med
     mediaQuery = 0;
     // can't use { because tokenizer state switches from mediaquery to 
initial state when it sees { token.
     // instead insert one " " (which is S in parser.y)
-    const char khtml_queries[] = "@-khtml-mediaquery ";
-    int length = string.length() + 6 + strlen(khtml_queries);
-    if (data)
-        free( data );
-    data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
-    for ( unsigned int i = 0; i < strlen(khtml_queries); i++ )
-        data[i] = khtml_queries[i];
-    memcpy( data + strlen( khtml_queries ), string.unicode(), 
string.length()*sizeof( unsigned short) );
-    data[length-6] = '}';
+    setupParser ("@-khtml-mediaquery ", string, "} ");
 
-    runParser(length);
+    CSSParser* old = currentParser;
+    currentParser = this;
+    cssyyparse(this);
+    currentParser = old;
+    boundLocalNames.clear();
 
     bool ok = false;
     if (mediaQuery) {
diff -upr kdelibs/khtml/css/cssparser.h kdelibs-bug167318/khtml/css/cssparser.h
--- kdelibs/khtml/css/cssparser.h	2009-03-15 13:24:42.000000000 +0000
+++ kdelibs-bug167318/khtml/css/cssparser.h	2009-03-15 13:31:48.000000000 
+0000
@@ -226,7 +226,7 @@ namespace DOM {
 	int lex();
     private:
 	int yyparse();
-        void runParser(int length);
+        void setupParser(const char *prefix, const DOMString &string, const 
char *suffix);
 
         bool inShorthand() const { return m_inParseShorthand; }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: bug167318.patch
Type: text/x-patch
Size: 6656 bytes
Desc: not available
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20090329/a9b83c06/attachment.bin>


More information about the kde-core-devel mailing list