Skip to content

Commit

Permalink
vnc: track & limit connections
Browse files Browse the repository at this point in the history
Also track the number of connections in "connecting" and "shared" state
(in addition to the "exclusive" state).  Apply a configurable limit to
these connections.

The logic to apply the limit to connections in "shared" state is pretty
simple:  When the limit is reached no new connections are allowed.

The logic to apply the limit to connections in "connecting" state (this
is the state you are in *before* successful authentication) is
slightly different:  A new connect kicks out the oldest client which is
still in "connecting" state.  This avoids a easy DoS by unauthenticated
users by simply opening connections until the limit is reached.

Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
  • Loading branch information
kraxel committed Jan 22, 2015
1 parent 86fdcf2 commit e5f34cd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
46 changes: 43 additions & 3 deletions ui/vnc.c
Expand Up @@ -68,12 +68,34 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
vs->csock, mn[vs->share_mode], mn[mode]);
#endif

if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
switch (vs->share_mode) {
case VNC_SHARE_MODE_CONNECTING:
vs->vd->num_connecting--;
break;
case VNC_SHARE_MODE_SHARED:
vs->vd->num_shared--;
break;
case VNC_SHARE_MODE_EXCLUSIVE:
vs->vd->num_exclusive--;
break;
default:
break;
}

vs->share_mode = mode;
if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {

switch (vs->share_mode) {
case VNC_SHARE_MODE_CONNECTING:
vs->vd->num_connecting++;
break;
case VNC_SHARE_MODE_SHARED:
vs->vd->num_shared++;
break;
case VNC_SHARE_MODE_EXCLUSIVE:
vs->vd->num_exclusive++;
break;
default:
break;
}
}

Expand Down Expand Up @@ -2337,6 +2359,11 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
}
vnc_set_share_mode(vs, mode);

if (vs->vd->num_shared > vs->vd->connections_limit) {
vnc_disconnect_start(vs);
return 0;
}

vs->client_width = pixman_image_get_width(vs->vd->server);
vs->client_height = pixman_image_get_height(vs->vd->server);
vnc_write_u16(vs, vs->client_width);
Expand Down Expand Up @@ -2889,6 +2916,15 @@ static void vnc_connect(VncDisplay *vd, int csock,
{
vnc_init_state(vs);
}

if (vd->num_connecting > vd->connections_limit) {
QTAILQ_FOREACH(vs, &vd->clients, next) {
if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
vnc_disconnect_start(vs);
return;
}
}
}
}

void vnc_init_state(VncState *vs)
Expand All @@ -2907,7 +2943,7 @@ void vnc_init_state(VncState *vs)
qemu_mutex_init(&vs->output_mutex);
vs->bh = qemu_bh_new(vnc_jobs_bh, vs);

QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
QTAILQ_INSERT_TAIL(&vd->clients, vs, next);

graphic_hw_update(vd->dcl.con);

Expand Down Expand Up @@ -3097,6 +3133,9 @@ static QemuOptsList qemu_vnc_opts = {
},{
.name = "head",
.type = QEMU_OPT_NUMBER,
},{
.name = "connections",
.type = QEMU_OPT_NUMBER,
},{
.name = "password",
.type = QEMU_OPT_BOOL,
Expand Down Expand Up @@ -3211,6 +3250,7 @@ void vnc_display_open(const char *id, Error **errp)
} else {
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
}
vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);

#ifdef CONFIG_VNC_WS
websocket = qemu_opt_get(opts, "websocket");
Expand Down
3 changes: 3 additions & 0 deletions ui/vnc.h
Expand Up @@ -150,7 +150,10 @@ typedef enum VncSharePolicy {
struct VncDisplay
{
QTAILQ_HEAD(, VncState) clients;
int num_connecting;
int num_shared;
int num_exclusive;
int connections_limit;
VncSharePolicy share_policy;
int lsock;
#ifdef CONFIG_VNC_WS
Expand Down

0 comments on commit e5f34cd

Please sign in to comment.