Skip to content

GUACAMOLE-306: Guard against NULL client in VNC size handler - #706

Open
denkovrov wants to merge 1 commit into
apache:mainfrom
denkovrov:guacamole-306-vnc-size-null-guard
Open

GUACAMOLE-306: Guard against NULL client in VNC size handler#706
denkovrov wants to merge 1 commit into
apache:mainfrom
denkovrov:guacamole-306-vnc-size-null-guard

Conversation

@denkovrov

Copy link
Copy Markdown

Summary

guac_vnc_user_size_handler() in src/protocols/vnc/input.c passes vnc_client->rfb_client directly into guac_vnc_display_set_size() (src/protocols/vnc/display.c), which dereferences it immediately via rfbClientGetClientData(). If the Guacamole "size" instruction (sent by the client as soon as the canvas opens) arrives before the VNC handshake completes and rfb_client is set, this is a NULL pointer dereference and crashes guacd.

This is the same class of bug as GUACAMOLE-306 ("VNC may segfault during the connection process"), which was fixed for the mouse and keyboard handlers in the same file (input.c) — both already guard on rfb_client != NULL before use. The auto-resize handler was added later by GUACAMOLE-1196 and appears to have missed the same guard.

Reproduction

Hit under load testing: opening many concurrent VNC connections measurably slows down handshake completion (creating the rfbClient), widening the window during which an already-open browser tab's "size" instruction can race ahead of it. Under normal single-connection use the window is small enough to be rare to nonexistent; under concurrent connection load it reproduced reliably (segfault visible in kernel logs, consistent fault address/offset every time).

A gdb thread apply all bt full backtrace on a core dump traced the fault into guac_vnc_display_set_size(), which is what led to this fix. I don't have that raw backtrace text on hand to attach to this PR, but wanted to flag it exists in case a maintainer would find it useful for confirming - happy to try to reproduce and re-capture it if that would help review.

The fix itself has been validated by re-running the same concurrent-connection load test against a build with this patch applied: zero segfaults, versus a reliable reproduction on the same test without it.

Fix

Adds a NULL check at the top of guac_vnc_display_set_size() rather than only in the size handler, since that function is the single choke point both of its callers go through. The other caller, guac_vnc_display_set_owner_size() (used for the initial post-handshake resize), always passes an already-valid client, so the added check is a no-op on that path and doesn't change existing behavior there.

Notes

  • Self-service registration on issues.apache.org (JIRA) appears to be closed, so I wasn't able to file a new ticket for this - this PR references GUACAMOLE-306 as the precedent for the same bug class already being fixed for the sibling handlers. Happy to have a committer file a proper follow-up ticket if that's preferred, or point me at the right way to request a JIRA account.
  • Verified the two touched functions are unchanged between the 1.6.0 tag and current main, so this applies cleanly to either.

guac_vnc_user_size_handler() passes vnc_client->rfb_client directly into
guac_vnc_display_set_size(), which dereferences it immediately via
rfbClientGetClientData(). If the Guacamole "size" instruction arrives
from the client before the VNC handshake completes and rfb_client is
set, this is a NULL dereference.

This is the same race already fixed by GUACAMOLE-306 for the mouse and
keyboard handlers in the same file (input.c), both of which guard on
rfb_client != NULL before use - just missed for this newer auto-resize
handler, added later by GUACAMOLE-1196.

Reproduced under load from many concurrent VNC connections opening at
once, which measurably slows down handshake completion and makes the
race far more likely to be hit (rare to nonexistent under normal
single-connection use). Confirmed via gdb backtrace on a core dump,
consistently faulting inside guac_vnc_display_set_size() at the same
offset.

The check is placed in guac_vnc_display_set_size() itself rather than
only in guac_vnc_user_size_handler(), since it is the single choke
point both of its callers go through; the other caller
(guac_vnc_display_set_owner_size(), used for the initial post-handshake
resize) always passes an already-valid client, so the added check is a
no-op on that path.
@necouchman

Copy link
Copy Markdown
Contributor

@denkovrov The GUACAMOLE-306 issue was marked as fixed several years ago and closed (it was fixed in version 0.9.13-incubating). You will need to open a new Jira issue for this and update the tagging appropriately.

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