[Spice-devel] [PATCH spice-server 03/30] Terminate HTTP header

Frediano Ziglio fziglio at redhat.com
Mon Nov 21 12:51:50 UTC 2016


Allow to use standard string functions and prevent some
possible overflow (like the use of strchr).
---
 server/reds-stream.c |  7 ++++---
 server/websocket.c   | 39 +++++++++++++++++----------------------
 server/websocket.h   |  4 ++--
 3 files changed, 23 insertions(+), 27 deletions(-)

diff --git a/server/reds-stream.c b/server/reds-stream.c
index 4327e57..b59586b 100644
--- a/server/reds-stream.c
+++ b/server/reds-stream.c
@@ -1202,10 +1202,11 @@ bool reds_stream_is_websocket(RedsStream *stream, unsigned char *buf, int len)
     }
 
     memcpy(rbuf, buf, len);
-    rc = stream->priv->read(stream, rbuf + len, sizeof(rbuf) - len);
+    rc = stream->priv->read(stream, rbuf + len, sizeof(rbuf) - len - 1);
     if (rc <= 0)
         return FALSE;
     len += rc;
+    rbuf[len] = 0;
 
     /* TODO:  this has a theoretical flaw around packet buffering
               that is not likely to occur in practice.  That is,
@@ -1223,10 +1224,10 @@ bool reds_stream_is_websocket(RedsStream *stream, unsigned char *buf, int len)
               so it seems wisest to live with this theoretical flaw.
     */
 
-    if (websocket_is_start(rbuf, len)) {
+    if (websocket_is_start(rbuf)) {
         char outbuf[1024];
 
-        websocket_create_reply(rbuf, len, outbuf);
+        websocket_create_reply(rbuf, outbuf);
         rc = stream->priv->write(stream, outbuf, strlen(outbuf));
         if (rc == strlen(outbuf)) {
             stream->priv->ws = spice_malloc0(sizeof(*stream->priv->ws));
diff --git a/server/websocket.c b/server/websocket.c
index 6dbf354..cfd93a0 100644
--- a/server/websocket.c
+++ b/server/websocket.c
@@ -15,6 +15,7 @@
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -55,16 +56,12 @@
 /* Perform a case insenstive search for needle in haystack.
    If found, return a pointer to the byte after the end of needle.
    Otherwise, return NULL */
-static gchar *find_str(gchar *haystack, const char *needle, int n)
+static gchar *find_str(gchar *haystack, const char *needle)
 {
-    int i;
-
-    for (i = 0; i < n; i++) {
-        if ((n - i) < strlen(needle))
-            break;
+    char *s = strcasestr(haystack, needle);
 
-        if (g_ascii_strncasecmp(haystack + i, needle, strlen(needle)) == 0)
-            return haystack + i + strlen(needle);
+    if (s) {
+        return s + strlen(needle);
     }
     return NULL;
 }
@@ -74,7 +71,7 @@ static gchar *find_str(gchar *haystack, const char *needle, int n)
    required to extract the length; useful for tracking where the
    mask will be.
 */
-static guint64 extract_length(guint8 *buf, int *used)
+static guint64 extract_length(const guint8 *buf, int *used)
 {
     int i;
     guint64 outlen = (*buf++) & LENGTH_MASK;
@@ -127,7 +124,7 @@ static int frame_bytes_needed(websocket_frame_t *frame)
 *  original key sent to us
 * If non null, caller must free returned key string.
 */
-static gchar *generate_reply_key(gchar *buf, int len)
+static gchar *generate_reply_key(gchar *buf)
 {
     GChecksum *checksum = NULL;
     gchar *b64 = NULL;
@@ -137,10 +134,10 @@ static gchar *generate_reply_key(gchar *buf, int len)
     gchar *p;
     gchar *k;
 
-    key = find_str(buf, "Sec-WebSocket-Key:", len);
+    key = find_str(buf, "\nSec-WebSocket-Key:");
     if (key) {
         p = strchr(key, '\r');
-        if (p && p - buf < len) {
+        if (p) {
             k = g_strndup(key, p - key);
             k = g_strstrip(k);
             checksum = g_checksum_new(G_CHECKSUM_SHA1);
@@ -432,25 +429,23 @@ void websocket_ack_close(void *opaque, websocket_write_cb_t write_cb)
     write_cb(opaque, header, sizeof(header));
 }
 
-bool websocket_is_start(gchar *buf, int len)
+bool websocket_is_start(gchar *buf)
 {
-    if (len < 4)
-        return FALSE;
-
-    if (find_str(buf, "GET", len) == (buf + 3) &&
-            find_str(buf, "Sec-WebSocket-Protocol: binary", len) &&
-            find_str(buf, "Sec-WebSocket-Key:", len) &&
-            buf[len - 2] == '\r' && buf[len - 1] == '\n')
+    if (strncmp(buf, "GET ", 4) == 0 &&
+            // TODO strip, do not assume a single space
+            find_str(buf, "\nSec-WebSocket-Protocol: binary") &&
+            find_str(buf, "\nSec-WebSocket-Key:") &&
+            g_str_has_suffix(buf, "\r\n"))
         return TRUE;
 
     return FALSE;
 }
 
-void websocket_create_reply(gchar *buf, int len, gchar *outbuf)
+void websocket_create_reply(gchar *buf, gchar *outbuf)
 {
     gchar *key;
 
-    key = generate_reply_key(buf, len);
+    key = generate_reply_key(buf);
     sprintf(outbuf, "HTTP/1.1 101 Switching Protocols\r\n"
                     "Upgrade: websocket\r\n"
                     "Connection: Upgrade\r\n"
diff --git a/server/websocket.h b/server/websocket.h
index 3561279..02aacc1 100644
--- a/server/websocket.h
+++ b/server/websocket.h
@@ -33,8 +33,8 @@ typedef ssize_t (*websocket_read_cb_t)(void *opaque, const void *buf, size_t nby
 typedef ssize_t (*websocket_write_cb_t)(void *opaque, const void *buf, size_t nbyte);
 typedef ssize_t (*websocket_writev_cb_t)(void *opaque, struct iovec *iov, int iovcnt);
 
-bool websocket_is_start(gchar *buf, int len);
-void websocket_create_reply(gchar *buf, int len, gchar *outbuf);
+bool websocket_is_start(gchar *buf);
+void websocket_create_reply(gchar *buf, gchar *outbuf);
 int websocket_read(void *opaque, guchar *buf, int len, websocket_frame_t *frame,
          websocket_read_cb_t read_cb,
          websocket_write_cb_t write_cb);
-- 
2.7.4



More information about the Spice-devel mailing list