From patchwork Wed Apr 1 14:11:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 457263 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 34B3C1400A0 for ; Thu, 2 Apr 2015 01:12:59 +1100 (AEDT) Received: from localhost ([::1]:52885 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YdJO5-00041Q-3U for incoming@patchwork.ozlabs.org; Wed, 01 Apr 2015 10:12:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50701) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YdJMh-0001qE-UJ for qemu-devel@nongnu.org; Wed, 01 Apr 2015 10:11:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YdJMd-0002CQ-UW for qemu-devel@nongnu.org; Wed, 01 Apr 2015 10:11:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43334) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YdJMd-0002C9-Pa for qemu-devel@nongnu.org; Wed, 01 Apr 2015 10:11:27 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 736F08F032 for ; Wed, 1 Apr 2015 14:11:27 +0000 (UTC) Received: from nilsson.home.kraxel.org (ovpn-116-62.ams2.redhat.com [10.36.116.62]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t31EBQlf006736; Wed, 1 Apr 2015 10:11:26 -0400 Received: by nilsson.home.kraxel.org (Postfix, from userid 500) id D995080F99; Wed, 1 Apr 2015 16:11:24 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Wed, 1 Apr 2015 16:11:15 +0200 Message-Id: <1427897475-26983-3-git-send-email-kraxel@redhat.com> In-Reply-To: <1427897475-26983-1-git-send-email-kraxel@redhat.com> References: <1427897475-26983-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Gerd Hoffmann Subject: [Qemu-devel] [PULL 2/2] CVE-2015-1779: limit size of HTTP headers from websockets clients X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "Daniel P. Berrange" The VNC server websockets decoder will read and buffer data from websockets clients until it sees the end of the HTTP headers, as indicated by \r\n\r\n. In theory this allows a malicious to trick QEMU into consuming an arbitrary amount of RAM. In practice, because QEMU runs g_strstr_len() across the buffered header data, it will spend increasingly long burning CPU time searching for the substring match and less & less time reading data. So while this does cause arbitrary memory growth, the bigger problem is that QEMU will be burning 100% of available CPU time. A novnc websockets client typically sends headers of around 512 bytes in length. As such it is reasonable to place a 4096 byte limit on the amount of data buffered while searching for the end of HTTP headers. Signed-off-by: Daniel P. Berrange Signed-off-by: Gerd Hoffmann --- ui/vnc-ws.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 0b7de4e..62eb97f 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -81,8 +81,11 @@ void vncws_handshake_read(void *opaque) VncState *vs = opaque; uint8_t *handshake_end; long ret; - buffer_reserve(&vs->ws_input, 4096); - ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); + /* Typical HTTP headers from novnc are 512 bytes, so limiting + * total header size to 4096 is easily enough. */ + size_t want = 4096 - vs->ws_input.offset; + buffer_reserve(&vs->ws_input, want); + ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want); if (!ret) { if (vs->csock == -1) { @@ -99,6 +102,9 @@ void vncws_handshake_read(void *opaque) vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + strlen(WS_HANDSHAKE_END)); + } else if (vs->ws_input.offset >= 4096) { + VNC_DEBUG("End of headers not found in first 4096 bytes\n"); + vnc_client_error(vs); } }