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#include "apr_general.h" 19#include "apr_xml.h" 20#include "abts.h" 21#include "testutil.h" 22 23static apr_status_t create_dummy_file_error(abts_case *tc, apr_pool_t *p, 24 apr_file_t **fd) 25{ 26 int i; 27 apr_status_t rv; 28 apr_off_t off = 0L; 29 char template[] = "data/testxmldummyerrorXXXXXX"; 30 31 rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | 32 APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); 33 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 34 35 if (rv != APR_SUCCESS) 36 return rv; 37 38 rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<maryx>" 39 "<had a=\"little\"/><lamb/>\n", *fd); 40 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 41 42 for (i = 0; i < 5000; i++) { 43 rv = apr_file_puts("<hmm roast=\"lamb\" " 44 "for=\"dinner\">yummy</hmm>\n", *fd); 45 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 46 } 47 48 rv = apr_file_puts("</mary>\n", *fd); 49 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 50 51 rv = apr_file_seek(*fd, APR_SET, &off); 52 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 53 54 return rv; 55} 56 57static apr_status_t create_dummy_file(abts_case *tc, apr_pool_t *p, 58 apr_file_t **fd) 59{ 60 int i; 61 apr_status_t rv; 62 apr_off_t off = 0L; 63 char template[] = "data/testxmldummyXXXXXX"; 64 65 rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | 66 APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); 67 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 68 69 if (rv != APR_SUCCESS) 70 return rv; 71 72 rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<mary>\n", *fd); 73 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 74 75 for (i = 0; i < 5000; i++) { 76 rv = apr_file_puts("<hmm roast=\"lamb\" " 77 "for=\"dinner <>=\">yummy</hmm>\n", *fd); 78 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 79 } 80 81 rv = apr_file_puts("</mary>\n", *fd); 82 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 83 84 rv = apr_file_seek(*fd, APR_SET, &off); 85 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 86 87 return rv; 88} 89 90static void dump_xml(abts_case *tc, apr_xml_elem *e, int level) 91{ 92 apr_xml_attr *a; 93 apr_xml_elem *ec; 94 95 if (level == 0) { 96 ABTS_STR_EQUAL(tc, "mary", e->name); 97 } else { 98 ABTS_STR_EQUAL(tc, "hmm", e->name); 99 } 100 101 if (e->attr) { 102 a = e->attr; 103 ABTS_PTR_NOTNULL(tc, a); 104 ABTS_STR_EQUAL(tc, "for", a->name); 105 ABTS_STR_EQUAL(tc, "dinner <>=", a->value); 106 a = a->next; 107 ABTS_PTR_NOTNULL(tc, a); 108 ABTS_STR_EQUAL(tc, "roast", a->name); 109 ABTS_STR_EQUAL(tc, "lamb", a->value); 110 } 111 if (e->first_child) { 112 ec = e->first_child; 113 while (ec) { 114 dump_xml(tc, ec, level + 1); 115 ec = ec->next; 116 } 117 } 118} 119 120static void test_xml_parser(abts_case *tc, void *data) 121{ 122 apr_file_t *fd; 123 apr_xml_parser *parser; 124 apr_xml_doc *doc; 125 apr_status_t rv; 126 127 rv = create_dummy_file(tc, p, &fd); 128 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 129 130 if (rv != APR_SUCCESS) 131 return; 132 133 rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); 134 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 135 136 dump_xml(tc, doc->root, 0); 137 138 rv = apr_file_close(fd); 139 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 140 141 rv = create_dummy_file_error(tc, p, &fd); 142 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 143 144 if (rv != APR_SUCCESS) 145 return; 146 147 rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); 148 ABTS_TRUE(tc, rv != APR_SUCCESS); 149} 150 151static void test_billion_laughs(abts_case *tc, void *data) 152{ 153 apr_file_t *fd; 154 apr_xml_parser *parser; 155 apr_xml_doc *doc; 156 apr_status_t rv; 157 158 rv = apr_file_open(&fd, "data/billion-laughs.xml", 159 APR_FOPEN_READ, 0, p); 160 apr_assert_success(tc, "open billion-laughs.xml", rv); 161 162 /* Don't test for return value; if it returns, chances are the bug 163 * is fixed or the machine has insane amounts of RAM. */ 164 apr_xml_parse_file(p, &parser, &doc, fd, 2000); 165 166 apr_file_close(fd); 167} 168 169static void test_CVE_2009_3720_alpha(abts_case *tc, void *data) 170{ 171 apr_xml_parser *xp; 172 apr_xml_doc *doc; 173 apr_status_t rv; 174 175 xp = apr_xml_parser_create(p); 176 177 rv = apr_xml_parser_feed(xp, "\0\r\n", 3); 178 if (rv == APR_SUCCESS) 179 apr_xml_parser_done(xp, &doc); 180} 181 182static void test_CVE_2009_3720_beta(abts_case *tc, void *data) 183{ 184 apr_xml_parser *xp; 185 apr_xml_doc *doc; 186 apr_status_t rv; 187 188 xp = apr_xml_parser_create(p); 189 190 rv = apr_xml_parser_feed(xp, "<?xml version\xc2\x85='1.0'?>\r\n", 25); 191 if (rv == APR_SUCCESS) 192 apr_xml_parser_done(xp, &doc); 193} 194 195abts_suite *testxml(abts_suite *suite) 196{ 197 suite = ADD_SUITE(suite); 198 199 abts_run_test(suite, test_xml_parser, NULL); 200 abts_run_test(suite, test_billion_laughs, NULL); 201 abts_run_test(suite, test_CVE_2009_3720_alpha, NULL); 202 abts_run_test(suite, test_CVE_2009_3720_beta, NULL); 203 204 return suite; 205} 206