xmlwf: Add support for custom attack protection parameters

This commit is contained in:
Sebastian Pipping 2021-04-17 17:26:17 +02:00
parent 65cddaa4e9
commit c6223b3b0f
3 changed files with 82 additions and 1 deletions

View File

@ -7,7 +7,7 @@
|_| XML parser
Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
Copyright (c) 2016-2017 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
@ -55,6 +55,8 @@
# define tmain wmain
# define tremove _wremove
# define tchar wchar_t
# define tcstof wcstof
# define tcstoull wcstoull
#else /* not XML_UNICODE */
# define T(x) x
# define ftprintf fprintf
@ -72,4 +74,6 @@
# define tmain main
# define tremove remove
# define tchar char
# define tcstof strtof
# define tcstoull strtoull
#endif /* not XML_UNICODE */

View File

@ -46,6 +46,8 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <math.h> /* for isnan */
#include <errno.h>
#include "expat.h"
#include "codepage.h"
@ -905,6 +907,12 @@ usage(const XML_Char *prog, int rc) {
T(" -t write no XML output for [t]iming of plain parsing\n")
T(" -N enable adding doctype and [n]otation declarations\n")
T("\n")
T("billion laughs attack protection:\n")
T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
T("\n")
T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n")
T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n")
T("\n")
T("info arguments:\n")
T(" -h show this [h]elp message and exit\n")
T(" -v show program's [v]ersion number and exit\n")
@ -953,6 +961,11 @@ tmain(int argc, XML_Char **argv) {
int requireStandalone = 0;
int requiresNotations = 0;
int continueOnError = 0;
float attackMaximumAmplification = -1.0f; /* signaling "not set" */
unsigned long long attackThresholdBytes;
XML_Bool attackThresholdGiven = XML_FALSE;
int exitCode = XMLWF_EXIT_SUCCESS;
enum XML_ParamEntityParsing paramEntityParsing
= XML_PARAM_ENTITY_PARSING_NEVER;
@ -1032,6 +1045,49 @@ tmain(int argc, XML_Char **argv) {
continueOnError = 1;
j++;
break;
case T('a'): {
const XML_Char *valueText = NULL;
XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
errno = 0;
XML_Char *afterValueText = (XML_Char *)valueText;
attackMaximumAmplification = tcstof(valueText, &afterValueText);
if ((errno != 0) || (afterValueText[0] != T('\0'))
|| isnan(attackMaximumAmplification)
|| (attackMaximumAmplification < 1.0f)) {
// This prevents tperror(..) from reporting misleading "[..]: Success"
errno = ERANGE;
tperror(T("invalid amplification limit") T(
" (needs a floating point number greater or equal than 1.0)"));
exit(XMLWF_EXIT_USAGE_ERROR);
}
#ifndef XML_DTD
ftprintf(stderr, T("Warning: Given amplification limit ignored") T(
", xmlwf has been compiled without DTD support.\n"));
#endif
break;
}
case T('b'): {
const XML_Char *valueText = NULL;
XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
errno = 0;
XML_Char *afterValueText = (XML_Char *)valueText;
attackThresholdBytes = tcstoull(valueText, &afterValueText, 10);
if ((errno != 0) || (afterValueText[0] != T('\0'))) {
// This prevents tperror(..) from reporting misleading "[..]: Success"
errno = ERANGE;
tperror(T("invalid ignore threshold")
T(" (needs an integer from 0 to 2^64-1)"));
exit(XMLWF_EXIT_USAGE_ERROR);
}
attackThresholdGiven = XML_TRUE;
#ifndef XML_DTD
ftprintf(stderr, T("Warning: Given attack threshold ignored") T(
", xmlwf has been compiled without DTD support.\n"));
#endif
break;
}
case T('\0'):
if (j > 1) {
i++;
@ -1062,6 +1118,19 @@ tmain(int argc, XML_Char **argv) {
exit(XMLWF_EXIT_INTERNAL_ERROR);
}
if (attackMaximumAmplification != -1.0f) {
#ifdef XML_DTD
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
parser, attackMaximumAmplification);
#endif
}
if (attackThresholdGiven) {
#ifdef XML_DTD
XML_SetBillionLaughsAttackProtectionActivationThreshold(
parser, attackThresholdBytes);
#endif
}
if (requireStandalone)
XML_SetNotStandaloneHandler(parser, notStandalone);
XML_SetParamEntityParsing(parser, paramEntityParsing);

View File

@ -73,6 +73,14 @@ output_mode.add_argument('-m', action='store_true', help='write [m]eta XML, not
output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
billion_laughs = parser.add_argument_group('billion laughs attack protection',
description='NOTE: '
'If you ever need to increase these values '
'for non-attack payload, please file a bug report.')
billion_laughs.add_argument('-a', metavar='FACTOR',
help='set maximum tolerated [a]mplification factor (default: 100.0)')
billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
info = parser.add_argument_group('info arguments')