]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Limit oc_text_buf to 16MiB, start adding test cases
authorDavid Woodhouse <dwmw2@infradead.org>
Tue, 18 May 2021 17:27:58 +0000 (18:27 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Tue, 18 May 2021 17:27:58 +0000 (18:27 +0100)
We really ought to unit test this a lot harder. This is a start...

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
tests/Makefile.am
tests/buftest.c [new file with mode: 0644]
textbuf.c

index a975cc5c358cd2928b90d8f9eb1b451dbf4f31cf..9e06b5db414424959a25843e9c9b71fb8ca22c57 100644 (file)
@@ -143,7 +143,7 @@ TESTS_ENVIRONMENT = srcdir="$(srcdir)" \
        EXEEXT=$(EXEEXT) \
        LSAN_OPTIONS=suppressions=suppressions.lsan
 
-C_TESTS = lzstest seqtest
+C_TESTS = lzstest seqtest buftest
 
 if OPENCONNECT_WIN32
 C_TESTS += list-taps
diff --git a/tests/buftest.c b/tests/buftest.c
new file mode 100644 (file)
index 0000000..b3148ad
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * OpenConnect (SSL + DTLS) VPN client
+ *
+ * Copyright © 2021 David Woodhouse.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+
+#define __OPENCONNECT_INTERNAL_H__
+
+/* I always coded as if it worked like this. Now it does. */
+#define realloc_inplace(p, size) do {                  \
+       void *__realloc_old = p;                        \
+       p = realloc(p, size);                           \
+       if (size && !p)                                 \
+               free(__realloc_old);                    \
+    } while (0)
+
+struct oc_packed_uint32_t {
+       uint32_t d;
+} __attribute__((packed));
+struct oc_packed_uint16_t {
+       uint16_t d;
+} __attribute__((packed));
+
+static inline uint32_t load_be32(const void *_p)
+{
+       const struct oc_packed_uint32_t *p = _p;
+       return ntohl(p->d);
+}
+
+static inline uint16_t load_be16(const void *_p)
+{
+       const struct oc_packed_uint16_t *p = _p;
+       return ntohs(p->d);
+}
+
+static inline void store_be32(void *_p, uint32_t d)
+{
+       struct oc_packed_uint32_t *p = _p;
+       p->d = htonl(d);
+}
+
+static inline void store_be16(void *_p, uint16_t d)
+{
+       struct oc_packed_uint16_t *p = _p;
+       p->d = htons(d);
+}
+
+static inline uint32_t load_le32(const void *_p)
+{
+       const unsigned char *p = _p;
+       return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+static inline uint16_t load_le16(const void *_p)
+{
+       const unsigned char *p = _p;
+       return p[0] | (p[1] << 8);
+}
+
+static inline void store_le32(void *_p, uint32_t d)
+{
+       unsigned char *p = _p;
+       p[0] = d;
+       p[1] = d >> 8;
+}
+
+static inline void store_le16(void *_p, uint16_t d)
+{
+       unsigned char *p = _p;
+       p[0] = d;
+       p[1] = d >> 8;
+       p[2] = d >> 16;
+       p[3] = d >> 24;
+}
+
+struct oc_text_buf {
+       char *data;
+       int pos;
+       int buf_len;
+       int error;
+};
+
+#include "../textbuf.c"
+
+#define assert(x) if (!(x)) {                                          \
+       fprintf(stderr, "assert(%s) failed at line %d\n", #x, __LINE__); \
+       exit(1); }
+
+
+static char testbytes[OC_BUF_MAX];
+
+int main(void)
+{
+       struct oc_text_buf *buf = NULL;
+
+       assert(buf_error(buf) == -ENOMEM);
+
+       buf = buf_alloc();
+       assert(!buf_error(buf));
+
+       int len = (OC_BUF_MAX - 1) / 4 * 3;
+       buf_append_base64(buf, testbytes, len, 0);
+       assert(!buf_error(buf));
+       assert(buf->pos == OC_BUF_MAX - 4);
+
+       buf_truncate(buf);
+       len++;
+       buf_append_base64(buf, testbytes, len, 0);
+       assert(buf_error(buf) == -E2BIG);
+
+       buf->error = 0;
+       buf_append_base64(buf, testbytes, -1, 0);
+       assert(buf_error(buf) == -EINVAL);
+
+       return 0;
+}
index 129475e52bb7611abe0ed0e831b22735c494aa77..ed9e2e8ccbec93f20431e67e99bd9edd0a62da10 100644 (file)
--- a/textbuf.c
+++ b/textbuf.c
 #include <config.h>
 
 #include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+#include <arpa/inet.h>
 #include <stdarg.h>
 
 #include "openconnect-internal.h"
 
 #define BUF_CHUNK_SIZE 4096
+#define OC_BUF_MAX ((unsigned)(16*1024*1024))
 
 struct oc_text_buf *buf_alloc(void)
 {
@@ -42,6 +44,18 @@ int buf_error(struct oc_text_buf *buf)
        return buf ? buf->error : -ENOMEM;
 }
 
+
+void buf_truncate(struct oc_text_buf *buf)
+{
+       if (!buf)
+               return;
+
+       if (buf->data)
+               memset(buf->data, 0, buf->pos);
+
+       buf->pos = 0;
+}
+
 int buf_free(struct oc_text_buf *buf)
 {
        int error = buf_error(buf);
@@ -56,17 +70,6 @@ int buf_free(struct oc_text_buf *buf)
        return error;
 }
 
-void buf_truncate(struct oc_text_buf *buf)
-{
-       if (!buf)
-               return;
-
-       if (buf->data)
-               memset(buf->data, 0, buf->pos);
-
-       buf->pos = 0;
-}
-
 int buf_ensure_space(struct oc_text_buf *buf, int len)
 {
        unsigned int new_buf_len;
@@ -79,7 +82,7 @@ int buf_ensure_space(struct oc_text_buf *buf, int len)
        if (new_buf_len <= buf->buf_len)
                return 0;
 
-       if (new_buf_len > INT_MAX) {
+       if (new_buf_len > OC_BUF_MAX) {
                buf->error = -E2BIG;
                return buf->error;
        } else {
@@ -416,11 +419,16 @@ void buf_append_base64(struct oc_text_buf *buf, const void *bytes, int len,
        if (!buf || buf->error)
                return;
 
+       if (len < 0) {
+               buf->error = -EINVAL;
+               return;
+       }
+
        unsigned int needed = ((len + 2u) / 3) * 4 + 1;
        if (line_len)
                needed += needed / line_len;
 
-       if (needed >= (unsigned)(INT_MAX - buf->pos)) {
+       if (needed >= (unsigned)(OC_BUF_MAX - buf->pos)) {
                buf->error = -E2BIG;
                return;
        }