aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-01-04 14:46:27 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-01-04 15:07:10 +0100
commit1d2d6200b8ff517db0f7530645180df3cc4afa74 (patch)
treed8369e0b9211ec3c93d044cfb323e363bdd6029b
parentMakefile: add standard 'all' target (diff)
downloadwireguard-tools-1d2d6200b8ff517db0f7530645180df3cc4afa74.tar.xz
wireguard-tools-1d2d6200b8ff517db0f7530645180df3cc4afa74.zip
ipc: simplify inflatable buffer and add fuzzer
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--src/fuzz/Makefile9
-rw-r--r--src/fuzz/config.c2
-rw-r--r--src/fuzz/stringlist.c59
-rw-r--r--src/fuzz/uapi.c2
-rw-r--r--src/ipc.c102
5 files changed, 109 insertions, 65 deletions
diff --git a/src/fuzz/Makefile b/src/fuzz/Makefile
index 98a16dd..3fb2970 100644
--- a/src/fuzz/Makefile
+++ b/src/fuzz/Makefile
@@ -2,10 +2,10 @@
#
# Copyright (C) 2018-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
-all: config uapi
+all: config uapi stringlist
CFLAGS ?= -O3 -march=native -g
-CFLAGS += -fsanitize=fuzzer -std=gnu11 -idirafter ../uapi
+CFLAGS += -fsanitize=fuzzer -fsanitize=address -std=gnu11 -idirafter ../uapi
CC := clang
config: config.c ../config.c ../encoding.c
@@ -14,7 +14,10 @@ config: config.c ../config.c ../encoding.c
uapi: uapi.c ../ipc.c ../curve25519.c ../encoding.c
$(CC) $(CFLAGS) -o $@ $<
+stringlist: stringlist.c ../ipc.c ../curve25519.c ../encoding.c
+ $(CC) $(CFLAGS) -o $@ $<
+
clean:
- rm -f config uapi
+ rm -f config uapi stringlist
.PHONY: all clean
diff --git a/src/fuzz/config.c b/src/fuzz/config.c
index 49c87b4..5812b4c 100644
--- a/src/fuzz/config.c
+++ b/src/fuzz/config.c
@@ -18,7 +18,7 @@
const char *__asan_default_options()
{
- return "verbosity=1";
+ return "verbosity=1";
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t len)
diff --git a/src/fuzz/stringlist.c b/src/fuzz/stringlist.c
new file mode 100644
index 0000000..85f7330
--- /dev/null
+++ b/src/fuzz/stringlist.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#define RUNSTATEDIR "/var/empty"
+#undef __linux__
+#include "../ipc.c"
+#include "../curve25519.c"
+#include "../encoding.c"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+const char *__asan_default_options()
+{
+ return "verbosity=1";
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t data_len)
+{
+ struct string_list list = { 0 };
+ char *interfaces;
+
+ if (!data_len)
+ return 0;
+
+ interfaces = malloc(data_len);
+ assert(interfaces);
+ memcpy(interfaces, data, data_len);
+ interfaces[data_len - 1] = '\0';
+
+ for (char *interface = interfaces; interface - interfaces < data_len; interface += strlen(interface) + 1)
+ assert(string_list_add(&list, interface) == 0);
+
+ for (char *interface = interfaces, *interface2 = list.buffer;;) {
+ size_t len;
+
+ if (interface - interfaces >= data_len) {
+ assert(!interface2 || !strlen(interface2));
+ break;
+ }
+ len = strlen(interface);
+ if (!len) {
+ ++interface;
+ continue;
+ }
+ assert(strlen(interface2) == len);
+ assert(!memcmp(interface, interface2, len + 1));
+ interface += len + 1;
+ interface2 += len + 1;
+ }
+ free(list.buffer);
+ free(interfaces);
+ return 0;
+}
diff --git a/src/fuzz/uapi.c b/src/fuzz/uapi.c
index 90b2ba6..a387125 100644
--- a/src/fuzz/uapi.c
+++ b/src/fuzz/uapi.c
@@ -20,7 +20,7 @@ static FILE *hacked_userspace_interface_file(const char *iface);
const char *__asan_default_options()
{
- return "verbosity=1";
+ return "verbosity=1";
}
union hackiface {
diff --git a/src/ipc.c b/src/ipc.c
index 9833b33..1110670 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -48,50 +48,34 @@
#define SOCKET_BUFFER_SIZE 8192
#endif
-struct inflatable_buffer {
+struct string_list {
char *buffer;
- char *next;
- bool good;
size_t len;
- size_t pos;
+ size_t cap;
};
-#define max(a, b) ((a) > (b) ? (a) : (b))
-static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
+static int string_list_add(struct string_list *list, const char *str)
{
- size_t len, expand_to;
- char *new_buffer;
+ size_t len = strlen(str) + 1;
- if (!buffer->good || !buffer->next) {
- free(buffer->next);
- buffer->good = false;
+ if (len == 1)
return 0;
- }
-
- len = strlen(buffer->next) + 1;
- if (len == 1) {
- free(buffer->next);
- buffer->good = false;
- return 0;
- }
+ if (len >= list->cap - list->len) {
+ char *new_buffer;
+ size_t new_cap = list->cap * 2;
- if (buffer->len - buffer->pos <= len) {
- expand_to = max(buffer->len * 2, buffer->len + len + 1);
- new_buffer = realloc(buffer->buffer, expand_to);
- if (!new_buffer) {
- free(buffer->next);
- buffer->good = false;
+ if (new_cap < list->len +len + 1)
+ new_cap = list->len + len + 1;
+ new_buffer = realloc(list->buffer, new_cap);
+ if (!new_buffer)
return -errno;
- }
- memset(&new_buffer[buffer->len], 0, expand_to - buffer->len);
- buffer->buffer = new_buffer;
- buffer->len = expand_to;
- }
- memcpy(&buffer->buffer[buffer->pos], buffer->next, len);
- free(buffer->next);
- buffer->good = false;
- buffer->pos += len;
+ list->buffer = new_buffer;
+ list->cap = new_cap;
+ }
+ memcpy(list->buffer + list->len, str, len);
+ list->len += len;
+ list->buffer[list->len] = '\0';
return 0;
}
@@ -167,7 +151,7 @@ static bool userspace_has_wireguard_interface(const char *iface)
return true;
}
-static int userspace_get_wireguard_interfaces(struct inflatable_buffer *buffer)
+static int userspace_get_wireguard_interfaces(struct string_list *list)
{
DIR *dir;
struct dirent *ent;
@@ -188,9 +172,7 @@ static int userspace_get_wireguard_interfaces(struct inflatable_buffer *buffer)
*end = '\0';
if (!userspace_has_wireguard_interface(ent->d_name))
continue;
- buffer->next = strdup(ent->d_name);
- buffer->good = true;
- ret = add_next_to_inflatable_buffer(buffer);
+ ret = string_list_add(list, ent->d_name);
if (ret < 0)
goto out;
}
@@ -451,37 +433,42 @@ err:
#ifdef __linux__
+struct interface {
+ const char *name;
+ bool is_wireguard;
+};
+
static int parse_linkinfo(const struct nlattr *attr, void *data)
{
- struct inflatable_buffer *buffer = data;
+ struct interface *interface = data;
- if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp("wireguard", mnl_attr_get_str(attr)))
- buffer->good = true;
+ if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
+ interface->is_wireguard = true;
return MNL_CB_OK;
}
static int parse_infomsg(const struct nlattr *attr, void *data)
{
- struct inflatable_buffer *buffer = data;
+ struct interface *interface = data;
if (mnl_attr_get_type(attr) == IFLA_LINKINFO)
return mnl_attr_parse_nested(attr, parse_linkinfo, data);
else if (mnl_attr_get_type(attr) == IFLA_IFNAME)
- buffer->next = strdup(mnl_attr_get_str(attr));
+ interface->name = mnl_attr_get_str(attr);
return MNL_CB_OK;
}
static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
{
- struct inflatable_buffer *buffer = data;
+ struct string_list *list = data;
+ struct interface interface = { 0 };
int ret;
- buffer->good = false;
- buffer->next = NULL;
- ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, data);
+ ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, &interface);
if (ret != MNL_CB_OK)
return ret;
- ret = add_next_to_inflatable_buffer(buffer);
+ if (interface.name && interface.is_wireguard)
+ ret = string_list_add(list, interface.name);
if (ret < 0)
return ret;
if (nlh->nlmsg_type != NLMSG_DONE)
@@ -489,7 +476,7 @@ static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int kernel_get_wireguard_interfaces(struct inflatable_buffer *buffer)
+static int kernel_get_wireguard_interfaces(struct string_list *list)
{
struct mnl_socket *nl = NULL;
char *rtnl_buffer = NULL;
@@ -536,7 +523,7 @@ another:
ret = -errno;
goto cleanup;
}
- if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, buffer)) < 0) {
+ if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0) {
/* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
* during the dump. That's unfortunate, but is pretty common on busy
* systems that are adding and removing tunnels all the time. Rather
@@ -940,30 +927,25 @@ out:
/* first\0second\0third\0forth\0last\0\0 */
char *ipc_list_devices(void)
{
- struct inflatable_buffer buffer = { .len = SOCKET_BUFFER_SIZE };
+ struct string_list list = { 0 };
int ret;
- ret = -ENOMEM;
- buffer.buffer = calloc(1, buffer.len);
- if (!buffer.buffer)
- goto cleanup;
-
#ifdef __linux__
- ret = kernel_get_wireguard_interfaces(&buffer);
+ ret = kernel_get_wireguard_interfaces(&list);
if (ret < 0)
goto cleanup;
#endif
- ret = userspace_get_wireguard_interfaces(&buffer);
+ ret = userspace_get_wireguard_interfaces(&list);
if (ret < 0)
goto cleanup;
cleanup:
errno = -ret;
if (errno) {
- free(buffer.buffer);
+ free(list.buffer);
return NULL;
}
- return buffer.buffer;
+ return list.buffer ?: strdup("\0");
}
int ipc_get_device(struct wgdevice **dev, const char *iface)