Add javascript capabilities in pdf_xfa_fdp_fuzzer
Add support for simple javascript statements in pdf_xfa_fdp_fuzzer
Bug: chromium:1276950
Change-Id: I327e681b773e0824b43a472bdfa2f0a72c7586b0
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/88110
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/testing/fuzzers/pdf_xfa_fdp_fuzzer.cc b/testing/fuzzers/pdf_xfa_fdp_fuzzer.cc
index 86d3139..de36fcd 100644
--- a/testing/fuzzers/pdf_xfa_fdp_fuzzer.cc
+++ b/testing/fuzzers/pdf_xfa_fdp_fuzzer.cc
@@ -195,8 +195,8 @@
FuzzedDataProvider* fdp_ = nullptr;
};
-// Possible names of an XFA script function
-std::string GenXfaScriptFuncName(FuzzedDataProvider* data_provider) {
+// Possible names of an XFA FormCalc script function
+std::string GenXfaFormCalcScriptFuncName(FuzzedDataProvider* data_provider) {
static const char* const kXfaScriptFuncs[] = {
"Abs", "Apr", "At", "Avg", "Ceil",
"Choose", "Concat", "Count", "Cterm", "Date",
@@ -648,17 +648,18 @@
// Possible XFA attributes values
std::string GenXfaTagValue(FuzzedDataProvider* data_provider) {
static const char* const kXfaTagVals[] = {
- "0", "0pt", "-1",
- "123", "1pt", "203.2mm",
- "22.1404mm", "255", "256",
- "321", "5431.21mm", "6.35mm",
- "8in", "8pt", "application/x-javascript",
- "bold", "bold", "consumeData",
- "en_US", "form1", "initialize",
- "italic", "middle", "name2",
- "name3", "name4", "name5",
- "Page1", "RadioList[0]", "subform_1",
- "tb", "Verdana", "Verdana",
+ "0", "0pt", "-1",
+ "123", "1pt", "203.2mm",
+ "22.1404mm", "255", "256",
+ "321", "5431.21mm", "6.35mm",
+ "8in", "8pt", "application/x-javascript",
+ "bold", "bold", "change",
+ "click", "consumeData", "docReady",
+ "en_US", "form1", "initialize",
+ "italic", "middle", "name2",
+ "name3", "name4", "name5",
+ "onEnter", "Page1", "RadioList[0]",
+ "subform_1", "tb", "Verdana",
};
size_t elem_selector = data_provider->ConsumeIntegralInRange<size_t>(
@@ -669,17 +670,22 @@
// possible XFA attributes
std::string GenXfaTagName(FuzzedDataProvider* data_provider) {
static const char* const kXfaTagNames[] = {
- "activity", "activity", "baselineShift",
- "contentType", "h", "id",
- "layout", "layout", "leftInset",
- "locale", "long", "marginLeft",
- "marginRight", "marginRight", "mergeMode",
- "name", "ref", "scriptTest",
- "short", "size", "spaceAbove",
- "spaceBelow", "startNew", "stock",
- "tetIndent", "timeStamp", "typeface",
- "uuid", "vAlign", "value",
- "w", "weight", "x",
+ "activity", "baselineShift",
+ "contentType", "h",
+ "id", "layout",
+ "layout", "leftInset",
+ "locale", "long",
+ "marginLeft", "marginRight",
+ "marginRight", "mergeMode",
+ "name", "ref",
+ "scriptTest", "short",
+ "size", "spaceAbove",
+ "spaceBelow", "startNew",
+ "stock", "textIndent",
+ "timeStamp", "typeface",
+ "uuid", "vAlign",
+ "value", "w",
+ "weight", "x",
"y",
};
size_t elem_selector = data_provider->ConsumeIntegralInRange<size_t>(
@@ -687,30 +693,158 @@
return kXfaTagNames[elem_selector];
}
-// Will create a simple XFA script that calls a single function.
-std::string GenXfacript(FuzzedDataProvider* data_provider) {
- std::string xfa_string = GenXfaScriptFuncName(data_provider);
+// Will create a simple XFA FormCalc script that calls a single function.
+std::string GenXfaFormCalcScript(FuzzedDataProvider* data_provider) {
+ std::string xfa_string = GenXfaFormCalcScriptFuncName(data_provider);
xfa_string += "(";
- int num_params = data_provider->ConsumeIntegralInRange(0, 3);
- // 0 case we do nothing.
- if (num_params == 1) {
- xfa_string += GenXfaScriptParam(data_provider);
- } else if (num_params == 2) {
- xfa_string += GenXfaScriptParam(data_provider);
- xfa_string += ",";
- xfa_string += GenXfaScriptParam(data_provider);
- } else if (num_params == 3) {
- xfa_string += GenXfaScriptParam(data_provider);
- xfa_string += ",";
- xfa_string += GenXfaScriptParam(data_provider);
- xfa_string += ",";
+ // Generate parameters
+ size_t num_params = data_provider->ConsumeIntegralInRange<size_t>(0, 3);
+ for (size_t i = 0; i < num_params; i++) {
+ if (i != 0) {
+ xfa_string += ",";
+ }
xfa_string += GenXfaScriptParam(data_provider);
}
xfa_string += ")";
return xfa_string;
}
+// XFA Javascript logic
+std::string GenXfaName(FuzzedDataProvider* data_provider) {
+ return "name" + std::to_string(data_provider->ConsumeIntegralInRange(0, 25));
+}
+
+std::string GetXfaJSPrimitiveType(FuzzedDataProvider* data_provider) {
+ return GenXfaScriptParam(data_provider);
+}
+
+std::string GenXfaJSRValue(FuzzedDataProvider* data_provider) {
+ if (data_provider->ConsumeBool()) {
+ return GenXfaScriptParam(data_provider);
+ }
+
+ std::string xfa_string;
+ if (data_provider->ConsumeBool()) {
+ xfa_string += "xfa.form.";
+ }
+
+ // Handle the possibility of nested names
+ size_t num_nests = data_provider->ConsumeIntegralInRange<size_t>(1, 3);
+ for (size_t i = 0; i < num_nests; i++) {
+ if (i != 0) {
+ xfa_string += ".";
+ }
+ xfa_string += GenXfaName(data_provider);
+ }
+ return MaybeQuote(data_provider, xfa_string);
+}
+
+std::string GenXfaJSAssignment(FuzzedDataProvider* data_provider) {
+ return GenXfaName(data_provider) + " = " + GenXfaJSRValue(data_provider);
+}
+
+std::string GenXfaJSMethodCall(FuzzedDataProvider* data_provider) {
+ static const char* const kXfaJSFuncs[] = {
+ "addItem",
+ "boundItem",
+ "clearItems",
+ "deleteItem",
+ "execCalculate",
+ "execEvent",
+ "execInitialize",
+ "execValidate",
+ "getDisplayItem",
+ "getItemState",
+ "getSaveItem",
+ "exec.form.formNodes",
+ "exec.form.recalculate",
+ "setItemState",
+ "xfa.container.getDelta",
+ "xfa.container.getDeltas",
+ "xfa.event.emit",
+ "xfa.event.reset",
+ "xfa.form.execCalculat",
+ "xfa.form.execInitialize",
+ "xfa.form.execValidate",
+ "xfa.form.remerge",
+ "xfa.host.beep",
+ "xfa.host.documentCountInBatch",
+ "xfa.host.documentInBatch",
+ "xfa.host.exportData",
+ "xfa.host.getFocus",
+ "xfa.host.gotoURL",
+ "xfa.host.importData",
+ "xfa.host.messageBox",
+ "xfa.host.openList",
+ "xfa.host.pageDown",
+ "xfa.host.pageUp",
+ "xfa.host.print",
+ "xfa.host.resetData",
+ "xfa.host.setFocus",
+ "xfa.host.response",
+ "xfa.resolveNode",
+ };
+
+ std::string xfa_string = data_provider->PickValueInArray(kXfaJSFuncs);
+ xfa_string += "(";
+
+ // Get the params
+ size_t param_count = data_provider->ConsumeIntegralInRange<size_t>(0, 3);
+ for (size_t i = 0; i < param_count; i++) {
+ if (i != 0) {
+ xfa_string += ",";
+ }
+ xfa_string += GenXfaJSRValue(data_provider);
+ }
+ xfa_string += ")";
+ return xfa_string;
+}
+
+// This is a simple generator of xfa-based javascript. The function creates
+// simple javascript statements that are related to XFA logic and the goal is
+// not to create fully-fleged javascript programs but rather use simple
+// statements to ensure XFA code is covered.
+enum XFAJSStatement {
+ kAssignment = 0,
+ kJSMethodCall,
+ kJSObjectCall,
+ kMaxValue = kJSObjectCall
+};
+
+std::string GenXfaJSScript(FuzzedDataProvider* data_provider) {
+ std::string xfa_string;
+
+ size_t num_stmts = data_provider->ConsumeIntegralInRange<size_t>(1, 10);
+ for (size_t i = 0; i < num_stmts; i++) {
+ XFAJSStatement stmt = data_provider->ConsumeEnum<XFAJSStatement>();
+ switch (stmt) {
+ case kAssignment:
+ xfa_string += GenXfaJSAssignment(data_provider);
+ break;
+ case kJSMethodCall:
+ xfa_string += GenXfaJSMethodCall(data_provider);
+ break;
+ case kJSObjectCall:
+ xfa_string += GenXfaName(data_provider);
+ xfa_string += ".";
+ xfa_string += GenXfaJSMethodCall(data_provider);
+ break;
+ }
+ xfa_string += ";\n";
+ }
+ return xfa_string;
+}
+
+std::string GenXfacript(FuzzedDataProvider* data_provider) {
+ // Determine if this should be a FormCalc script or Javascript, 50/50 chance
+ // for each.
+ if (data_provider->ConsumeBool()) {
+ return GenXfaFormCalcScript(data_provider);
+ }
+ return GenXfaJSScript(data_provider);
+}
+
// Will create a single XFA attributes, with both lhs and rhs.
std::string getXfaElemAttributes(FuzzedDataProvider* data_provider) {
// Generate a set of tags, and a set of values for the tags.