Skip to content

Comments

Fix buffer overflow, resource leaks, missing error checks and possible use of uninitialized variables#563

Open
aaronmerey wants to merge 10 commits intoicl-utk-edu:masterfrom
aaronmerey:master
Open

Fix buffer overflow, resource leaks, missing error checks and possible use of uninitialized variables#563
aaronmerey wants to merge 10 commits intoicl-utk-edu:masterfrom
aaronmerey:master

Conversation

@aaronmerey
Copy link

Pull Request Description

Patch series to fix buffer overflow, resource leaks, missing error checks and possible use of uninitialized variables

papi_load_derived_events and papi_load_derived_events_component might
pass string literal "papi_events.csv" to open_event_table using the
PAPI_EVENT_FILE alias.

In this case, open_event_table may attempt to call sprintf where
PAPI_EVENT_FILE alias is both the destination buffer and the source
string for the format argument.

This is undefined behaviour in two ways: (1) The destination buffer
for sprintf cannot also be used as a source for a format argument.
(2) String literals are read-only and should not be modified.

Fix this by copying PAPI_EVENT_FILE to a modifiable local buffer for
use in papi_load_derived_events and papi_load_derived_events_component.
In exp_container_insert_element, variable chunk is set to the number
of chunks already allocated in exp_container.  chunk is set to a number
between 0 and EXP_CONTAINER_ENTRIES - 1.

If used_entries == total_entries, chunk is incremented by 1 and used
as an index into exp_container->ptr_array.  This array has size
EXP_CONTAINER_ENTRIES.  This results in an overrun if chunk is equal
to EXP_CONTAINER_ENTRIES after the increment.

Fix this by returning SDE_EINVAL if chunk >= EXP_CONTAINER_ENTRIES.
Check pread return value for -1 and handle error case.
Fix error cases in generateEventList that return early without calling
closedir on DIR* variables dir and d.
Ensure variables allNames, allPMID and allFetch are freed for all early
returns for error cases.
Ensure localname is freed before early return for error case.
Ensure malloc, calloc and strdup return values are checked for errors
and free all allocated resources when an error is encountered.
Ensure variable evt_name_copy is freed if returning early due to error.
Initialize variables with a default value to avoid warnings regarding
possible uninitialized use in static analyzer tools such as coverity.
@Treece-Burgess
Copy link
Contributor

@aaronmerey Thank you for submitting this PR. I will take a look through it.

@Treece-Burgess Treece-Burgess self-requested a review February 18, 2026 00:05
if (event_fd == -1) { break; }

int sz = pread(event_fd, read_buff, PAPI_MAX_STR_LEN, 0);
if (sz == -1) { HANDLE_STRING_ERROR; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting here for HANDLE_STRING_ERROR is different from the rest below. I did not an counter any error if the formatting here mimics the formatting below. Can you change the formatting here to be like below or vice versa?

}

if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
err = PAPI_ECMP;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert_in_list can also return PAPI_ENOMEM. Can you change this check such that you set err equal to insert_in_list and then if a failure does occur you can jump to done_error?

}

if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
err = PAPI_ECMP;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

}

if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
err = PAPI_ECMP;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

fn_exit:
free(allNames); // Locals allocations not needed anymore.
free(allPMID); // .. the pmIDs we read.
pcp_pmFreeResult(allFetch); // .. release the results we fetched.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From documentation:

As a general rule, if the called function returns an error status, then no allocation is done, the pointer to the variable sized result is undefined, and free, pmFreeLabelSets, or pmFreeResult should not be called.


Therefore, before calling pcp_pmFreeResult we need to check:

if (all_fetch != NULL) {
    pcp_pmFreeResult(allFetch); 
}


for (k = 0; k < prstPtr->num_quals; k++){
providedQuals[k] = (char*)malloc(sizeof(char)*(PAPI_MAX_STR_LEN+1));
PAPIERROR("Could not allocate %lu bytes of memory for providedQuals element.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The allocation for providedQuals[k] needs to be checked if it is equal to NULL and then you subsequently have the PAPIERROR, ret = PAPI_ENOMEM, and goto done.

for (k = 0; k < numProvidedQuals; k++) {
wholeQual1 = strdup(providedQuals[k]);
if (wholeQual1 == NULL) {
PAPIERROR("Failed to make copy of qualifier %s", providedQuals[k]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this PAPIERROR message more descriptive? Same as the two that follow for the qualifiers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants