1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "apr.h"
18251876Speter#include "apr_general.h"
19251876Speter#include "apr_xml.h"
20251876Speter#include "abts.h"
21251876Speter#include "testutil.h"
22251876Speter
23251876Speterstatic apr_status_t create_dummy_file_error(abts_case *tc, apr_pool_t *p,
24251876Speter                                            apr_file_t **fd)
25251876Speter{
26251876Speter    int i;
27251876Speter    apr_status_t rv;
28251876Speter    apr_off_t off = 0L;
29251876Speter    char template[] = "data/testxmldummyerrorXXXXXX";
30251876Speter
31251876Speter    rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE |
32251876Speter                         APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p);
33251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
34251876Speter
35251876Speter    if (rv != APR_SUCCESS)
36251876Speter        return rv;
37251876Speter
38251876Speter    rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<maryx>"
39251876Speter                       "<had a=\"little\"/><lamb/>\n", *fd);
40251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
41251876Speter
42251876Speter    for (i = 0; i < 5000; i++) {
43251876Speter        rv = apr_file_puts("<hmm roast=\"lamb\" "
44251876Speter                           "for=\"dinner\">yummy</hmm>\n", *fd);
45251876Speter        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
46251876Speter    }
47251876Speter
48251876Speter    rv = apr_file_puts("</mary>\n", *fd);
49251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
50251876Speter
51251876Speter    rv = apr_file_seek(*fd, APR_SET, &off);
52251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
53251876Speter
54251876Speter    return rv;
55251876Speter}
56251876Speter
57251876Speterstatic apr_status_t create_dummy_file(abts_case *tc, apr_pool_t *p,
58251876Speter                                      apr_file_t **fd)
59251876Speter{
60251876Speter    int i;
61251876Speter    apr_status_t rv;
62251876Speter    apr_off_t off = 0L;
63251876Speter    char template[] = "data/testxmldummyXXXXXX";
64251876Speter
65251876Speter    rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE |
66251876Speter                         APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p);
67251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
68251876Speter
69251876Speter    if (rv != APR_SUCCESS)
70251876Speter        return rv;
71251876Speter
72251876Speter    rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<mary>\n", *fd);
73251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
74251876Speter
75251876Speter    for (i = 0; i < 5000; i++) {
76251876Speter        rv = apr_file_puts("<hmm roast=\"lamb\" "
77251876Speter                           "for=\"dinner &lt;&gt;&#x3D;\">yummy</hmm>\n", *fd);
78251876Speter        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
79251876Speter    }
80251876Speter
81251876Speter    rv = apr_file_puts("</mary>\n", *fd);
82251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
83251876Speter
84251876Speter    rv = apr_file_seek(*fd, APR_SET, &off);
85251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
86251876Speter
87251876Speter    return rv;
88251876Speter}
89251876Speter
90251876Speterstatic void dump_xml(abts_case *tc, apr_xml_elem *e, int level)
91251876Speter{
92251876Speter    apr_xml_attr *a;
93251876Speter    apr_xml_elem *ec;
94251876Speter
95251876Speter    if (level == 0) {
96251876Speter        ABTS_STR_EQUAL(tc, "mary", e->name);
97251876Speter    } else {
98251876Speter        ABTS_STR_EQUAL(tc, "hmm", e->name);
99251876Speter    }
100251876Speter
101251876Speter    if (e->attr) {
102251876Speter        a = e->attr;
103251876Speter        ABTS_PTR_NOTNULL(tc, a);
104251876Speter        ABTS_STR_EQUAL(tc, "for", a->name);
105251876Speter        ABTS_STR_EQUAL(tc, "dinner <>=", a->value);
106251876Speter        a = a->next;
107251876Speter        ABTS_PTR_NOTNULL(tc, a);
108251876Speter        ABTS_STR_EQUAL(tc, "roast", a->name);
109251876Speter        ABTS_STR_EQUAL(tc, "lamb", a->value);
110251876Speter    }
111251876Speter    if (e->first_child) {
112251876Speter        ec = e->first_child;
113251876Speter        while (ec) {
114251876Speter            dump_xml(tc, ec, level + 1);
115251876Speter            ec = ec->next;
116251876Speter        }
117251876Speter    }
118251876Speter}
119251876Speter
120251876Speterstatic void test_xml_parser(abts_case *tc, void *data)
121251876Speter{
122251876Speter    apr_file_t *fd;
123251876Speter    apr_xml_parser *parser;
124251876Speter    apr_xml_doc *doc;
125251876Speter    apr_status_t rv;
126251876Speter
127251876Speter    rv = create_dummy_file(tc, p, &fd);
128251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
129251876Speter
130251876Speter    if (rv != APR_SUCCESS)
131251876Speter        return;
132251876Speter
133251876Speter    rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000);
134251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
135251876Speter
136251876Speter    dump_xml(tc, doc->root, 0);
137251876Speter
138251876Speter    rv = apr_file_close(fd);
139251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
140251876Speter
141251876Speter    rv = create_dummy_file_error(tc, p, &fd);
142251876Speter    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
143251876Speter
144251876Speter    if (rv != APR_SUCCESS)
145251876Speter        return;
146251876Speter
147251876Speter    rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000);
148251876Speter    ABTS_TRUE(tc, rv != APR_SUCCESS);
149251876Speter}
150251876Speter
151251876Speterstatic void test_billion_laughs(abts_case *tc, void *data)
152251876Speter{
153251876Speter    apr_file_t *fd;
154251876Speter    apr_xml_parser *parser;
155251876Speter    apr_xml_doc *doc;
156251876Speter    apr_status_t rv;
157251876Speter
158251876Speter    rv = apr_file_open(&fd, "data/billion-laughs.xml",
159251876Speter                       APR_FOPEN_READ, 0, p);
160251876Speter    apr_assert_success(tc, "open billion-laughs.xml", rv);
161251876Speter
162251876Speter    /* Don't test for return value; if it returns, chances are the bug
163251876Speter     * is fixed or the machine has insane amounts of RAM. */
164251876Speter    apr_xml_parse_file(p, &parser, &doc, fd, 2000);
165251876Speter
166251876Speter    apr_file_close(fd);
167251876Speter}
168251876Speter
169251876Speterstatic void test_CVE_2009_3720_alpha(abts_case *tc, void *data)
170251876Speter{
171251876Speter    apr_xml_parser *xp;
172251876Speter    apr_xml_doc *doc;
173251876Speter    apr_status_t rv;
174251876Speter
175251876Speter    xp = apr_xml_parser_create(p);
176251876Speter
177251876Speter    rv = apr_xml_parser_feed(xp, "\0\r\n", 3);
178251876Speter    if (rv == APR_SUCCESS)
179251876Speter        apr_xml_parser_done(xp, &doc);
180251876Speter}
181251876Speter
182251876Speterstatic void test_CVE_2009_3720_beta(abts_case *tc, void *data)
183251876Speter{
184251876Speter    apr_xml_parser *xp;
185251876Speter    apr_xml_doc *doc;
186251876Speter    apr_status_t rv;
187251876Speter
188251876Speter    xp = apr_xml_parser_create(p);
189251876Speter
190251876Speter    rv = apr_xml_parser_feed(xp, "<?xml version\xc2\x85='1.0'?>\r\n", 25);
191251876Speter    if (rv == APR_SUCCESS)
192251876Speter        apr_xml_parser_done(xp, &doc);
193251876Speter}
194251876Speter
195251876Speterabts_suite *testxml(abts_suite *suite)
196251876Speter{
197251876Speter    suite = ADD_SUITE(suite);
198251876Speter
199251876Speter    abts_run_test(suite, test_xml_parser, NULL);
200251876Speter    abts_run_test(suite, test_billion_laughs, NULL);
201251876Speter    abts_run_test(suite, test_CVE_2009_3720_alpha, NULL);
202251876Speter    abts_run_test(suite, test_CVE_2009_3720_beta, NULL);
203251876Speter
204251876Speter    return suite;
205251876Speter}
206