From deaeeee5d4f0704e5bd29dfc79d7535eac46d893 Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Aug 06 2009 13:59:54 +0000 Subject: CVE-2009-1885 --- diff --git a/import.log b/import.log index 284360a..e439ec1 100644 --- a/import.log +++ b/import.log @@ -1 +1,2 @@ xerces-c-2_8_0-2_fc9:HEAD:xerces-c-2.8.0-2.fc9.src.rpm:1214829476 +xerces-c-2_8_0-5_fc11:F-10:xerces-c-2.8.0-5.fc11.src.rpm:1249567159 diff --git a/xerces-c--CVE-2009-1885.diff b/xerces-c--CVE-2009-1885.diff new file mode 100644 index 0000000..e2fff00 --- /dev/null +++ b/xerces-c--CVE-2009-1885.diff @@ -0,0 +1,649 @@ +--- src/xercesc/validators/DTD/DTDScanner.cpp 2007-08-28 22:43:25.000000000 +0400 ++++ src/xercesc/validators/DTD/DTDScanner.cpp 2009-08-06 17:21:40.086497628 +0400 +@@ -27,7 +27,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -39,7 +41,6 @@ + #include + #include + #include +-#include + + XERCES_CPP_NAMESPACE_BEGIN + +@@ -1046,338 +1047,356 @@ + // Check for a PE ref here, but don't require spaces + checkForPERef(false, true); + +- // We have to check entity nesting here +- unsigned int curReader; +- ++ ValueStackOf* arrNestedDecl=NULL; + // + // We know that the caller just saw an opening parenthesis, so we need +- // to parse until we hit the end of it, recursing for other nested +- // parentheses we see. ++ // to parse until we hit the end of it; if we find several parenthesis, ++ // store them in an array to be processed later. + // + // We have to check for one up front, since it could be something like + // (((a)*)) etc... + // + ContentSpecNode* curNode = 0; +- if (fReaderMgr->skippedChar(chOpenParen)) ++ while(fReaderMgr->skippedChar(chOpenParen)) + { +- curReader = fReaderMgr->getCurrentReaderNum(); +- +- // Lets call ourself and get back the resulting node +- curNode = scanChildren(elemDecl, bufToUse); ++ // to check entity nesting ++ const XMLSize_t curReader = fReaderMgr->getCurrentReaderNum(); ++ if(arrNestedDecl==NULL) ++ arrNestedDecl=new (fMemoryManager) ValueStackOf(5, fMemoryManager); ++ arrNestedDecl->push(curReader); + +- // If that failed, no need to go further, return failure +- if (!curNode) +- return 0; +- +- if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation()) +- fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE); ++ // Check for a PE ref here, but don't require spaces ++ checkForPERef(false, true); + } +- else ++ // We must find a leaf node here, either standalone or nested in the parenthesis ++ if (!fReaderMgr->getName(bufToUse)) + { +- // Not a nested paren, so it must be a leaf node +- if (!fReaderMgr->getName(bufToUse)) +- { +- fScanner->emitError(XMLErrs::ExpectedElementName); +- return 0; +- } ++ fScanner->emitError(XMLErrs::ExpectedElementName); ++ return 0; ++ } + +- // +- // Create a leaf node for it. If we can find the element id for +- // this element, then use it. Else, we have to fault in an element +- // decl, marked as created because of being in a content model. +- // +- XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE); +- if (!decl) +- { +- decl = new (fGrammarPoolMemoryManager) DTDElementDecl +- ( +- bufToUse.getRawBuffer() +- , fEmptyNamespaceId +- , DTDElementDecl::Any +- , fGrammarPoolMemoryManager +- ); +- decl->setCreateReason(XMLElementDecl::InContentModel); +- decl->setExternalElemDeclaration(isReadingExternalEntity()); +- fDTDGrammar->putElemDecl(decl); +- } +- curNode = new (fGrammarPoolMemoryManager) ContentSpecNode ++ // ++ // Create a leaf node for it. If we can find the element id for ++ // this element, then use it. Else, we have to fault in an element ++ // decl, marked as created because of being in a content model. ++ // ++ XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE); ++ if (!decl) ++ { ++ decl = new (fGrammarPoolMemoryManager) DTDElementDecl + ( +- decl->getElementName() ++ bufToUse.getRawBuffer() ++ , fEmptyNamespaceId ++ , DTDElementDecl::Any + , fGrammarPoolMemoryManager + ); ++ decl->setCreateReason(XMLElementDecl::InContentModel); ++ decl->setExternalElemDeclaration(isReadingExternalEntity()); ++ fDTDGrammar->putElemDecl(decl); ++ } ++ curNode = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ decl->getElementName() ++ , fGrammarPoolMemoryManager ++ ); + +- // Check for a PE ref here, but don't require spaces +- const bool gotSpaces = checkForPERef(false, true); ++ // Check for a PE ref here, but don't require spaces ++ const bool gotSpaces = checkForPERef(false, true); + +- // Check for a repetition character after the leaf +- const XMLCh repCh = fReaderMgr->peekNextChar(); +- ContentSpecNode* tmpNode = makeRepNode(repCh, curNode, fGrammarPoolMemoryManager); +- if (tmpNode != curNode) ++ // Check for a repetition character after the leaf ++ XMLCh repCh = fReaderMgr->peekNextChar(); ++ ContentSpecNode* tmpNode = makeRepNode(repCh, curNode, fGrammarPoolMemoryManager); ++ if (tmpNode != curNode) ++ { ++ if (gotSpaces) + { +- if (gotSpaces) ++ if (fScanner->emitErrorWillThrowException(XMLErrs::UnexpectedWhitespace)) + { +- if (fScanner->emitErrorWillThrowException(XMLErrs::UnexpectedWhitespace)) +- { +- delete tmpNode; +- } +- fScanner->emitError(XMLErrs::UnexpectedWhitespace); ++ delete tmpNode; + } +- fReaderMgr->getNextChar(); +- curNode = tmpNode; ++ fScanner->emitError(XMLErrs::UnexpectedWhitespace); + } ++ fReaderMgr->getNextChar(); ++ curNode = tmpNode; + } + +- // Check for a PE ref here, but don't require spaces +- checkForPERef(false, true); ++ while(arrNestedDecl==NULL || !arrNestedDecl->empty()) ++ { ++ // Check for a PE ref here, but don't require spaces ++ checkForPERef(false, true); + +- // +- // Ok, the next character tells us what kind of content this particular +- // model this particular parentesized section is. Its either a choice if +- // we see ',', a sequence if we see '|', or a single leaf node if we see +- // a closing paren. +- // +- const XMLCh opCh = fReaderMgr->peekNextChar(); +- +- if ((opCh != chComma) +- && (opCh != chPipe) +- && (opCh != chCloseParen)) +- { +- // Not a legal char, so delete our node and return failure +- delete curNode; +- fScanner->emitError(XMLErrs::ExpectedSeqChoiceLeaf); +- return 0; +- } ++ // ++ // Ok, the next character tells us what kind of content this particular ++ // model this particular parentesized section is. Its either a choice if ++ // we see ',', a sequence if we see '|', or a single leaf node if we see ++ // a closing paren. ++ // ++ const XMLCh opCh = fReaderMgr->peekNextChar(); ++ ++ if ((opCh != chComma) ++ && (opCh != chPipe) ++ && (opCh != chCloseParen)) ++ { ++ // Not a legal char, so delete our node and return failure ++ delete curNode; ++ fScanner->emitError(XMLErrs::ExpectedSeqChoiceLeaf); ++ return 0; ++ } + +- // +- // Create the head node of the correct type. We need this to remember +- // the top of the local tree. If it was a single subexpr, then just +- // set the head node to the current node. For the others, we'll build +- // the tree off the second child as we move across. +- // +- ContentSpecNode* headNode = 0; +- ContentSpecNode::NodeTypes curType = ContentSpecNode::UnknownType; +- if (opCh == chComma) +- { +- curType = ContentSpecNode::Sequence; +- headNode = new (fGrammarPoolMemoryManager) ContentSpecNode +- ( +- curType +- , curNode +- , 0 +- , true +- , true +- , fGrammarPoolMemoryManager +- ); +- curNode = headNode; +- } +- else if (opCh == chPipe) +- { +- curType = ContentSpecNode::Choice; +- headNode = new (fGrammarPoolMemoryManager) ContentSpecNode +- ( +- curType +- , curNode +- , 0 +- , true +- , true +- , fGrammarPoolMemoryManager +- ); +- curNode = headNode; +- } +- else +- { +- headNode = curNode; +- fReaderMgr->getNextChar(); +- } ++ // ++ // Create the head node of the correct type. We need this to remember ++ // the top of the local tree. If it was a single subexpr, then just ++ // set the head node to the current node. For the others, we'll build ++ // the tree off the second child as we move across. ++ // ++ ContentSpecNode* headNode = 0; ++ ContentSpecNode::NodeTypes curType = ContentSpecNode::UnknownType; ++ if (opCh == chComma) ++ { ++ curType = ContentSpecNode::Sequence; ++ headNode = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ curType ++ , curNode ++ , 0 ++ , true ++ , true ++ , fGrammarPoolMemoryManager ++ ); ++ curNode = headNode; ++ } ++ else if (opCh == chPipe) ++ { ++ curType = ContentSpecNode::Choice; ++ headNode = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ curType ++ , curNode ++ , 0 ++ , true ++ , true ++ , fGrammarPoolMemoryManager ++ ); ++ curNode = headNode; ++ } ++ else ++ { ++ headNode = curNode; ++ fReaderMgr->getNextChar(); ++ } + +- // +- // If it was a sequence or choice, we just loop until we get to the +- // end of our section, adding each new leaf or sub expression to the +- // right child of the current node, and making that new node the current +- // node. +- // +- if ((opCh == chComma) || (opCh == chPipe)) +- { +- ContentSpecNode* lastNode = 0; +- while (true) ++ // ++ // If it was a sequence or choice, we just loop until we get to the ++ // end of our section, adding each new leaf or sub expression to the ++ // right child of the current node, and making that new node the current ++ // node. ++ // ++ if ((opCh == chComma) || (opCh == chPipe)) + { +- // +- // The next thing must either be another | or , character followed +- // by another leaf or subexpression, or a closing parenthesis, or a +- // PE ref. +- // +- if (fReaderMgr->lookingAtChar(chPercent)) +- { +- checkForPERef(false, true); +- } +- else if (fReaderMgr->skippedSpace()) +- { +- // Just skip whitespace +- fReaderMgr->skipPastSpaces(); +- } +- else if (fReaderMgr->skippedChar(chCloseParen)) ++ ContentSpecNode* lastNode = 0; ++ while (true) + { + // +- // We've hit the end of this section, so break out. But, we +- // need to see if we left a partial sequence of choice node +- // without a second node. If so, we have to undo that and +- // put its left child into the right node of the previous +- // node. ++ // The next thing must either be another | or , character followed ++ // by another leaf or subexpression, or a closing parenthesis, or a ++ // PE ref. + // +- if ((curNode->getType() == ContentSpecNode::Choice) +- || (curNode->getType() == ContentSpecNode::Sequence)) ++ if (fReaderMgr->lookingAtChar(chPercent)) + { +- if (!curNode->getSecond()) ++ checkForPERef(false, true); ++ } ++ else if (fReaderMgr->skippedSpace()) ++ { ++ // Just skip whitespace ++ fReaderMgr->skipPastSpaces(); ++ } ++ else if (fReaderMgr->skippedChar(chCloseParen)) ++ { ++ // ++ // We've hit the end of this section, so break out. But, we ++ // need to see if we left a partial sequence of choice node ++ // without a second node. If so, we have to undo that and ++ // put its left child into the right node of the previous ++ // node. ++ // ++ if ((curNode->getType() == ContentSpecNode::Choice) ++ || (curNode->getType() == ContentSpecNode::Sequence)) + { +- ContentSpecNode* saveFirst = curNode->orphanFirst(); +- lastNode->setSecond(saveFirst); +- curNode = lastNode; ++ if (!curNode->getSecond()) ++ { ++ ContentSpecNode* saveFirst = curNode->orphanFirst(); ++ lastNode->setSecond(saveFirst); ++ curNode = lastNode; ++ } + } ++ break; + } +- break; +- } +- else if (fReaderMgr->skippedChar(opCh)) +- { +- // Check for a PE ref here, but don't require spaces +- checkForPERef(false, true); +- +- if (fReaderMgr->skippedChar(chOpenParen)) ++ else if (fReaderMgr->skippedChar(opCh)) + { +- curReader = fReaderMgr->getCurrentReaderNum(); ++ // Check for a PE ref here, but don't require spaces ++ checkForPERef(false, true); + +- // Recurse to handle this new guy +- ContentSpecNode* subNode; +- try { +- subNode = scanChildren(elemDecl, bufToUse); +- } +- catch (const XMLErrs::Codes) ++ if (fReaderMgr->skippedChar(chOpenParen)) + { +- delete headNode; +- throw; +- } ++ const XMLSize_t curReader = fReaderMgr->getCurrentReaderNum(); + +- // If it failed, we are done, clean up here and return failure +- if (!subNode) +- { +- delete headNode; +- return 0; ++ // Recurse to handle this new guy ++ ContentSpecNode* subNode; ++ try { ++ subNode = scanChildren(elemDecl, bufToUse); ++ } ++ catch (const XMLErrs::Codes) ++ { ++ delete headNode; ++ throw; ++ } ++ ++ // If it failed, we are done, clean up here and return failure ++ if (!subNode) ++ { ++ delete headNode; ++ return 0; ++ } ++ ++ if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getValidationScheme() == XMLScanner::Val_Always) ++ fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE); ++ ++ // Else patch it in and make it the new current ++ ContentSpecNode* newCur = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ curType ++ , subNode ++ , 0 ++ , true ++ , true ++ , fGrammarPoolMemoryManager ++ ); ++ curNode->setSecond(newCur); ++ lastNode = curNode; ++ curNode = newCur; + } ++ else ++ { ++ // ++ // Got to be a leaf node, so get a name. If we cannot get ++ // one, then clean up and get outa here. ++ // ++ if (!fReaderMgr->getName(bufToUse)) ++ { ++ delete headNode; ++ fScanner->emitError(XMLErrs::ExpectedElementName); ++ return 0; ++ } + +- if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation()) +- fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE); ++ // ++ // Create a leaf node for it. If we can find the element ++ // id for this element, then use it. Else, we have to ++ // fault in an element decl, marked as created because ++ // of being in a content model. ++ // ++ XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE); ++ if (!decl) ++ { ++ decl = new (fGrammarPoolMemoryManager) DTDElementDecl ++ ( ++ bufToUse.getRawBuffer() ++ , fEmptyNamespaceId ++ , DTDElementDecl::Any ++ , fGrammarPoolMemoryManager ++ ); ++ decl->setCreateReason(XMLElementDecl::InContentModel); ++ decl->setExternalElemDeclaration(isReadingExternalEntity()); ++ fDTDGrammar->putElemDecl(decl); ++ } + +- // Else patch it in and make it the new current +- ContentSpecNode* newCur = new (fGrammarPoolMemoryManager) ContentSpecNode +- ( +- curType +- , subNode +- , 0 +- , true +- , true +- , fGrammarPoolMemoryManager +- ); +- curNode->setSecond(newCur); +- lastNode = curNode; +- curNode = newCur; ++ ContentSpecNode* tmpLeaf = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ decl->getElementName() ++ , fGrammarPoolMemoryManager ++ ); ++ ++ // Check for a repetition character after the leaf ++ const XMLCh repCh = fReaderMgr->peekNextChar(); ++ ContentSpecNode* tmpLeaf2 = makeRepNode(repCh, tmpLeaf, fGrammarPoolMemoryManager); ++ if (tmpLeaf != tmpLeaf2) ++ fReaderMgr->getNextChar(); ++ ++ // ++ // Create a new sequence or choice node, with the leaf ++ // (or rep surrounding it) we just got as its first node. ++ // Make the new node the second node of the current node, ++ // and then make it the current node. ++ // ++ ContentSpecNode* newCur = new (fGrammarPoolMemoryManager) ContentSpecNode ++ ( ++ curType ++ , tmpLeaf2 ++ , 0 ++ , true ++ , true ++ , fGrammarPoolMemoryManager ++ ); ++ curNode->setSecond(newCur); ++ lastNode = curNode; ++ curNode = newCur; ++ } + } + else + { +- // +- // Got to be a leaf node, so get a name. If we cannot get +- // one, then clean up and get outa here. +- // +- if (!fReaderMgr->getName(bufToUse)) ++ // Cannot be valid ++ delete headNode; // emitError may do a throw so need to clean-up first ++ if (opCh == chComma) + { +- delete headNode; +- fScanner->emitError(XMLErrs::ExpectedElementName); +- return 0; ++ fScanner->emitError(XMLErrs::ExpectedChoiceOrCloseParen); + } +- +- // +- // Create a leaf node for it. If we can find the element +- // id for this element, then use it. Else, we have to +- // fault in an element decl, marked as created because +- // of being in a content model. +- // +- XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE); +- if (!decl) ++ else + { +- decl = new (fGrammarPoolMemoryManager) DTDElementDecl ++ fScanner->emitError + ( +- bufToUse.getRawBuffer() +- , fEmptyNamespaceId +- , DTDElementDecl::Any +- , fGrammarPoolMemoryManager ++ XMLErrs::ExpectedSeqOrCloseParen ++ , elemDecl.getFullName() + ); + decl->setCreateReason(XMLElementDecl::InContentModel); + decl->setExternalElemDeclaration(isReadingExternalEntity()); + fDTDGrammar->putElemDecl(decl); +- } ++ } ++ return 0; ++ } ++ } ++ } + +- ContentSpecNode* tmpLeaf = new (fGrammarPoolMemoryManager) ContentSpecNode +- ( +- decl->getElementName() +- , fGrammarPoolMemoryManager +- ); ++ // ++ // We saw the terminating parenthesis so lets check for any repetition ++ // character, and create a node for that, making the head node the child ++ // of it. ++ // ++ const XMLCh repCh = fReaderMgr->peekNextChar(); ++ curNode = makeRepNode(repCh, headNode, fGrammarPoolMemoryManager); ++ if (curNode != headNode) ++ fReaderMgr->getNextChar(); + +- // Check for a repetition character after the leaf +- const XMLCh repCh = fReaderMgr->peekNextChar(); +- ContentSpecNode* tmpLeaf2 = makeRepNode(repCh, tmpLeaf, fGrammarPoolMemoryManager); +- if (tmpLeaf != tmpLeaf2) +- fReaderMgr->getNextChar(); ++ // prepare for recursion ++ if(arrNestedDecl==NULL) ++ break; ++ else ++ { ++ // If that failed, no need to go further, return failure ++ if (!curNode) ++ return 0; + +- // +- // Create a new sequence or choice node, with the leaf +- // (or rep surrounding it) we just got as its first node. +- // Make the new node the second node of the current node, +- // and then make it the current node. +- // +- ContentSpecNode* newCur = new (fGrammarPoolMemoryManager) ContentSpecNode +- ( +- curType +- , tmpLeaf2 +- , 0 +- , true +- , true +- , fGrammarPoolMemoryManager +- ); +- curNode->setSecond(newCur); +- lastNode = curNode; +- curNode = newCur; +- } +- } +- else ++ const XMLSize_t curReader = arrNestedDecl->pop(); ++ if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getValidationScheme() == XMLScanner::Val_Always) ++ fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE); ++ ++ if(arrNestedDecl->empty()) + { +- // Cannot be valid +- delete headNode; // emitError may do a throw so need to clean-up first +- if (opCh == chComma) +- { +- fScanner->emitError(XMLErrs::ExpectedChoiceOrCloseParen); +- } +- else +- { +- fScanner->emitError +- ( +- XMLErrs::ExpectedSeqOrCloseParen +- , elemDecl.getFullName() +- ); +- } +- return 0; ++ delete arrNestedDecl; ++ arrNestedDecl=NULL; + } + } + } + +- // +- // We saw the terminating parenthesis so lets check for any repetition +- // character, and create a node for that, making the head node the child +- // of it. +- // +- XMLCh repCh = fReaderMgr->peekNextChar(); +- ContentSpecNode* retNode = makeRepNode(repCh, headNode, fGrammarPoolMemoryManager); +- if (retNode != headNode) +- fReaderMgr->getNextChar(); +- +- return retNode; ++ return curNode; + } + + diff --git a/xerces-c.spec b/xerces-c.spec index bbc6879..5e36497 100644 --- a/xerces-c.spec +++ b/xerces-c.spec @@ -1,11 +1,12 @@ Summary: Validating XML Parser Name: xerces-c Version: 2.8.0 -Release: 2%{?dist} +Release: 5%{?dist} License: ASL 2.0 Group: System Environment/Libraries URL: http://xml.apache.org/xerces-c/ -Source: http://www.apache.org/dist/xerces/c/sources/xerces-c-src_2_8_0.tar.gz +Source0: http://www.apache.org/dist/xerces/c/sources/xerces-c-src_2_8_0.tar.gz +PAtch0: xerces-c--CVE-2009-1885.diff BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %description @@ -55,6 +56,7 @@ find ./samples -type f -perm 755 -exec chmod 644 {} \; %{__perl} -pi.orig -e 's|(PREFIX.)/lib\b|$1/%{_lib}|g' src/xercesc/configure */Makefile.in rm doc/html/apiDocs/XMLRegisterCleanup_8hpp__incl.map rm doc/html/apiDocs/XSConstants_8hpp__incl.map +%patch0 -p0 -b .CVE-2009-1885 # make rpmlint happy sed -i 's/\r//' doc/charter.xml @@ -124,6 +126,15 @@ export XERCESCROOT="$PWD" #%{_datadir}/%{name}/samples %changelog +* Thu Aug 6 2009 Peter Lemenkov 2.8.0-5 +- Fix CVE-2009-1885 + +* Mon Jul 27 2009 Fedora Release Engineering - 2.8.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Feb 26 2009 Fedora Release Engineering - 2.8.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + * Mon Jun 30 2008 Peter Lemenkov 2.8.0-2 - Spec cleanups ( https://bugzilla.redhat.com/show_bug.cgi?id=435132 )