Skip to content

set_tls_verify_peer: use peer_info callback for relay cert verification - #591

Merged
millert merged 1 commit into
sudo-project:mainfrom
iefa-m:relay-tls-verify-peer-info
Nov 4, 2026
Merged

millert merged 1 commit into
sudo-project:mainfrom
iefa-m:relay-tls-verify-peer-info

Conversation

@iefa-m

@iefa-m iefa-m commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Heap overread in relay TLS certificate verification

set_tls_verify_peer() installs verify_peer_identity() on the relay SSL_CTX, but that callback reads a struct connection_closure from SSL ex_data slot 1. Relay connections store a struct peer_info there instead (tls_ctx_client_setup() sets it to &relay_closure->relay_name), so during the handshake verify_peer() reads ->name and ->ipaddr from past the end of the 248-byte relay_closure and hands the result to validate_hostname() in sudo_logsrvd. With tls_checkpeer set on the relay, any client connection that opens a relay connection reaches this path. Beyond the out-of-bounds read, the relay certificate's host check is then computed from adjacent heap rather than the configured relay name, so it fails closed on a zeroed heap and could misvalidate with groomed heap.

The relay wants the same peer_info-based check the sendlog client already does, so this exports that callback from tls_client.c as tls_verify_peer() and uses it for the relay context. The server accept path keeps verify_peer_identity(), which is where the connection_closure really lives.

Confirmed with AddressSanitizer: before the change a relayed log triggers a heap-buffer-overflow READ in verify_peer, 32 bytes past a 248-byte relay_closure; after it the handshake validates against the relay name and the log forwards.

The relay SSL_CTX was given verify_peer_identity(), which reads a
struct connection_closure from SSL ex_data slot 1.  Relay connections
store a struct peer_info there instead (tls_ctx_client_setup() sets it
to &relay_closure->relay_name), so verify_peer() read ->name and
->ipaddr past the end of the relay_closure and passed the result to
validate_hostname().  Use tls_client.c's peer_info-based callback,
now exported as tls_verify_peer(), for the relay context.

@millert millert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It would be nice to be able to use the same verify function in both cases, but embedding struct peer_info into struct connection_closure makes the code a bit ugly. This seems like the best solution for now.

@millert
millert merged commit 1633d11 into sudo-project:main Nov 4, 2026
5 checks passed
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