-
Notifications
You must be signed in to change notification settings - Fork 365
OSS-Fuzz: Add new fuzzer and corpus targets xml parsing #4168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
arthurscchan
wants to merge
2
commits into
ClusterLabs:main
Choose a base branch
from
arthurscchan:new-fuzzer
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| /* | ||
| * Copyright 2026 the Pacemaker project contributors | ||
| * | ||
| * The version control history for this file may have further details. | ||
| * | ||
| * This source code is licensed under the GNU Lesser General Public License | ||
| * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. | ||
| */ | ||
|
|
||
| #include <crm_internal.h> | ||
|
|
||
| #include <libgen.h> // dirname() | ||
| #include <limits.h> // PATH_MAX | ||
| #include <stdbool.h> // bool, false, true | ||
| #include <stdint.h> // uint8_t | ||
| #include <stdlib.h> // free(), getenv(), setenv() | ||
| #include <string.h> // memcpy() | ||
| #include <unistd.h> // readlink() | ||
|
|
||
| #include <glib.h> // GString, g_string_sized_new() | ||
|
|
||
| #include <crm/common/xml.h> | ||
|
|
||
| /* The input is treated as a CIB document and taken through the stages a real | ||
| * configuration goes through: parse, walk, serialize, validate against a | ||
| * schema, then upgrade to the newest schema. Each stage lives in a different | ||
| * source file, so one input covers the whole XML pipeline. | ||
| */ | ||
|
|
||
| // Schema copy shipped beside the fuzzer binary | ||
| #define SCHEMA_SUBDIR "pacemaker-schemas" | ||
|
|
||
| // Maximum element depth to walk (a deep document costs more to walk than parse) | ||
| #define MAX_DEPTH 8 | ||
|
|
||
| static bool initialized = false; | ||
|
|
||
| /*! | ||
| * \internal | ||
| * \brief Point \c PCMK_schema_directory at the schema copy beside this binary | ||
| * | ||
| * \note The schema cache reads .rng and upgrade .xsl files from disk, so the | ||
| * validate and upgrade stages return early unless it can find them. An | ||
| * existing value is left alone, so a caller can override the location. | ||
| */ | ||
| static void | ||
| set_schema_dir(void) | ||
| { | ||
| char exe[PATH_MAX] = { '\0', }; | ||
| char *schema_dir = NULL; | ||
| ssize_t len = 0; | ||
|
|
||
| if (getenv("PCMK_schema_directory") != NULL) { | ||
| return; | ||
| } | ||
|
|
||
| len = readlink("/proc/self/exe", exe, sizeof(exe) - 1); | ||
| if (len <= 0) { | ||
| return; | ||
| } | ||
| exe[len] = '\0'; | ||
|
|
||
| schema_dir = pcmk__assert_asprintf("%s/%s", dirname(exe), SCHEMA_SUBDIR); | ||
| setenv("PCMK_schema_directory", schema_dir, 0); | ||
| free(schema_dir); | ||
| } | ||
|
|
||
| /*! | ||
| * \internal | ||
| * \brief Recursively parse every attribute of every element | ||
| * | ||
| * \param[in] xml XML element to walk the children of | ||
| * \param[in] depth Current recursion depth | ||
| * | ||
| * \note The parsed values are discarded. What is under test is turning an | ||
| * arbitrary attribute string into a score, a number, a boolean, or a | ||
| * date/time, not whatever any given attribute happens to hold. | ||
| */ | ||
| static void | ||
| walk_children(const xmlNode *xml, int depth) | ||
| { | ||
| if ((xml == NULL) || (depth >= MAX_DEPTH)) { | ||
| return; | ||
| } | ||
|
|
||
| for (const xmlNode *child = pcmk__xe_first_child(xml, NULL, NULL, NULL); | ||
| child != NULL; child = pcmk__xe_next(child, NULL)) { | ||
|
|
||
| for (const xmlAttr *attr = pcmk__xe_first_attr(child); attr != NULL; | ||
| attr = attr->next) { | ||
|
|
||
| const char *name = (const char *) attr->name; | ||
| int score = 0; | ||
| long long ll = 0; | ||
| bool boolean = false; | ||
| crm_time_t *t = NULL; | ||
|
|
||
| pcmk__xe_get_score(child, name, &score, 0); | ||
| pcmk__xe_get_ll(child, name, &ll); | ||
| pcmk__xe_get_bool(child, name, &boolean); | ||
|
|
||
| if (pcmk__xe_get_datetime(child, name, &t) == pcmk_rc_ok) { | ||
| free(t); | ||
| } | ||
| } | ||
|
|
||
| walk_children(child, depth + 1); | ||
| } | ||
| } | ||
|
|
||
| int | ||
| LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
| { | ||
| char *ns = NULL; | ||
| xmlNode *xml = NULL; | ||
| xmlNode *upgraded = NULL; | ||
| GString *buffer = NULL; | ||
|
|
||
| // Have at least some data | ||
| if (size < 5) { | ||
| return -1; // Do not add input to testing corpus | ||
| } | ||
|
|
||
| if (!initialized) { | ||
| set_schema_dir(); | ||
| pcmk__schema_init(); | ||
| initialized = true; | ||
| } | ||
|
|
||
| // pcmk__assert_alloc() zeroes the memory, so the string is terminated | ||
| ns = pcmk__assert_alloc(size + 1, sizeof(char)); | ||
| memcpy(ns, data, size); | ||
|
|
||
| xml = pcmk__xml_parse(ns); | ||
| if (xml == NULL) { | ||
| goto done; | ||
| } | ||
|
|
||
| walk_children(xml, 0); | ||
|
|
||
| buffer = g_string_sized_new(1024); | ||
| pcmk__xml_string(xml, pcmk__xml_fmt_pretty|pcmk__xml_fmt_open | ||
| |pcmk__xml_fmt_children|pcmk__xml_fmt_close | ||
| |pcmk__xml_fmt_text, buffer, 0); | ||
|
|
||
| pcmk__validate_xml(xml, NULL, NULL); | ||
|
|
||
| /* pcmk__update_schema() replaces the node it is given, so hand it a copy | ||
| * and free whatever comes back. Only a crash along the way is of interest | ||
| * here, so its return code is ignored. | ||
| */ | ||
| upgraded = pcmk__xml_copy(NULL, xml); | ||
| if (upgraded != NULL) { | ||
| pcmk__update_schema(&upgraded, NULL, true, false); | ||
| } | ||
|
|
||
| done: | ||
| if (buffer != NULL) { | ||
| g_string_free(buffer, TRUE); | ||
| } | ||
| pcmk__xml_free(upgraded); | ||
| pcmk__xml_free(xml); | ||
| free(ns); | ||
| return 0; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-3.10"><configuration><crm_config/><nodes/><resources/><constraints/><acls><acl_role id="ro"><acl_permission id="p" kind="read" xpath="/cib"/></acl_role><acl_target id="t"><role id="ro"/></acl_target></acls></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-9.9"><configuration/><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib><configuration><resources><primitive id="a"><primitive id="a"/></primitive></resources></configuration></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <?xml version="1.0"?><!DOCTYPE cib [<!ENTITY e "x">]><cib>&e;</cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-3.10" epoch="1" num_updates="0" admin_epoch="0"><configuration><crm_config/><nodes/><resources/><constraints/></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib epoch="1"><configuration><crm_config/><nodes/><resources/><constraints/></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-1.2" epoch="1" num_updates="0" admin_epoch="0"><configuration><crm_config/><nodes><node id="1" uname="node1"/></nodes><resources/><constraints/></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-3.10"><configuration><crm_config><cluster_property_set id="cib-bootstrap-options"><nvpair id="p1" name="stonith-enabled" value="false"/></cluster_property_set></crm_config><nodes/><resources><primitive id="r1" class="ocf" provider="heartbeat" type="Dummy"><operations><op id="o1" name="monitor" interval="10s"/></operations><meta_attributes id="m1"><nvpair id="m1n" name="target-role" value="Started"/></meta_attributes></primitive></resources><constraints/></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib validate-with="pacemaker-3.10"><configuration><crm_config/><nodes/><resources/><constraints><rsc_location id="l1" rsc="r1"><rule id="ru1" score="100" boolean-op="and"><expression id="e1" attribute="#uname" operation="eq" value="node1"/><date_expression id="d1" operation="in_range" start="2026-01-01" end="2026-12-31"/></rule></rsc_location></constraints></configuration><status/></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib><status><node_state id="1"><lrm id="1"><lrm_resources><lrm_resource id="r1" type="Dummy" class="ocf"><lrm_rsc_op id="op1" operation="monitor" rc-code="0" call-id="1"/></lrm_resource></lrm_resources></lrm></node_state></status></cib> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <cib |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.