fuzzer: add varlink fuzzer

This commit is contained in:
Lennart Poettering 2019-04-11 18:42:37 +02:00
parent 635d059fa5
commit d768467563
9 changed files with 136 additions and 0 deletions

131
src/fuzz/fuzz-varlink.c Normal file
View File

@ -0,0 +1,131 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <unistd.h>
#include "errno-util.h"
#include "fd-util.h"
#include "fuzz.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "varlink.h"
#include "log.h"
static FILE *null = NULL;
static int method_something(Varlink *v, JsonVariant *p, VarlinkMethodFlags flags, void *userdata) {
json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
return 0;
}
static int reply_callback(Varlink *v, JsonVariant *p, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
return 0;
}
static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
struct iovec *iov = userdata;
bool write_eof = false, read_eof = false;
assert(s);
assert(fd >= 0);
assert(iov);
if ((revents & (EPOLLOUT|EPOLLHUP|EPOLLERR)) && iov->iov_len > 0) {
ssize_t n;
/* never write more than 143 bytes a time, to make broken up recv()s on the other side more
* likely, and thus test some additional code paths. */
n = send(fd, iov->iov_base, MIN(iov->iov_len, 143U), MSG_NOSIGNAL|MSG_DONTWAIT);
if (n < 0) {
if (ERRNO_IS_DISCONNECT(errno))
write_eof = true;
else
assert_se(errno == EAGAIN);
} else
IOVEC_INCREMENT(iov, 1, n);
}
if (revents & EPOLLIN) {
char c[137];
ssize_t n;
n = recv(fd, c, sizeof(c), MSG_DONTWAIT);
if (n < 0) {
if (ERRNO_IS_DISCONNECT(errno))
read_eof = true;
else
assert_se(errno == EAGAIN);
} else if (n == 0)
read_eof = true;
else
hexdump(null, c, (size_t) n);
}
/* After we wrote everything we could turn off EPOLLOUT. And if we reached read EOF too turn off the
* whole thing. */
if (write_eof || iov->iov_len == 0) {
if (read_eof)
assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
else
assert_se(sd_event_source_set_io_events(s, EPOLLIN) >= 0);
}
return 0;
}
static int idle_callback(sd_event_source *s, void *userdata) {
assert(s);
/* Called as idle callback when there's nothing else to do anymore */
sd_event_exit(sd_event_source_get_event(s), 0);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct iovec server_iov = IOVEC_MAKE((void*) data, size), client_iov = IOVEC_MAKE((void*) data, size);
/* Important: the declaration order matters here! we want that the fds are closed on return after the
* event sources, hence we declare the fds first, the event sources second */
_cleanup_close_pair_ int server_pair[2] = { -1, -1 }, client_pair[2] = { -1, -1 };
_cleanup_(sd_event_source_unrefp) sd_event_source *idle_event_source = NULL,
*server_event_source = NULL, *client_event_source = NULL;
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
_cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
log_set_max_level(LOG_CRIT);
log_parse_environment();
assert_se(null = fopen("/dev/null", "we"));
assert_se(sd_event_default(&e) >= 0);
/* Test one: write the data as method call to a server */
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, server_pair) >= 0);
assert_se(varlink_server_new(&s, 0) >= 0);
assert_se(varlink_server_set_description(s, "myserver") >= 0);
assert_se(varlink_server_attach_event(s, e, 0) >= 0);
assert_se(varlink_server_add_connection(s, server_pair[0], NULL) >= 0);
TAKE_FD(server_pair[0]);
assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0);
assert_se(sd_event_add_io(e, &server_event_source, server_pair[1], EPOLLIN|EPOLLOUT, io_callback, &server_iov) >= 0);
/* Test two: write the data as method response to a client */
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, client_pair) >= 0);
assert_se(varlink_connect_fd(&c, client_pair[0]) >= 0);
TAKE_FD(client_pair[0]);
assert_se(varlink_set_description(c, "myclient") >= 0);
assert_se(varlink_attach_event(c, e, 0) >= 0);
assert_se(varlink_bind_reply(c, reply_callback) >= 0);
assert_se(varlink_invoke(c, "io.test.DoSomething", NULL) >= 0);
assert_se(sd_event_add_io(e, &client_event_source, client_pair[1], EPOLLIN|EPOLLOUT, io_callback, &client_iov) >= 0);
assert_se(sd_event_add_defer(e, &idle_event_source, idle_callback, NULL) >= 0);
assert_se(sd_event_source_set_priority(idle_event_source, SD_EVENT_PRIORITY_IDLE) >= 0);
assert_se(sd_event_loop(e) >= 0);
null = safe_fclose(null);
return 0;
}

View File

@ -51,6 +51,10 @@ fuzzers += [
[libshared],
[]],
[['src/fuzz/fuzz-varlink.c'],
[libshared],
[]],
[['src/fuzz/fuzz-unit-file.c'],
[libcore,
libshared],

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.