Skip to content

Commit

Permalink
Add proper test suite, add WIP daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnanastasio committed Feb 17, 2019
1 parent 897242c commit 953fc36
Show file tree
Hide file tree
Showing 10 changed files with 859 additions and 118 deletions.
36 changes: 29 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,48 @@
DEPS_SRC:=$(shell find . -name "*.c" -not -name "test.c")
DEPS:=$(DEPS_SRC:.c=.o)
DEPS:=library.o ringbuf.o
BIN:=libkvmchan.so
LIBS=-lrt -pthread

DAEMON_DEPS:=daemon/daemon.o daemon/libvirt.o daemon/util.o
DAEMON_BIN:=kvmchand
DAEMON_LIBS:=$(shell pkg-config --libs libvirt)

TEST_DEPS:=test.o
TEST_BIN:=test
TEST_LIBS:=$(shell pkg-config --cflags --libs check)

CFLAGS=-O2 -Wall -fpic -fvisibility=hidden -std=gnu99 -g -I. \
-fstack-protector-strong -D_FORITY_SOURCE=2 -fstack-clash-protection
LIBS=-lrt -pthread
-fstack-protector-strong -D_FORITY_SOURCE=2

COMPILER_NAME:=$(shell $(CC) --version |cut -d' ' -f1 |head -n1)
ifneq ($(COMPILER_NAME),clang)
# This flag is GCC-only
CFLAGS += -fstack-clash-protection
endif

.PHONY all: library test

.PHONY all: library daemon

library: $(DEPS)
$(CC) -shared $(CFLAGS) $(DEPS) -o $(BIN) $(LIBS)

%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<

test: $(DEPS) $(TEST_DEPS)
$(CC) $(CFLAGS) $(DEPS) $(TEST_DEPS) -o $(TEST_BIN) $(LIBS)
daemon: $(DAEMON_DEPS) $(DEPS)
$(CC) $(CFLAGS) $(DAEMON_DEPS) $(DEPS) -o $(DAEMON_BIN) $(LIBS) $(DAEMON_LIBS)

build_test: $(DEPS) $(TEST_DEPS)
$(CC) $(CFLAGS) $(DEPS) $(TEST_DEPS) -o $(TEST_BIN) $(LIBS) $(TEST_LIBS)

test: build_test
./$(TEST_BIN)

clean:
rm -f $(DEPS)
rm -f $(BIN)
rm -f $(DAEMON_DEPS)
rm -f $(DAEMON_BIN)
rm -f $(TEST_BIN)
rm -f $(TEST_DEPS)

print-% : ; @echo $* = $($*)
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ As of now, only blocking, packet-based communication is supported.

Overview
-----
libkvmchan uses a host/client architecture. Generally, the host is the KVM host system and the client is a virtual machine.
libkvmchan uses a host/client architecture. Generally, the host is the KVM host system and the client is a virtual machine, but other configurations work too.
Since libkvmchan uses `ivshmem`, all client machines must be configured with an `ivshmem` device in qemu/libvirt.
This is described in the [Looking Glass Project's Documentation](https://looking-glass.hostfission.com/quickstart/linux/libvirt).

Expand Down Expand Up @@ -88,6 +88,12 @@ worst case, a malicious process can only get a trusted process to overwrite exis
in the ring buffer and corrupt it. This should have no security consequences for the
trusted process, since it will never read from any ring buffer that it writes to.

Daemon
------
The included daemon is a WIP that will eventually allow automatic configuration of ivshmem shared memory channels
and libkvmchan ring buffers by accessing the host's libvirt configuration interface. This will allow users
to utilize libkvmchan without manually configuring the ivshmem devices attached to each VM, as well as
dynamic allocation of >2 ring buffers per ivshmem channel.

Why?
---
Expand Down
54 changes: 54 additions & 0 deletions daemon/daemon-priv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright 2018-2019 Shawn Anastasio
*
* This file is part of libkvmchan.
*
* libkvmchan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libkvmchan 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libkvmchan. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef KVMCHAN_DAEMON_PRIV_H
#define KVMCHAN_DAEMON_PRIV_H

#include <stdlib.h>
#include <stdbool.h>

enum log_level {
LOGL_INFO,
LOGL_WARN,
LOGL_ERROR
};

#ifdef __GNUC__
#define log(level, fmt, ...) log_impl(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#else
#define log(level, fmt, ...) log_impl(level, __FILE__, __LINE__, __VA_ARGS__)
#endif

struct vec {
void **data;
size_t size;
size_t count;
void (*destructor)(void *);
};

void log_impl(enum log_level level, const char *file, int line, const char *fmt, ...);

bool vec_init(struct vec *v, size_t initial_size, void (*destructor)(void *));
bool vec_push_back(struct vec *v, void *element);
void *vec_at(struct vec *v, size_t i);
void vec_remove(struct vec *v, size_t i);

int run_libvirt_loop(const char *);

#endif // KVMCHAN_DAEMON_PRIV_H
106 changes: 106 additions & 0 deletions daemon/daemon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Copyright 2018-2019 Shawn Anastasio
*
* This file is part of libkvmchan.
*
* libkvmchan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libkvmchan 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libkvmchan. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* This daemon interfaces with libvirt and allows VMs
* to query and create vchans which they can't do by
* themselves
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <assert.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "daemon-priv.h"

// TODO: Support proper authentication and different libvirt hosts
#define LIBVIRT_HOST_URI "qemu:///system"

void daemonize() {
// Fork to background
pid_t child = fork();
if (child < 0) {
log(LOGL_ERROR, "Failed to fork to background!");
exit(EXIT_FAILURE);
} else if (child > 0) {
// Child forked successfully, parent can exit
exit(EXIT_SUCCESS);
}

// Change the file mode mask
umask(0);

// Create a new session
pid_t sid = setsid();
if (sid < 0) {
log(LOGL_ERROR, "Failed to set sid!");
exit(EXIT_FAILURE);
}

// Chdir to /
if (chdir("/") < 0) {
log(LOGL_ERROR, "Failed to chdir!");
exit(EXIT_FAILURE);
}

// Lastly, close all STDIO file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}

void show_help(const char *progname) {
fprintf(stderr, "Usage: %s [-h|-d]\n", progname);
}

int main(int argc, char **argv) {
bool daemon = false;
int opt;
while ((opt = getopt(argc, argv, "hd")) != -1) {
switch(opt) {
case 'h':
show_help(argv[0]);
return EXIT_SUCCESS;

case 'd':
daemon = true;
break;

default:
fprintf(stderr, "Unknown argument!\n");
show_help(argv[0]);
return EXIT_FAILURE;
}
}


// Daemonize if requested
if (daemon)
daemonize();

return run_libvirt_loop(LIBVIRT_HOST_URI);
}
Loading

0 comments on commit 953fc36

Please sign in to comment.