Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/xml/apr_xml_expat.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "apr.h"
18
19
#if APU_USE_EXPAT
20
#include "apr_xml.h"
21
22
#if defined(HAVE_XMLPARSE_XMLPARSE_H)
23
#include <xmlparse/xmlparse.h>
24
#elif defined(HAVE_XMLTOK_XMLPARSE_H)
25
#include <xmltok/xmlparse.h>
26
#elif defined(HAVE_XML_XMLPARSE_H)
27
#include <xml/xmlparse.h>
28
#else
29
#include <expat.h>
30
#endif
31
32
typedef enum XML_Error XML_Error;
33
34
#include "apr_xml_internal.h"
35
36
static apr_status_t cleanup_parser(void *ctx)
37
0
{
38
0
    apr_xml_parser *parser = ctx;
39
40
0
    XML_ParserFree(parser->xp);
41
0
    parser->xp = NULL;
42
43
0
    return APR_SUCCESS;
44
0
}
45
static apr_status_t do_parse(apr_xml_parser *parser,
46
                             const char *data, apr_size_t len,
47
                             int is_final)
48
0
{
49
0
    if (parser->xp == NULL) {
50
0
        parser->error = APR_XML_ERROR_PARSE_DONE;
51
0
    }
52
0
    else {
53
0
        int rv = XML_Parse(parser->xp, data, (int)len, is_final);
54
55
0
        if (rv == 0) {
56
0
            parser->error = APR_XML_ERROR_EXPAT;
57
0
            parser->xp_err = XML_GetErrorCode(parser->xp);
58
0
            parser->xp_msg = XML_ErrorString(parser->xp_err);
59
0
        }
60
0
    }
61
62
    /* ### better error code? */
63
0
    return parser->error ? APR_EGENERAL : APR_SUCCESS;
64
0
}
65
66
67
static XMLParserImpl xml_parser_expat = {
68
    do_parse,
69
    cleanup_parser
70
};
71
72
0
XMLParserImpl* apr_xml_get_parser_impl(void) { return &xml_parser_expat; }
73
static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' };
74
75
#if XML_MAJOR_VERSION > 1
76
/* Stop the parser if an entity declaration is hit. */
77
static void entity_declaration(void *userData, const XML_Char *entityName,
78
                               int is_parameter_entity, const XML_Char *value,
79
                               int value_length, const XML_Char *base,
80
                               const XML_Char *systemId, const XML_Char *publicId,
81
                               const XML_Char *notationName)
82
0
{
83
0
    apr_xml_parser *parser = userData;
84
85
0
    XML_StopParser(parser->xp, XML_FALSE);
86
0
}
87
#else
88
/* A noop default_handler. */
89
static void default_handler(void *userData, const XML_Char *s, int len)
90
{
91
}
92
#endif
93
94
apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t *pool,
95
    void *start_func, void *end_func, void *cdata_func)
96
0
{
97
0
    apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser));
98
99
0
    parser->impl = apr_xml_get_parser_impl();
100
101
0
    parser->p = pool;
102
0
    parser->doc = apr_pcalloc(pool, sizeof(*parser->doc));
103
104
0
    parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *));
105
106
    /* ### is there a way to avoid hard-coding this? */
107
0
    apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV);
108
109
0
    parser->xp = XML_ParserCreate(NULL);
110
0
    if (parser->xp == NULL) {
111
0
        (*apr_pool_abort_get(pool))(APR_ENOMEM);
112
0
        return NULL;
113
0
    }
114
115
0
    apr_pool_cleanup_register(pool, parser, cleanup_parser,
116
0
                              apr_pool_cleanup_null);
117
118
0
    XML_SetUserData(parser->xp, parser);
119
0
    XML_SetElementHandler(parser->xp, start_func, end_func);
120
0
    XML_SetCharacterDataHandler(parser->xp, cdata_func);
121
122
    /* Prevent the "billion laughs" attack against expat by disabling
123
     * internal entity expansion.  With 2.x, forcibly stop the parser
124
     * if an entity is declared - this is safer and a more obvious
125
     * failure mode.  With older versions, installing a noop
126
     * DefaultHandler means that internal entities will be expanded as
127
     * the empty string, which is also sufficient to prevent the
128
     * attack. */
129
0
#if XML_MAJOR_VERSION > 1
130
0
    XML_SetEntityDeclHandler(parser->xp, entity_declaration);
131
#else
132
    XML_SetDefaultHandler(parser->xp, default_handler);
133
#endif
134
135
0
    return parser;
136
0
}
137
#endif