[xmlsec] error in moving nodes between documents: heap corruption detected

Tomas Sieger tomas.sieger at systinet.com
Tue Nov 30 03:10:33 PST 2004


Hi,
  I found a problem in moving document (D1) nodes into another
document (D2). It seems that the moved nodes still refer to some
data in the original document D1, so after D1 gets deleted,
D2 contains invalid nodes. The invalid nodes are revealed e.g.
when deleting D1 - glibc reports heap corruption.

A note for xmlsec users: I encountered this problem using xmlSec:
xmlSecReplaceNodeBuffer function is the creator of D1 as well as
it also moves D1 nodes into another document. The
xmlSecReplaceNodeBuffer function is used e.g. when decrypting
encrypted data.

The problem appears in libxml2-2.6.15 and newer. libxml2-2.6.14
does not cause the problem. I've discovered that this commit:

   http://cvs.gnome.org/viewcvs/libxml2/parser.c?r1=1.391&r2=1.392

causes the problem. Revision 1.391 of parser.c works well,
revision 1.392 does not. CVS HEAD (revision 1.404) suffers from
the same problem.

I attach a simple test case. When running with glibc memory debugs
enabled (MALLOC_CHECK_ environment variable, enabled by default on
Fedora Core 3), the following message is displayed:

   *** glibc detected *** double free or corruption: 0x0966dc43 ***
   Aborted

when deleting "doc" at line 138:

   xmlFreeDoc(doc);

gdb gives the following stack trace:

#0  0x006f87a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1  0x00738955 in raise () from /lib/tls/libc.so.6
#2  0x0073a319 in abort () from /lib/tls/libc.so.6
#3  0x00771a1b in malloc_printerr () from /lib/tls/libc.so.6
#4  0x007724ba in free () from /lib/tls/libc.so.6
#5  0xf6f4ec0c in xmlFreeNodeList__internal_alias (cur=0x835800) at 
tree.c:3380
#6  0xf6f4eb49 in xmlFreeNodeList__internal_alias (cur=0x86f40a0) at 
tree.c:3353
#7  0xf6f4eb49 in xmlFreeNodeList__internal_alias (cur=0x86f32d8) at 
tree.c:3353
#8  0xf6f4f2c5 in xmlFreeDoc__internal_alias (cur=0x86f3268) at tree.c:1153
#9  0x08048b33 in main () at testinsert.c:138

libxml2 memory debugs (enabled by giving libxml2 ./configure
"--with-mem-debug --with-run-debug" parameters) output is attached,
too.

best regards,
  Tomas

-------------- next part --------------
#include <libxml/tree.h>
//#include <xmlsec/xmltree.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

typedef unsigned char xmlSecByte;

void printElement(xmlNodePtr a) {
    printf("node %p (%s)\n",a,a?a->name:BAD_CAST "n/a");
}

/*
 * took from xmlsec:
 */
xmlDocPtr parseMemoryExt(const xmlSecByte *prefix, int prefixSize,
                         const xmlSecByte *buffer, int bufferSize,
                         const xmlSecByte *postfix, int postfixSize) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlDocPtr doc = NULL;
    int ret;

    /* create context */
    ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
    if(ctxt == NULL) {
        fprintf(stderr,"xmlCreatePushParserCtxt");
        goto done;
    }

    /* required for c14n! */
    ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
    ctxt->replaceEntities = 1;

    /* prefix */
    if((prefix != NULL) && (prefixSize > 0)) {
        ret = xmlParseChunk(ctxt, (const char*)prefix, prefixSize, 0);
        if(ret != 0) {
            fprintf(stderr,"xmlParseChunk");
            goto done;
        }
    }

    /* buffer */
    if((buffer != NULL) && (bufferSize > 0)) {
        ret = xmlParseChunk(ctxt, (const char*)buffer, bufferSize, 0);
        if(ret != 0) {
            fprintf(stderr,"xmlParseChunk");
            goto done;
        }
    }

    /* postfix */
    if((postfix != NULL) && (postfixSize > 0)) {
        ret = xmlParseChunk(ctxt, (const char*)postfix, postfixSize, 0);
        if(ret != 0) {
            fprintf(stderr,"xmlParseChunk");
            goto done;
        }
    }

    /* finishing */
    ret = xmlParseChunk(ctxt, NULL, 0, 1);
    if((ret != 0) || (ctxt->myDoc == NULL)) {
        fprintf(stderr,"xmlParseChunk");
        goto done;
    }
    doc = ctxt->myDoc;

done:
    if(ctxt != NULL) {
        xmlFreeParserCtxt(ctxt);
    }
    return(doc);
}

/*
 * took from xmlsec:
 */
int replaceNodeBuffer(xmlNodePtr node,
                      const xmlSecByte *buffer, int size) {
    static const char dummyPrefix[] = "<dummy>";
    static const char dummyPostfix[] = "</dummy>";
    xmlDocPtr doc;
    xmlNodePtr ptr1, ptr2;

    doc = parseMemoryExt((xmlSecByte*)dummyPrefix, strlen(dummyPrefix),
                               buffer, size,
                               (xmlSecByte*)dummyPostfix, strlen(dummyPostfix));
    if(doc == NULL){
        fprintf(stderr,"xmlSecParseMemoryExt");
        return(-1);
    }

    ptr1 = xmlDocGetRootElement(doc);
    if(ptr1 == NULL){
        fprintf(stderr,"xmlDocGetRootElement");
        xmlFreeDoc(doc);
        return(-1);
    }
    ptr1 = ptr1->children;
    while(ptr1 != NULL) {
        ptr2 = ptr1->next;
        xmlUnlinkNode(ptr1);
        xmlAddPrevSibling(node, ptr1);
        ptr1 = ptr2;
    }
    xmlUnlinkNode(node);
    xmlFreeNode(node);
    xmlFreeDoc(doc);
    return(0);
}

