Skip to content

Commit

Permalink
Merge pull request #18 from trailofbits/kernel-abstraction
Browse files Browse the repository at this point in the history
Freebsd integration
  • Loading branch information
hmwildermuth authored Jun 17, 2019
2 parents c3b2c49 + fb65ae6 commit 82990c2
Show file tree
Hide file tree
Showing 188 changed files with 823 additions and 427 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
*.gen.h
*.gen.c
*.cmd
*~
krfexec
krfctl
*.bak
example/*
21 changes: 17 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ export CFLAGS := -std=gnu99 -Wall -Werror -pedantic

ALL_SRCS := $(shell find . -type f \( -name '*.c' -o -name '*.h' \) )

# OS detection - manually can be controlled by `make PLATFORM=FreeBSD` or whatever
PLATFORM := $(shell uname -s)

all: module krfexec krfctl example

.PHONY: module
module:
$(MAKE) -C src/module
ifeq ($(PLATFORM),Linux)
$(MAKE) -C src/module/linux
endif
ifeq ($(PLATFORM),FreeBSD)
$(MAKE) -C src/module/freebsd
endif

.PHONY: krfexec
krfexec:
Expand All @@ -18,19 +26,24 @@ krfctl:

.PHONY: insmod
insmod:
$(MAKE) -C src/module insmod
$(MAKE) -C src/module/linux insmod

.PHONY: rmmod
rmmod:
$(MAKE) -C src/module rmmod
$(MAKE) -C src/module/linux rmmod

.PHONY: example
example:
$(MAKE) -C example

.PHONY: clean
clean:
$(MAKE) -C src/module clean
ifeq ($(PLATFORM),Linux)
$(MAKE) -C src/module/linux clean
endif
ifeq ($(PLATFORM),FreeBSD)
$(MAKE) -C src/module/freebsd clean
endif
$(MAKE) -C src/krfexec clean
$(MAKE) -C src/krfctl clean
$(MAKE) -C example clean
Expand Down
3 changes: 3 additions & 0 deletions src/krfctl/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
PROG := krfctl

# OS detection - manually can be controlled by `make PLATFORM=FreeBSD` or whatever
PLATFORM := $(shell uname -s)

all: gentable $(PROG)

.PHONY: gentable
Expand Down
2 changes: 1 addition & 1 deletion src/krfctl/genprofiles
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

require "yaml"

SYSCALL_SPECS_DIR = File.expand_path "../module/codegen/syscalls", __dir__
SYSCALL_SPECS_DIR = File.expand_path "../module/linux/codegen/syscalls", __dir__
SYSCALL_SPECS = Dir[File.join(SYSCALL_SPECS_DIR, "*.yml")]

SYSCALLS = SYSCALL_SPECS.map do |path|
Expand Down
46 changes: 30 additions & 16 deletions src/module/codegen/codegen
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@

require "yaml"

PLATFORM = ARGV.shift || 'linux'
TYPEOF = (PLATFORM == "freebsd") ? "__typeof" : "typeof"
SYSCALL_RET_TYPE = (PLATFORM == "freebsd") ? "int" : "long"
PRINT = (PLATFORM == "freebsd") ? "uprintf" : "printk"
FAULT_PREFIX = (PLATFORM == "freebsd") ? "" : "-"
HEADER = <<~HEADER
/* WARNING!
* This file was generated by KRF's codegen.
* Do not edit it by hand.
*/
HEADER

SYSCALL_SPECS = Dir[File.join(__dir__, "syscalls", "*.yml")]
SYSCALL_SPECS = Dir[File.join(__dir__, PLATFORM, "*.yml")]

SYSCALLS = SYSCALL_SPECS.map do |path|
spec = YAML.safe_load File.read(path)
[File.basename(path, ".yml"), spec]
end.to_h

SOURCE_DIR = File.expand_path "..", __dir__
SOURCE_DIR = File.expand_path "../#{PLATFORM}", __dir__

def hai(msg)
STDERR.puts "[codegen] #{msg}"
Expand All @@ -45,20 +50,28 @@ SYSCALLS.each do |call, spec|
# 3. syscalls.gen.x, to set up the initial wrapper
# 4. syscalls/internal.gen.h, to prototype the internal wrapper
# 5. syscalls/<syscall>.gen.c, to set up the actual faulty calls

nr = spec["nr"] || call
number = (PLATFORM == "freebsd") ? "SYS_#{nr}" : "__NR_#{nr}"

