Skip to content

CVE-2026-14612: ipa-otpd/oauth2: fix memory safety and error handling…#8473

Open
abbra wants to merge 1 commit into
freeipa:masterfrom
abbra:CVE-2026-14612
Open

CVE-2026-14612: ipa-otpd/oauth2: fix memory safety and error handling…#8473
abbra wants to merge 1 commit into
freeipa:masterfrom
abbra:CVE-2026-14612

Conversation

@abbra

@abbra abbra commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

… bugs

Fix several pre-existing bugs in the OAuth2 device code flow:

  • Use-after-free: otpd_queue_item_free() was called before the retry check in oauth2_on_child_writable(). On EAGAIN, the freed saved_item would be dereferenced on the next callback invocation.

  • CVE-2026-14612: buffer overflow: read() into a 10240-byte buffer could return exactly 10240 bytes, causing buf[10240]='\0' to write past the end. Use sizeof(buf)-1 instead.

  • Memory leaks: saved_item was leaked on strndup failure and on child_ctx allocation failure. The done: label now cleans up saved_item, pipe fds, and child_ctx on error paths.

  • NULL dereference: ipaidpSub was dereferenced without a NULL check in check_access_token_reply().

  • verto_add_child() return was not checked for NULL, leading to a NULL dereference on verto_set_private().

  • set_fd_nonblocking() return values were silently ignored; a failure would leave pipes in blocking mode, hanging the daemon.

  • Off-by-one in memchr length calculation for second newline.

  • Avoid logging full oidc_child output (may contain tokens); log byte count instead.

  • Fix error message for reader event (was copy-pasted as "writer").

  • Fix uninitialized loop variable in disabled debug block.

Fixes: CVE-2026-14612

Summary by Sourcery

Harden the OAuth2 device code flow in ipa-otpd by fixing memory safety issues, improving error handling, and tightening child process I/O handling and logging.

Bug Fixes:

  • Prevent a use-after-free when retrying writes to the oauth2 child by only freeing the saved queue item after I/O completes.
  • Fix a potential buffer overflow and off-by-one error when reading and parsing the oauth2 child output buffer.
  • Avoid NULL dereferences by validating ipaidpSub and verto child event allocations before use.
  • Eliminate memory leaks on failures when allocating saved state or child context structures and when setting up pipes.
  • Handle zero-length reads and failures from set_fd_nonblocking to avoid hangs and undefined behavior in the daemon.
  • Correct an incorrect reader event error message and initialize a previously uninitialized loop variable in debug-only code.

Enhancements:

  • Stop logging the full oidc_child output and instead log only the byte count to avoid exposing sensitive tokens.
  • Ensure file descriptors and ownership (between parent and verto) are consistently tracked and closed on all error paths to improve robustness.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@abbra abbra added the re-run Trigger a new run of PR-CI label Jul 3, 2026
@freeipa-pr-ci freeipa-pr-ci removed the re-run Trigger a new run of PR-CI label Jul 3, 2026

@rjeffman rjeffman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall, looks good to me, but I have just one question before ack-ing.

Comment thread daemons/ipa-otpd/oauth2.c
@abbra
abbra force-pushed the CVE-2026-14612 branch from 4436b21 to 01401cb Compare July 3, 2026 19:50
Comment thread daemons/ipa-otpd/oauth2.c
… bugs

Fix several pre-existing bugs in the OAuth2 device code flow:

- Use-after-free: otpd_queue_item_free() was called before the retry
  check in oauth2_on_child_writable(). On EAGAIN, the freed saved_item
  would be dereferenced on the next callback invocation.

- CVE-2026-14612: buffer overflow: read() into a 10240-byte buffer could
  return exactly 10240 bytes, causing buf[10240]='\0' to write past the
  end. Use sizeof(buf)-1 instead.

- Memory leaks: saved_item was leaked on strndup failure and on
  child_ctx allocation failure. The done: label now cleans up
  saved_item, pipe fds, and child_ctx on error paths.

- NULL dereference: ipaidpSub was dereferenced without a NULL check in
  check_access_token_reply().

- verto_add_child() return was not checked for NULL, leading to a NULL
  dereference on verto_set_private().

- set_fd_nonblocking() return values were silently ignored; a failure
  would leave pipes in blocking mode, hanging the daemon.

- Off-by-one in memchr length calculation for second newline.

- Avoid logging full oidc_child output (may contain tokens); log byte
  count instead.

- Fix error message for reader event (was copy-pasted as "writer").

- Fix uninitialized loop variable in disabled debug block.

Fixes: CVE-2026-14612
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
@abbra
abbra force-pushed the CVE-2026-14612 branch from 01401cb to d777cf8 Compare July 7, 2026 05:42

@rjeffman rjeffman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@abbra one last comment, but I'm not really sure it would happen.

I might be just asking something so that I understand this better, not a real issue.

Comment thread daemons/ipa-otpd/oauth2.c
Comment on lines +588 to +589
kill(child_pid, SIGKILL);
waitpid(child_pid, NULL, 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the only place where kill+waitpid is used in the new code before goto done;. Shouldn't the kill+waitpid idiom be used before goto done for every exit path after creating the child fork to prevent zombies?

(Playing by rusted memory here - pun intended - as I haven't fork-ed anything in many, many years.)

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.

4 participants