2024-04-16 14:24:12 +03:00
/*
* xml . c : a libFuzzer target to test several XML parser interfaces .
*
* See Copyright for the status of this software .
*/
# include <libxml/catalog.h>
# include <libxml/parser.h>
# include <libxml/tree.h>
# include <libxml/xmlerror.h>
# include <libxml/xmlreader.h>
# include <libxml/xmlsave.h>
# include "fuzz.h"
# include <string.h>
#if 0
# define DEBUG printf
# else
# define DEBUG noop
# endif
typedef enum {
OP_READ = 1 ,
OP_READ_INNER_XML ,
OP_READ_OUTER_XML ,
OP_READ_STRING ,
OP_READ_ATTRIBUTE_VALUE ,
OP_ATTRIBUTE_COUNT ,
OP_DEPTH ,
OP_HAS_ATTRIBUTES ,
OP_HAS_VALUE ,
OP_IS_DEFAULT ,
OP_IS_EMPTY_ELEMENT ,
OP_NODE_TYPE ,
OP_QUOTE_CHAR ,
OP_READ_STATE ,
OP_IS_NAMESPACE_DECL ,
OP_CONST_BASE_URI ,
OP_CONST_LOCAL_NAME ,
OP_CONST_NAME ,
OP_CONST_NAMESPACE_URI ,
OP_CONST_PREFIX ,
OP_CONST_XML_LANG ,
OP_CONST_VALUE ,
OP_BASE_URI ,
OP_LOCAL_NAME ,
OP_NAME ,
OP_NAMESPACE_URI ,
OP_PREFIX ,
OP_XML_LANG ,
OP_VALUE ,
OP_CLOSE ,
OP_GET_ATTRIBUTE_NO ,
OP_GET_ATTRIBUTE ,
OP_GET_ATTRIBUTE_NS ,
OP_GET_REMAINDER ,
OP_LOOKUP_NAMESPACE ,
OP_MOVE_TO_ATTRIBUTE_NO ,
OP_MOVE_TO_ATTRIBUTE ,
OP_MOVE_TO_ATTRIBUTE_NS ,
OP_MOVE_TO_FIRST_ATTRIBUTE ,
OP_MOVE_TO_NEXT_ATTRIBUTE ,
OP_MOVE_TO_ELEMENT ,
OP_NORMALIZATION ,
OP_CONST_ENCODING ,
OP_GET_PARSER_PROP ,
OP_CURRENT_NODE ,
OP_GET_PARSER_LINE_NUMBER ,
OP_GET_PARSER_COLUMN_NUMBER ,
OP_PRESERVE ,
OP_CURRENT_DOC ,
OP_EXPAND ,
OP_NEXT ,
OP_NEXT_SIBLING ,
OP_IS_VALID ,
OP_CONST_XML_VERSION ,
OP_STANDALONE ,
OP_BYTE_CONSUMED ,
OP_MAX
} opType ;
static void
noop ( const char * fmt , . . . ) {
( void ) fmt ;
}
static void
startOp ( const char * name ) {
( void ) name ;
DEBUG ( " %s \n " , name ) ;
}
int
LLVMFuzzerInitialize ( int * argc ATTRIBUTE_UNUSED ,
char * * * argv ATTRIBUTE_UNUSED ) {
xmlFuzzMemSetup ( ) ;
xmlInitParser ( ) ;
# ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog ( ) ;
xmlCatalogSetDefaults ( XML_CATA_ALLOW_NONE ) ;
# endif
return 0 ;
}
int
LLVMFuzzerTestOneInput ( const char * data , size_t size ) {
xmlTextReaderPtr reader ;
xmlDocPtr doc = NULL ;
const xmlError * error ;
const char * docBuffer ;
const unsigned char * program ;
size_t maxAlloc , docSize , programSize , i ;
size_t totalStringSize = 0 ;
int opts ;
int oomReport = 0 ;
xmlFuzzDataInit ( data , size ) ;
opts = ( int ) xmlFuzzReadInt ( 4 ) ;
maxAlloc = xmlFuzzReadInt ( 4 ) % ( size + 100 ) ;
program = ( const unsigned char * ) xmlFuzzReadString ( & programSize ) ;
if ( programSize > 1000 )
programSize = 1000 ;
xmlFuzzReadEntities ( ) ;
docBuffer = xmlFuzzMainEntity ( & docSize ) ;
if ( docBuffer = = NULL )
goto exit ;
xmlFuzzMemSetLimit ( maxAlloc ) ;
reader = xmlReaderForMemory ( docBuffer , docSize , NULL , NULL , opts ) ;
if ( reader = = NULL )
goto exit ;
2024-06-11 17:58:09 +03:00
xmlTextReaderSetStructuredErrorHandler ( reader , xmlFuzzSErrorFunc , NULL ) ;
2024-06-11 16:48:32 +03:00
xmlTextReaderSetResourceLoader ( reader , xmlFuzzResourceLoader , NULL ) ;
2024-04-16 14:24:12 +03:00
i = 0 ;
while ( i < programSize ) {
int op = program [ i + + ] ;
# define READ_BYTE() (i < programSize ? program[i++] : 0)
# define FREE_STRING(str) \
do { \
if ( str ! = NULL ) { \
totalStringSize + = strlen ( ( char * ) str ) ; \
xmlFree ( str ) ; \
} \
} while ( 0 )
switch ( op & 0x3F ) {
case OP_READ :
default :
startOp ( " Read " ) ;
xmlTextReaderRead ( reader ) ;
break ;
case OP_READ_INNER_XML : {
xmlChar * result ;
startOp ( " ReadInnerXml " ) ;
result = xmlTextReaderReadInnerXml ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_READ_OUTER_XML : {
xmlChar * result ;
startOp ( " ReadOuterXml " ) ;
result = xmlTextReaderReadOuterXml ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_READ_STRING : {
xmlChar * result ;
startOp ( " ReadString " ) ;
result = xmlTextReaderReadString ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_READ_ATTRIBUTE_VALUE :
startOp ( " ReadAttributeValue " ) ;
xmlTextReaderReadAttributeValue ( reader ) ;
break ;
case OP_ATTRIBUTE_COUNT :
startOp ( " AttributeCount " ) ;
xmlTextReaderAttributeCount ( reader ) ;
break ;
case OP_DEPTH :
startOp ( " Depth " ) ;
xmlTextReaderDepth ( reader ) ;
break ;
case OP_HAS_ATTRIBUTES :
startOp ( " HasAttributes " ) ;
xmlTextReaderHasAttributes ( reader ) ;
break ;
case OP_HAS_VALUE :
startOp ( " HasValue " ) ;
xmlTextReaderHasValue ( reader ) ;
break ;
case OP_IS_DEFAULT :
startOp ( " IsDefault " ) ;
xmlTextReaderIsDefault ( reader ) ;
break ;
case OP_IS_EMPTY_ELEMENT :
startOp ( " IsEmptyElement " ) ;
xmlTextReaderIsEmptyElement ( reader ) ;
break ;
case OP_NODE_TYPE :
startOp ( " NodeType " ) ;
xmlTextReaderNodeType ( reader ) ;
break ;
case OP_QUOTE_CHAR :
startOp ( " QuoteChar " ) ;
xmlTextReaderQuoteChar ( reader ) ;
break ;
case OP_READ_STATE :
startOp ( " ReadState " ) ;
xmlTextReaderReadState ( reader ) ;
break ;
case OP_IS_NAMESPACE_DECL :
startOp ( " IsNamespaceDecl " ) ;
xmlTextReaderIsNamespaceDecl ( reader ) ;
break ;
case OP_CONST_BASE_URI :
startOp ( " ConstBaseUri " ) ;
xmlTextReaderConstBaseUri ( reader ) ;
break ;
case OP_CONST_LOCAL_NAME :
startOp ( " ConstLocalName " ) ;
xmlTextReaderConstLocalName ( reader ) ;
break ;
case OP_CONST_NAME :
startOp ( " ConstName " ) ;
xmlTextReaderConstName ( reader ) ;
break ;
case OP_CONST_NAMESPACE_URI :
startOp ( " ConstNamespaceUri " ) ;
xmlTextReaderConstNamespaceUri ( reader ) ;
break ;
case OP_CONST_PREFIX :
startOp ( " ConstPrefix " ) ;
xmlTextReaderConstPrefix ( reader ) ;
break ;
case OP_CONST_XML_LANG :
startOp ( " ConstXmlLang " ) ;
xmlTextReaderConstXmlLang ( reader ) ;
oomReport = - 1 ;
break ;
case OP_CONST_VALUE :
startOp ( " ConstValue " ) ;
xmlTextReaderConstValue ( reader ) ;
break ;
case OP_BASE_URI : {
xmlChar * result ;
startOp ( " BaseUri " ) ;
result = xmlTextReaderBaseUri ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_LOCAL_NAME : {
xmlChar * result ;
startOp ( " LocalName " ) ;
result = xmlTextReaderLocalName ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_NAME : {
xmlChar * result ;
startOp ( " Name " ) ;
result = xmlTextReaderName ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_NAMESPACE_URI : {
xmlChar * result ;
startOp ( " NamespaceUri " ) ;
result = xmlTextReaderNamespaceUri ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_PREFIX : {
xmlChar * result ;
startOp ( " Prefix " ) ;
result = xmlTextReaderPrefix ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_XML_LANG : {
xmlChar * result ;
startOp ( " XmlLang " ) ;
result = xmlTextReaderXmlLang ( reader ) ;
oomReport = - 1 ;
FREE_STRING ( result ) ;
break ;
}
case OP_VALUE : {
xmlChar * result ;
startOp ( " Value " ) ;
result = xmlTextReaderValue ( reader ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_CLOSE :
startOp ( " Close " ) ;
if ( doc = = NULL )
doc = xmlTextReaderCurrentDoc ( reader ) ;
xmlTextReaderClose ( reader ) ;
break ;
case OP_GET_ATTRIBUTE_NO : {
xmlChar * result ;
int no = READ_BYTE ( ) ;
startOp ( " GetAttributeNo " ) ;
result = xmlTextReaderGetAttributeNo ( reader , no ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_GET_ATTRIBUTE : {
const xmlChar * name = xmlTextReaderConstName ( reader ) ;
xmlChar * result ;
startOp ( " GetAttribute " ) ;
result = xmlTextReaderGetAttribute ( reader , name ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_GET_ATTRIBUTE_NS : {
const xmlChar * localName , * namespaceUri ;
xmlChar * result ;
startOp ( " GetAttributeNs " ) ;
localName = xmlTextReaderConstLocalName ( reader ) ;
namespaceUri = xmlTextReaderConstNamespaceUri ( reader ) ;
result = xmlTextReaderGetAttributeNs ( reader , localName ,
namespaceUri ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_GET_REMAINDER :
startOp ( " GetRemainder " ) ;
if ( doc = = NULL )
doc = xmlTextReaderCurrentDoc ( reader ) ;
xmlFreeParserInputBuffer ( xmlTextReaderGetRemainder ( reader ) ) ;
break ;
case OP_LOOKUP_NAMESPACE : {
const xmlChar * prefix = xmlTextReaderConstPrefix ( reader ) ;
xmlChar * result ;
startOp ( " LookupNamespace " ) ;
result = xmlTextReaderLookupNamespace ( reader , prefix ) ;
FREE_STRING ( result ) ;
break ;
}
case OP_MOVE_TO_ATTRIBUTE_NO : {
int no = READ_BYTE ( ) ;
startOp ( " MoveToAttributeNo " ) ;
xmlTextReaderMoveToAttributeNo ( reader , no ) ;
break ;
}
case OP_MOVE_TO_ATTRIBUTE : {
const xmlChar * name = xmlTextReaderConstName ( reader ) ;
startOp ( " MoveToAttribute " ) ;
xmlTextReaderMoveToAttribute ( reader , name ) ;
break ;
}
case OP_MOVE_TO_ATTRIBUTE_NS : {
const xmlChar * localName , * namespaceUri ;
startOp ( " MoveToAttributeNs " ) ;
localName = xmlTextReaderConstLocalName ( reader ) ;
namespaceUri = xmlTextReaderConstNamespaceUri ( reader ) ;
xmlTextReaderMoveToAttributeNs ( reader , localName ,
namespaceUri ) ;
break ;
}
case OP_MOVE_TO_FIRST_ATTRIBUTE :
startOp ( " MoveToFirstAttribute " ) ;
xmlTextReaderMoveToFirstAttribute ( reader ) ;
break ;
case OP_MOVE_TO_NEXT_ATTRIBUTE :
startOp ( " MoveToNextAttribute " ) ;
xmlTextReaderMoveToNextAttribute ( reader ) ;
break ;
case OP_MOVE_TO_ELEMENT :
startOp ( " MoveToElement " ) ;
xmlTextReaderMoveToElement ( reader ) ;
break ;
case OP_NORMALIZATION :
startOp ( " Normalization " ) ;
xmlTextReaderNormalization ( reader ) ;
break ;
case OP_CONST_ENCODING :
startOp ( " ConstEncoding " ) ;
xmlTextReaderConstEncoding ( reader ) ;
break ;
case OP_GET_PARSER_PROP : {
int prop = READ_BYTE ( ) ;
startOp ( " GetParserProp " ) ;
xmlTextReaderGetParserProp ( reader , prop ) ;
break ;
}
case OP_CURRENT_NODE :
startOp ( " CurrentNode " ) ;
xmlTextReaderCurrentNode ( reader ) ;
break ;
case OP_GET_PARSER_LINE_NUMBER :
startOp ( " GetParserLineNumber " ) ;
xmlTextReaderGetParserLineNumber ( reader ) ;
break ;
case OP_GET_PARSER_COLUMN_NUMBER :
startOp ( " GetParserColumnNumber " ) ;
xmlTextReaderGetParserColumnNumber ( reader ) ;
break ;
case OP_PRESERVE :
startOp ( " Preserve " ) ;
xmlTextReaderPreserve ( reader ) ;
break ;
case OP_CURRENT_DOC : {
xmlDocPtr result ;
startOp ( " CurrentDoc " ) ;
result = xmlTextReaderCurrentDoc ( reader ) ;
if ( doc = = NULL )
doc = result ;
break ;
}
case OP_EXPAND :
startOp ( " Expand " ) ;
xmlTextReaderExpand ( reader ) ;
break ;
case OP_NEXT :
startOp ( " Next " ) ;
xmlTextReaderNext ( reader ) ;
break ;
case OP_NEXT_SIBLING :
startOp ( " NextSibling " ) ;
xmlTextReaderNextSibling ( reader ) ;
break ;
case OP_IS_VALID :
startOp ( " IsValid " ) ;
xmlTextReaderIsValid ( reader ) ;
break ;
case OP_CONST_XML_VERSION :
startOp ( " ConstXmlVersion " ) ;
xmlTextReaderConstXmlVersion ( reader ) ;
break ;
case OP_STANDALONE :
startOp ( " Standalone " ) ;
xmlTextReaderStandalone ( reader ) ;
break ;
case OP_BYTE_CONSUMED :
startOp ( " ByteConsumed " ) ;
xmlTextReaderByteConsumed ( reader ) ;
break ;
}
if ( totalStringSize > docSize * 2 )
break ;
}
error = xmlTextReaderGetLastError ( reader ) ;
if ( error - > code = = XML_ERR_NO_MEMORY )
oomReport = 1 ;
xmlFuzzCheckMallocFailure ( " reader " , oomReport ) ;
xmlFreeTextReader ( reader ) ;
if ( doc ! = NULL )
xmlFreeDoc ( doc ) ;
exit :
xmlFuzzMemSetLimit ( 0 ) ;
xmlFuzzDataCleanup ( ) ;
xmlResetLastError ( ) ;
return ( 0 ) ;
}