hai "#{call} (nr: #{number})"
if PLATFORM == 'freebsd'
gen_files[:krf_x].puts <<~KRF_X
krf_faultable_table[#{number}].sy_call = (sy_call_t *)&krf_sys_#{call};
KRF_X
else
gen_files[:krf_x].puts <<~KRF_X
krf_faultable_table[#{number}] = (void *)&krf_sys_#{call};
KRF_X
end

hai "#{call} (nr: __NR_#{nr})"

gen_files[:krf_x].puts <<~KRF_X
krf_faultable_table[__NR_#{nr}] = (void *)&krf_sys_#{call};
KRF_X

syscall_insert = (PLATFORM == "freebsd") ? "(#{TYPEOF}(sys_#{call}) *)krf_sys_call_table[#{number}].sy_call" : "(void *)krf_sys_call_table[#{number}]"

gen_files[:syscalls_x].puts <<~SYSCALLS_X
long KRF_DEFINE(#{call})(#{spec["proto"]}) {
typeof(sys_#{call}) *real_#{call} = (void *)krf_sys_call_table[__NR_#{nr}];
#{SYSCALL_RET_TYPE} KRF_DEFINE(#{call})(#{spec["proto"]}) {
#{TYPEOF}(sys_#{call}) *real_#{call} = #{syscall_insert};
if (krf_targeted() && (KRF_RNG_NEXT() % krf_probability) == 0) {
if (krf_targeted(KRF_TARGETING_PARMS) && (KRF_RNG_NEXT() % krf_probability) == 0) {
return KRF_SYS_INTERNAL(#{call})(#{spec["parms"]});
} else {
return real_#{call}(#{spec["parms"]});
Expand Down Expand Up @@ -92,21 +105,22 @@ SYSCALLS.each do |call, spec|
file.puts <<~FAULT
DEFINE_FAULT(#{fault}) {
if (krf_log_faults) {
printk("faulting #{call} with #{fault}\\n");
#{PRINT}("faulting #{call} with #{fault}\\n");
}
return -#{fault};
return #{FAULT_PREFIX}#{fault};
}
FAULT
end


file.puts <<~TRAILER
static typeof(sys_#{call})(*fault_table[]) = {
static #{TYPEOF}(sys_#{call})(*fault_table[]) = {
#{fault_table.join ", "}
};
// Fault entrypoint.
long KRF_DEFINE_INTERNAL(#{call})(KRF_SYS_PARMS) {
#{SYSCALL_RET_TYPE} KRF_DEFINE_INTERNAL(#{call})(KRF_SYS_PARMS) {
return fault_table[KRF_RNG_NEXT() % NFAULTS](KRF_SYS_PARMSX);
}
TRAILER
Expand Down
16 changes: 16 additions & 0 deletions src/module/codegen/freebsd/accept.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
proto: struct thread *td, struct accept_args *uap
parms: td, uap
errors:
- EBADF
- EINTR
- EMFILE
- ENFILE
- ENOTSOCK
- EINVAL
- EFAULT
- EWOULDBLOCK
- EAGAIN
- ECONNABORTED
profiles:
- net

15 changes: 15 additions & 0 deletions src/module/codegen/freebsd/read.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
proto: struct thread *td, struct read_args *uap
parms: td, uap
errors:
- ECONNRESET
- EFAULT
- EIO
- EBUSY
- EINTR
- EINVAL
- EAGAIN
- EISDIR
- EOPNOTSUPP
- EOVERFLOW
profiles:
- io
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions src/module/freebsd/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SYSCALL_C_FILES!=ls syscalls/*.gen.c
SRCS=krf.c syscalls.c ../config.c ../krf.c ${SYSCALL_C_FILES}
KMOD=krf

.include <bsd.kmod.mk>
20 changes: 20 additions & 0 deletions src/module/freebsd/Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

# -*- mode: ruby; -*-

# Force Virtualbox for those people who have installed vagrant-lxc (e.g.)
#ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

Vagrant.configure("2") do |config|
config.vm.guest = :freebsd
config.vm.network "private_network", ip: "10.0.1.10"

# Use NFS as a shared folder
# config.vm.synced_folder ".", "/vagrant", type: "nfs", id: "vagrant-root"
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
# Set to a shell that actually exists
config.ssh.shell = 'sh'

config.vm.box = "freebsd/FreeBSD-12.0-CURRENT"


end
15 changes: 15 additions & 0 deletions src/module/freebsd/freebsd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
// FreeBSD specific definitions
#include "syscalls.h"

#define KRF_SAFE_WRITE(x) x // ???
#define KRF_LOG(...) uprintf(__VA_ARGS__)
#define KRF_SYSCALL_TABLE sysent
#define KRF_TARGETING_PROTO struct thread *td
#define KRF_TARGETING_PARMS td
#define KRF_PERSONALITY() (td->td_proc->p_flag2)
#define KRF_PID() (td->td_proc->p_pid)
#define KRF_UID() \
(td->td_proc->p_ucred->cr_ruid) // Currently using real UID but could use effective UID (cr_uid)
#define KRF_GID() (td->td_proc->p_ucred->cr_rgid)
#define KRF_EXTRACT_SYSCALL(x) ((x).sy_call)
120 changes: 120 additions & 0 deletions src/module/freebsd/krf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/sysproto.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/conf.h>

#include <sys/syscall.h>

#include "../config.h"
#include "../krf.h"
#include "syscalls.h"

static struct sysctl_ctx_list clist;
static struct sysctl_oid *krf_sysctl_root;
static unsigned int krf_control;
static char krf_targetings[13];

static int control_file_sysctl(SYSCTL_HANDLER_ARGS) {
int syscall = -1;
int err = 0;

if (sysctl_handle_int(oidp, &syscall, 0, req)) {
return -1;
} else if (req->newptr) {
err = control_file_handler(syscall);
if (err < 0)
return -err;
} else {
// read request?
}
return err;
}

static int targeting_file_sysctl(SYSCTL_HANDLER_ARGS) {
int err = 0;
krf_target_mode_t mode;
unsigned int data;

err = sysctl_handle_string(oidp, &krf_targetings, 13, req);
if (err) {
return -err;
} else if (req->newptr) {
if (sscanf(krf_targetings, "%u %u", &mode, &data) != 2) {
return EINVAL;
}
if (targeting_file_write_handler(mode, data) < 0) {
return EINVAL;
}
} else {
// read request?
}
return err;
}

static int krf_init() {
int err = 0;
sysctl_ctx_init(&clist);
if (!(krf_sysctl_root =
SYSCTL_ADD_ROOT_NODE(&clist, OID_AUTO, "krf", CTLFLAG_RW, 0, "krf sysctl root node"))) {
uprintf("krf error: Failed to add root sysctl node.\n");
return -1;
}

memset(krf_faultable_table, 0, KRF_NR_SYSCALLS * sizeof(struct sysent));
memcpy(krf_sys_call_table, sysent, KRF_NR_SYSCALLS * sizeof(struct sysent));

SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_PROBABILITY_FILENAME,
CTLFLAG_RW, &krf_probability, krf_probability,
"Reciprocal of the probability of a fault");
SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_RNG_STATE_FILENAME,
CTLFLAG_RW, &krf_rng_state, krf_rng_state, "Sets the current RNG state");
SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_LOG_FAULTS_FILENAME,
CTLFLAG_RW, &krf_log_faults, krf_log_faults, "Toggle logging faults to syslog");
SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_CONTROL_FILENAME,
CTLTYPE_UINT | CTLFLAG_WR, &krf_control, krf_control, control_file_sysctl, "IU",
"Enables specific syscall faults");
SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_TARGETING_FILENAME,
CTLTYPE_STRING | CTLFLAG_WR, &krf_targetings, 13, targeting_file_sysctl, "A",
"Enables specific targeting options");
return err;
}

static int krf_teardown() {
krf_flush_table();
sysctl_remove_oid(krf_sysctl_root, 1, 0);
sysctl_ctx_free(&clist);
return 0;
}

static int krf_loader(struct module *m, int what, void *arg) {
int err = 0;
switch (what) {
case MOD_LOAD:
err = krf_init();
if (err != 0)
uprintf("krf_init failed with %d\n", err);

#include "krf.gen.x"

uprintf("krf: loaded\n");
break;
case MOD_UNLOAD:
krf_teardown();
uprintf("krf: unloaded\n");
break;
default:
err = EOPNOTSUPP;
break;
}
return (err);
}

static moduledata_t krf_mod = {"krf", krf_loader, NULL};

DECLARE_MODULE(krf, krf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
19 changes: 19 additions & 0 deletions src/module/freebsd/syscalls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/sysproto.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include "syscalls.h"
#include "syscalls/internal.h"
#include "../targeting.h"
#include "freebsd.h"

struct sysent krf_faultable_table[KRF_MAX_SYSCALL] = {};
struct sysent krf_sys_call_table[KRF_MAX_SYSCALL] = {};

#include "syscalls.gen.x"
Loading

0 comments on commit 82990c2

Please sign in to comment.