CVE-2012-0037 (C, published 2012-06-17T03:41Z)
Description: value: Redland Raptor (aka libraptor) before 2.0.7, as used by OpenOffice 3.3 and 3.4 Beta, LibreOffice before 3.4.6 and 3.5.x before 3.5.1, and other products, allows user-assisted remote attackers to read arbitrary files via a crafted XML external entity (XXE) declaration and reference in an RDF document.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-611 \u2014 Improper Restriction of XML External Entity Reference
The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
Repository: https://github.com/dajobe/raptor
Files changed:
ChangeLog
NEWS.html
RELEASE.html
docs/raptor-1-to-2-map.tsv
librdfa/rdfa.c
src/raptor2.h.in
src/raptor_libxml.c
src/raptor_option.c
src/raptor_rdfxml.c
src/raptor_rss.c
src/raptor_turtle_writer.c
Commit message: CVE-2012-0037

Enforce entity loading policy in raptor_libxml_resolveEntity
and raptor_libxml_getEntity by checking for file URIs and network URIs.

Add RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES / loadExternalEntities for
turning on loading of XML external entity loading, disabled by default.

This affects all the parsers that use SAX2: rdfxml, rss-tag-soup (and
aliases) and rdfa.


Vulnerable code:
<h2 id="D2012-XX-XX-V2.0.7">2012-XX-XX Raptor2 Version 2.0.7 Released</h2>
<p>Not yet released.
</p>

