Skip to content

options: fix heap-use-after-free in ioengine_so_path#2070

Merged
axboe merged 1 commit into
axboe:masterfrom
msuozzo:push-lnvrzuqpnylp
Mar 10, 2026
Merged

options: fix heap-use-after-free in ioengine_so_path#2070
axboe merged 1 commit into
axboe:masterfrom
msuozzo:push-lnvrzuqpnylp

Conversation

@msuozzo
Copy link
Copy Markdown
Contributor

@msuozzo msuozzo commented Mar 9, 2026

When parsing ioengine=external:/path, td->o.ioengine_so_path was
previously assigned as a pointer directly into the td->o.ioengine
string buffer. If td->o.ioengine was subsequently reallocated (e.g.,
due to multiple ioengine definitions or the use of include directives),
ioengine_so_path became a dangling pointer, resulting in a
heap-use-after-free during dlopen_ioengine.

Fix this by ensuring ioengine_so_path owns its own memory allocation
independent of the ioengine string. Since this field is not defined
as a standard option entry, manual lifecycle management is implemented:

  1. str_ioengine_external_cb: Use strdup to store the path and
    free any previously allocated string.
  2. fio_options_mem_dupe: Explicitly duplicate the string when
    copying thread options.
  3. fio_options_free: Explicitly free the string when tearing down
    thread options.

This approach resolves the UAF while avoiding adding a new option entry.

@axboe
Copy link
Copy Markdown
Owner

axboe commented Mar 10, 2026

Looks good to me, running it through the CI now. You need to add a Signed-off-by to the commit message though, see other commits in the tree.

When parsing `ioengine=external:/path`, `td->o.ioengine_so_path` was
previously assigned as a pointer directly into the `td->o.ioengine`
string buffer. If `td->o.ioengine` was subsequently reallocated (e.g.,
due to multiple ioengine definitions or the use of include directives),
`ioengine_so_path` became a dangling pointer, resulting in a
heap-use-after-free during `dlopen_ioengine`.

Fix this by ensuring `ioengine_so_path` owns its own memory allocation
independent of the `ioengine` string. Since this field is not defined
as a standard option entry, manual lifecycle management is implemented:

1.  **str_ioengine_external_cb**: Use `strdup` to store the path and
    free any previously allocated string.
2.  **fio_options_mem_dupe**: Explicitly duplicate the string when
    copying thread options.
3.  **fio_options_free**: Explicitly free the string when tearing down
    thread options.

This approach resolves the UAF while adhering to the requirement of not
adding a new option entry to the parser. Verified with ASan and existing
test suites.

Signed-off-by: Matthew Suozzo <[email protected]>
@msuozzo msuozzo force-pushed the push-lnvrzuqpnylp branch from b2d7e9e to 7aeef09 Compare March 10, 2026 02:00
@msuozzo
Copy link
Copy Markdown
Contributor Author

msuozzo commented Mar 10, 2026

Thanks! Added the signed off trailer.

@axboe axboe merged commit fa23c09 into axboe:master Mar 10, 2026
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