/*
 * took from xmlsec:
 */
xmlNodePtr
getNextElementNode(xmlNodePtr cur) {
    while((cur != NULL) && (cur->type != XML_ELEMENT_NODE)) {
        cur = cur->next;
    }
    return(cur);
}

main() {
    xmlDocPtr doc;
    xmlNodePtr n;
    xmlChar *buffer1=BAD_CAST "<original><children/></original>";
    xmlChar *buffer2=BAD_CAST "<a><b/></a>";

    doc = parseMemoryExt(NULL,0,buffer1,xmlStrlen(buffer1),NULL,0);
    n=xmlDocGetRootElement(doc);
    n=getNextElementNode(n->children);
    printf("DOC:\n");
    printElement(n);

    replaceNodeBuffer(n,buffer2,xmlStrlen(buffer2));

    xmlFreeDoc(doc);
}
-------------- next part --------------
element: <several hundreds of 0xFF characters>: 
error: Name is not from the document dictionnary '<several hundreds of 0xFFcharacters>'
element: <several hundreds of 0xFF characters>: 
error: Name is not from the document dictionnary '<several hundreds of 0xFFcharacters>'

Memory tag error occurs :0x9b26153 
         bye
      11:12:30 AM

      MEMORY ALLOCATED : 4966, MAX was 16284
BLOCK  NUMBER   SIZE  TYPE
0        1961   1144 realloc() in none(0) [Name is not from the document dictionnary ']
1          59     60 malloc()  in none(0) pointer to #58 at index 20
2          58     60 malloc()  in none(0) pointer to #59 at index 12
3          37     16 malloc()  in none(0)
4          36     60 malloc()  in none(0) pointer to #58 at index 12
5          35      4 malloc()  in none(0) "1.0"
6          34     88 malloc()  in none(0) pointer to #36 at index 12
7          32     16 malloc()  in none(0)
8          31   1024 malloc()  in none(0)
9          23   2048 malloc()  in none(0) pointer to #32 at index 928
10         22     24 malloc()  in none(0) pointer to #23 at index 4
11         20     20 malloc()  in none(0) pointer to #19 at index 0
12         19      5 strdup()  in none(0) "HTML"
13         18     20 malloc()  in none(0) pointer to #17 at index 0
14         17      9 strdup()  in none(0) "US-ASCII"
15         16     20 malloc()  in none(0) pointer to #15 at index 0
16         15      6 strdup()  in none(0) "ASCII"
17         14     20 malloc()  in none(0) pointer to #13 at index 0
18         13     11 strdup()  in none(0) "ISO-8859-1"
19         12     20 malloc()  in none(0) pointer to #11 at index 0
20         11      7 strdup()  in none(0) "UTF-16"
21         10     20 malloc()  in none(0) pointer to #9 at index 0
22          9      9 strdup()  in none(0) "UTF-16BE"
23          8     20 malloc()  in none(0) pointer to #7 at index 0
24          7      9 strdup()  in none(0) "UTF-16LE"
25          6     20 malloc()  in none(0) pointer to #5 at index 0
26          5      6 strdup()  in none(0) "UTF-8"
27          4    200 malloc()  in none(0) pointer to #6 at index 0
xmlMemFree(9B26173) error
xmlMallocBreakpoint reached on block 0
Memory tag error occurs :0x9b26151 
         bye
      11:12:30 AM

      MEMORY ALLOCATED : 4906, MAX was 16284
BLOCK  NUMBER   SIZE  TYPE
0        1961   1144 realloc() in none(0) [Name is not from the document dictionnary ']
1          58     60 malloc()  in none(0) pointer to #36 at index 20
2          37     16 malloc()  in none(0)
3          36     60 malloc()  in none(0) pointer to #58 at index 12
4          35      4 malloc()  in none(0) "1.0"
5          34     88 malloc()  in none(0) pointer to #36 at index 12
6          32     16 malloc()  in none(0)
7          31   1024 malloc()  in none(0)
8          23   2048 malloc()  in none(0) pointer to #32 at index 928
9          22     24 malloc()  in none(0) pointer to #23 at index 4
10         20     20 malloc()  in none(0) pointer to #19 at index 0
11         19      5 strdup()  in none(0) "HTML"
12         18     20 malloc()  in none(0) pointer to #17 at index 0
13         17      9 strdup()  in none(0) "US-ASCII"
14         16     20 malloc()  in none(0) pointer to #15 at index 0
15         15      6 strdup()  in none(0) "ASCII"
16         14     20 malloc()  in none(0) pointer to #13 at index 0
17         13     11 strdup()  in none(0) "ISO-8859-1"
18         12     20 malloc()  in none(0) pointer to #11 at index 0
19         11      7 strdup()  in none(0) "UTF-16"
20         10     20 malloc()  in none(0) pointer to #9 at index 0
21          9      9 strdup()  in none(0) "UTF-16BE"
22          8     20 malloc()  in none(0) pointer to #7 at index 0
23          7      9 strdup()  in none(0) "UTF-16LE"
24          6     20 malloc()  in none(0) pointer to #5 at index 0
25          5      6 strdup()  in none(0) "UTF-8"
26          4    200 malloc()  in none(0) pointer to #6 at index 0
xmlMemFree(9B26171) error
xmlMallocBreakpoint reached on block 0


More information about the xmlsec mailing list