<p>
Added new options for denying file requests and SSL certificate verifying<br />
<p>Not yet released.
</p>
<p>
Added <code>raptor_sax2_set_uri_filter()</code> to set a URI filter
for any SAX2 calls that do internal lookups of URIs.
  RAPTOR_OPTION_LAST = RAPTOR_OPTION_WWW_SSL_VERIFY_HOST
                            const xmlChar *publicId, const xmlChar *systemId) {
  return libxml2_resolveEntity(sax2->xc, publicId, systemId);
raptor_libxml_getEntity(void* user_data, const xmlChar *name) {
  return libxml2_getEntity(sax2->xc, name);

Fixed code:
2012-01-29  Dave Beckett <dave@dajobe.org>

	* librdfa/rdfa.c, src/raptor2.h.in, src/raptor_libxml.c,
	src/raptor_option.c, src/raptor_rdfxml.c, src/raptor_rss.c,
	src/raptor_turtle_writer.c: CVE-2012-0037

	Enforce entity loading policy in raptor_libxml_resolveEntity and
	raptor_libxml_getEntity by checking for file URIs and network
	URIs.

	Add RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES / loadExternalEntities
	for turning on loading of XML external entity loading, disabled by
	default.

	This affects all the parsers that use SAX2: rdfxml, rdfa,
	rss-tag-soup (and aliases).

<h2 id="D2012-03-22-V2.0.7">2012-03-22 Raptor2 Version 2.0.7 Released</h2>
<p>CVE-2012-0037 fixed<br />
Added options for denying file requests and XML entity loading<br />
Added options for SSL certificate verifying<br />
<p>See the <a href="RELEASE.html#rel2_0_7">Raptor2 2.0.7 Release Notes</a>
for the full details of the changes.</p>

<p>CVE-2012-0037 fixed</p>
  <dt><code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code><br/></dt>
  <dd>Deny loading of XML external entity loading. Disabled by
  default.</dd>

<p>The RDF/XML, RSS Tag Soup and RDFa parsers now pass on network,
file and entity loading parser options to the internal SAX2 to enable
enforcing of network, file and entity loading policy.</p>

<p>Added <code>raptor_sax2_set_uri_filter()</code> to set a URI
filter for any SAX2 calls that do internal lookups of URIs.
<p>Control file and network loading inside SAX2.  Option
<code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code> now enforces
loading external XML entities and is by default enabled.  If enabled,
<code>RAPTOR_OPTION_NO_FILE</code> and
<code>RAPTOR_OPTION_NO_NET</code> are also checked.  All URIs loaded
are also passed through any URI filter, if set by
<code>raptor_sax2_set_uri_filter()</code>.
</p>
2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES	-	-
     raptor_sax2_set_option(context->sax2,
                            RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                            RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
 * @RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES: When reading XML, load external entities.
  RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
  RAPTOR_OPTION_LAST = RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES
                            const xmlChar *publicId, const xmlChar *systemId)
{
  xmlParserCtxtPtr ctxt = sax2->xc;
  const unsigned char *uri_string = NULL;
  xmlParserInputPtr entity_input;
  int load_entity = 0;

  if(ctxt->input)
    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->input->filename);

  if(!uri_string)
    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->directory);

  load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
  if(load_entity)
    load_entity = raptor_sax2_check_load_uri_string(sax2, uri_string);

  if(load_entity) {
    entity_input = xmlLoadExternalEntity(RAPTOR_GOOD_CAST(const char*, uri_string),
                                         RAPTOR_GOOD_CAST(const char*, publicId),
                                         ctxt);
  } else {
    RAPTOR_DEBUG4("Not loading entity URI %s by policy for publicId '%s' systemId '%s'\n", uri_string, publicId, systemId);
  }
  
  return entity_input;
raptor_libxml_getEntity(void* user_data, const xmlChar *name)
{
  xmlParserCtxtPtr xc = sax2->xc;
  xmlEntityPtr ret = NULL;

  if(!xc)
    return NULL;

  if(!xc->inSubset) {
    /* looks for hardcoded set of entity names - lt, gt etc. */
    ret = xmlGetPredefinedEntity(name);
    if(ret) {
      RAPTOR_DEBUG2("Entity '%s' found in predefined set\n", name);
      return ret;
    }
  }

  /* This section uses xmlGetDocEntity which looks for entities in
   * memory only, never from a file or URI 
   */
  if(xc->myDoc && (xc->myDoc->standalone == 1)) {
    RAPTOR_DEBUG2("Entity '%s' document is standalone\n", name);
    /* Document is standalone: no entities are required to interpret doc */
    if(xc->inSubset == 2) {
      xc->myDoc->standalone = 0;
      ret = xmlGetDocEntity(xc->myDoc, name);
      xc->myDoc->standalone = 1;
    } else {
      ret = xmlGetDocEntity(xc->myDoc, name);
      if(!ret) {
        xc->myDoc->standalone = 0;
        ret = xmlGetDocEntity(xc->myDoc, name);
        xc->myDoc->standalone = 1;
      }
    }
  } else {
    ret = xmlGetDocEntity(xc->myDoc, name);
  }

  if(ret && !ret->children &&
    (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
    /* Entity is an external general parsed entity. It may be in a
     * catalog file, user file or user URI
     */
    int val = 0;
    xmlNodePtr children;
    int load_entity = 0;

    load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
    if(load_entity)
      load_entity = raptor_sax2_check_load_uri_string(sax2, ret->URI);

    if(!load_entity) {
      RAPTOR_DEBUG2("Not getting entity URI %s by policy\n", ret->URI);
      children = xmlNewText((const xmlChar*)"");
    } else {
      /* Disable SAX2 handlers so that the SAX2 events do not all get
       * sent to callbacks during dealing with the entity parsing.
       */
      sax2->enabled = 0;
      val = xmlParseCtxtExternalEntity(xc, ret->URI, ret->ExternalID, &children);
      sax2->enabled = 1;
    }
    
    if(!val) {
      xmlAddChildList((xmlNodePtr)ret, children);
    } else {
      xc->validate = 0;
      return NULL;
    }
    
    ret->owner = 1;

    /* Mark this entity as having been checked - never do this again */
    if(!ret->checked)
      ret->checked = 1;
  }

  return ret;
  },
  { RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
    (raptor_option_area)(RAPTOR_OPTION_AREA_PARSER | RAPTOR_OPTION_AREA_SAX2),
    RAPTOR_OPTION_VALUE_TYPE_BOOL,
    "loadExternalEntities",
    "Parsers and SAX2 should load external entities."
  raptor_sax2_set_option(rdf_xml_parser->sax2, 
                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
  raptor_sax2_set_option(rss_parser->sax2, 
                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES:
    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES: