XCCDF/OVAL/CPE/DS: fix NULL-pointer dereferences on malformed input#2361
XCCDF/OVAL/CPE/DS: fix NULL-pointer dereferences on malformed input#2361edznux-dd wants to merge 2 commits into
Conversation
Missing XML attributes/namespaces/text make libxml return NULL, which was then passed to strcmp/atoi/atof or dereferenced. Guard these and make the shared string helpers NULL-tolerant. - common/util.h: oscap_str_startswith()/oscap_str_endswith() return false on a NULL string (matching oscap_strcmp/oscap_streq). - OVAL: guard the optional `version` attribute before atoi() in oval_state, oval_definition, oval_object, oval_variable, oval_resultDefinition; guard the `reported` attribute (oval_directives); guard a NULL frame from a duplicate variable id (oval_varModel). - XCCDF: NULL-safe atof() for empty lower/upper-bound and score elements (value.c, result.c); reject a NULL <TestResult> (benchmark.c); skip a <platform> with no @idref before strlen() (item.c); reject a NULL profile in tailoring (tailoring.c). - DS: NULL-safe id comparisons in sds_index / rds; reject a component with no id as a hash key (ds_rds_session.c).
Mab879
left a comment
There was a problem hiding this comment.
First of all, thank you for this series of PRs.
Please consider adding regression tests.
|
|
||
| int ret = 1; | ||
|
|
||
| if (s == NULL) |
There was a problem hiding this comment.
Shouldn't this be placed before line 457?
| val = _xccdf_value_find_or_create_instance(XVALUE(value), selector, type); | ||
| val->lower_bound = atof(oscap_element_string_get(reader)); | ||
| const char *lb = oscap_element_string_get(reader); | ||
| val->lower_bound = lb ? atof(lb) : 0.0; |
There was a problem hiding this comment.
Defaulting 0.0 might not be right thing here. Something like below might be better.
if (lb == NULL) {
dW("Empty <lower-bound> element is invalid, rejecting <Value>.");
xccdf_value_free(value);
return NULL;
}
val = _xccdf_value_find_or_create_instance(XVALUE(value), selector, type);
val->lower_bound = atof(lb);There was a problem hiding this comment.
Yea, I wasn't sure if it was preferable to default or to fail. sounds good to me :)
Applied your suggestion in 906022e as well
| val = _xccdf_value_find_or_create_instance(XVALUE(value), selector, type); | ||
| val->upper_bound = atof(oscap_element_string_get(reader)); | ||
| const char *ub = oscap_element_string_get(reader); | ||
| val->upper_bound = ub ? atof(ub) : 0.0; |
There was a problem hiding this comment.
Same as lower bound. Something like
const char *ub = oscap_element_string_get(reader);
if (ub == NULL) {
dW("Empty <upper-bound> element is invalid, rejecting <Value>.");
xccdf_value_free(value);
return NULL;
}
val = _xccdf_value_find_or_create_instance(XVALUE(value), selector, type);
val->upper_bound = atof(ub);| else score->maximum = XCCDF_SCORE_MAX_DAFAULT; | ||
| score->score = atof(oscap_element_string_get(reader)); | ||
| const char *score_str = oscap_element_string_get(reader); | ||
| score->score = score_str ? atof(score_str) : 0.0; |
There was a problem hiding this comment.
Something like might be better here.
if (score_str == NULL) {
dW("Empty <score> element is invalid, rejecting.");
xccdf_score_free(score);
return NULL;
}
score->score = atof(score_str);
|



Hey :)
I was looking at some of our logs and noticed that
openscapwas crashing on memory corruption issues, so I decided to dig a bit into it and write some fuzz test (I didn't have the exact source of the crashes).This is the 1st of 4 fix PR (+ one for the fuzz test), that I tried to split into manageable diff.
(There will be one PR that contains the fuzz-harnesses that I used. They are not comprehensive for all the code path
This current PR mostly ensure that all references are guarded by null checks.
Notes:
For some context on this specific PR:
versionattribute before atoi() in oval_state, oval_definition, oval_object, oval_variable, oval_resultDefinition; guard thereportedattribute (oval_directives); guard a NULL frame from a duplicate variable id (oval_varModel).