├── debian ├── compat ├── picon-pass.docs ├── source │ └── format ├── picon-monitor.install ├── picon-pass.install ├── changelog ├── README.Debian ├── rules ├── copyright └── control ├── .gitignore ├── llvm_pass ├── CFI │ ├── CMakeLists.txt │ ├── DebugPrintRT.hh │ ├── Debug.hh │ ├── CFIModulePass.hh │ ├── CFIInjector.hh │ ├── DebugPrintRT.cpp │ ├── CFIModulePass.cpp │ ├── CFI.hh │ ├── CFIInjector.cpp │ └── CFI.cpp ├── Makefile └── CMakeLists.txt ├── examples ├── shared_libs │ ├── src │ │ ├── file2.c │ │ ├── libmylib3.c │ │ ├── main_prog.c │ │ ├── libmylib2.c │ │ └── libmylib1.c │ ├── Makefile │ ├── Makefile.no_cfi │ ├── Makefile.common │ └── Makefile.cfi ├── unit_tests │ ├── src │ │ ├── test_init.c │ │ ├── test_sleep.c │ │ ├── test_rop_asm.c │ │ ├── test_indirect_call.c │ │ ├── test_rop.c │ │ ├── test_fork.c │ │ └── test_no_basic_blocks.c │ ├── Makefile.no_cfi │ ├── Makefile.common │ ├── Makefile │ └── Makefile.cfi └── Makefile ├── include └── picon │ ├── picon.h │ ├── log.h │ ├── injected_code.c │ └── shared.h ├── prelink ├── Makefile └── picon-prelink ├── Makefile ├── monitor ├── include │ ├── monitor_dot.h │ ├── monitor_run.h │ ├── call_stack.h │ ├── defs.h │ ├── block_stack.h │ └── monitor_load.h ├── Makefile └── src │ ├── defs.c │ ├── monitor_dot.c │ ├── block_stack.c │ ├── call_stack.c │ ├── main.c │ ├── monitor_run.c │ └── monitor_load.c ├── README.md └── COPYING /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/picon-pass.docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/picon-monitor.install: -------------------------------------------------------------------------------- 1 | usr/bin/picon-monitor 2 | -------------------------------------------------------------------------------- /debian/picon-pass.install: -------------------------------------------------------------------------------- 1 | usr/bin/picon-prelink 2 | usr/include 3 | usr/lib 4 | usr/share/doc/picon/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | examples/unit_tests/build.cfi 2 | examples/unit_tests/build.no_cfi 3 | build 4 | .*.swp 5 | *~ 6 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(CFI 2 | MODULE 3 | CFI.cpp 4 | CFIInjector.cpp 5 | CFIModulePass.cpp) 6 | -------------------------------------------------------------------------------- /examples/shared_libs/src/file2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int file2_fct1(void) 4 | { 5 | printf("%s\n", __FUNCTION__); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /examples/shared_libs/src/libmylib3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int mylib3_fct1(void) 4 | { 5 | printf("%s\n", __FUNCTION__); 6 | return 0; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /include/picon/picon.h: -------------------------------------------------------------------------------- 1 | #ifndef __PICON_H__ 2 | #define __PICON_H__ 3 | 4 | #define CFI_IGNORE_BASIC_BLOCKS __attribute__((annotate("cfi_ignore_blocks"))) 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | picon (1.0-1) unstable; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Arnaud Fontaine Wed, 29 Jul 2015 15:20:22 +0200 6 | -------------------------------------------------------------------------------- /examples/shared_libs/src/main_prog.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int mylib1_fct1(void); 4 | 5 | int main(void) 6 | { 7 | puts("Hello, world!"); 8 | 9 | mylib1_fct1(); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples/shared_libs/src/libmylib2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int mylib3_fct1(void); 4 | 5 | int mylib2_fct1(void) 6 | { 7 | printf("%s\n", __FUNCTION__); 8 | mylib3_fct1(); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((constructor)) 4 | void xinit() { 5 | printf("constructor\n"); 6 | } 7 | 8 | int main() { 9 | printf("main\n"); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /prelink/Makefile: -------------------------------------------------------------------------------- 1 | all: picon-prelink 2 | 3 | clean: 4 | 5 | install: 6 | $(INSTALL) -m 0755 -d $(DESTDIR)/usr/bin ; \ 7 | $(INSTALL) -m 0755 picon-prelink $(DESTDIR)/usr/bin/ 8 | 9 | 10 | .PHONY: all clean install 11 | -------------------------------------------------------------------------------- /examples/unit_tests/Makefile.no_cfi: -------------------------------------------------------------------------------- 1 | BUILDDIR:=build.no_cfi 2 | 3 | include Makefile.common 4 | 5 | 6 | ############## 7 | 8 | 9 | 10 | $(BUILDDIR)/%.o: $(SRCDIR)/%.c $(BUILDDIR) 11 | $(CC) $(CFLAGS) -c -o $@ $< 12 | 13 | $(BUILDDIR)/%: $(BUILDDIR)/%.o 14 | $(LD) $(LDFLAGS) -o $@ $< 15 | 16 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SLEEP_DURATION_SECONDS 2 5 | 6 | 7 | int main() { 8 | 9 | printf("entering sleep for %u seconds\n", SLEEP_DURATION_SECONDS); 10 | 11 | sleep(SLEEP_DURATION_SECONDS); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_rop_asm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void fun_should_not_be_called() { 5 | printf("fun_should_not_be_called\n"); 6 | } 7 | 8 | void fun() { 9 | printf("fun called\n"); 10 | 11 | __asm__ ("mov %%rbp,%%rsp; pop %%rbp; push %0; retq;" : : "i"(fun_should_not_be_called)); 12 | } 13 | 14 | int main() { 15 | 16 | fun(); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_indirect_call.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | void fun1(const int x) { 6 | printf("fun1 : %u\n", x); 7 | } 8 | 9 | void fun2(const int x) { 10 | printf("fun2 : %u\n", x); 11 | } 12 | 13 | int main() { 14 | void (*fun)(int); 15 | 16 | if(random()%2) { 17 | fun = fun1; 18 | } else { 19 | fun = fun2; 20 | } 21 | 22 | fun(10); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_rop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void fun_should_not_be_called() { 6 | printf("fun_should_not_be_called\n"); 7 | exit(1); 8 | } 9 | 10 | void fun() { 11 | void (*fun)(void) = fun_should_not_be_called; 12 | 13 | printf("fun called\n"); 14 | 15 | *(&fun + 2) = fun_should_not_be_called; 16 | } 17 | 18 | int main() { 19 | 20 | fun(); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() { 6 | pid_t child_pid; 7 | 8 | switch((child_pid = fork())) { 9 | case -1: 10 | fprintf(stderr, "failed to fork"); 11 | return 1; 12 | 13 | case 0: 14 | /* child */ 15 | printf("child\n"); 16 | break; 17 | 18 | default: 19 | /* parent */ 20 | printf("parent\n"); 21 | break; 22 | } 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /llvm_pass/Makefile: -------------------------------------------------------------------------------- 1 | BUILDDIR:=build 2 | 3 | MKDIR?=mkdir 4 | CMAKE?=cmake 5 | 6 | PWD:=$(CURDIR) 7 | 8 | all: 9 | $(MKDIR) -p $(BUILDDIR) ; \ 10 | cd $(BUILDDIR) && $(CMAKE) -D LLVM_CONFIG=$(LLVM_CONFIG) $(PWD) && $(MAKE) 11 | 12 | clean: 13 | $(RM) -r $(BUILDDIR) 14 | 15 | install: 16 | $(INSTALL) -m 0755 -d $(DESTDIR)/usr/lib/picon/ ; \ 17 | $(INSTALL) -m 0644 $(BUILDDIR)/CFI/libCFI.so $(DESTDIR)/usr/lib/picon/ 18 | 19 | 20 | .PHONY: all clean install 21 | -------------------------------------------------------------------------------- /examples/shared_libs/src/libmylib1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int mylib2_fct1(void); 4 | 5 | static void __attribute__((constructor)) mylib1_init(void) 6 | { 7 | printf("Init function %s\n", __FUNCTION__); 8 | } 9 | 10 | int mylib1_fct1(void) 11 | { 12 | printf("%s\n", __FUNCTION__); 13 | mylib2_fct1(); 14 | return 0; 15 | } 16 | 17 | static void __attribute__((destructor)) mylib1_fini(void) 18 | { 19 | printf("Fini function %s\n", __FUNCTION__); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | picon for Debian 2 | ---------------- 3 | 4 | picon-monitor is compiled with timeout feature deactivated. It means 5 | that picon-monitor will not kill the monitored program if it receives 6 | no signal from it. To activate this feature you need to rebuild the 7 | monitor with this feature enabled. Indeed, for security reasons, it 8 | cannot be enabled/disabled at runtime. 9 | 10 | -- Arnaud Fontaine Wed, 29 Jul 2015 15:20:22 +0200 11 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS:=unit_tests shared_libs 2 | 3 | INSTALL?=install 4 | 5 | 6 | TARGET?=all 7 | export CC:=clang 8 | 9 | %: 10 | $(MAKE) recursive TARGET=$@ 11 | 12 | recursive: 13 | for DIR in $(SUBDIRS) ; do $(MAKE) -C $${DIR} $(TARGET) ; done 14 | 15 | install: 16 | $(INSTALL) -m 0755 -d $(DESTDIR)/usr/share/doc/picon/examples/ ; \ 17 | $(INSTALL) -m 0644 Makefile $(DESTDIR)/usr/share/doc/picon/examples/ ; \ 18 | $(MAKE) recursive TARGET=$@ EXAMPLES_DESTDIR=$(DESTDIR)/usr/share/doc/picon/examples 19 | 20 | .PHONY: install recursive 21 | 22 | -------------------------------------------------------------------------------- /examples/unit_tests/Makefile.common: -------------------------------------------------------------------------------- 1 | PROJECTDIR?=../../ 2 | 3 | BUILDDIR?=build 4 | 5 | SRCDIR:=src 6 | SRC:=$(wildcard $(SRCDIR)/*.c) 7 | 8 | CFI_INCLUDE?=/usr/include 9 | 10 | CC:=clang 11 | CFLAGS+=-I$(CFI_INCLUDE) 12 | CFLAGS+=-Wall -Wextra -Wtype-limits -fstrict-overflow -Wsign-compare -DCFI_DEBUG 13 | LD:=$(CC) 14 | 15 | 16 | BASENAMES:=$(patsubst $(SRCDIR)/%,%,$(basename $(SRC))) 17 | TARGETS:=$(addprefix $(BUILDDIR)/,$(BASENAMES)) 18 | MKDIR?=mkdir 19 | 20 | 21 | all: clean $(TARGETS) 22 | 23 | clean: 24 | $(RM) -r $(BUILDDIR) 25 | 26 | $(BUILDDIR): 27 | $(MKDIR) -p $@ 28 | 29 | install: 30 | 31 | .PHONY: all clean install $(BUILDDIR) 32 | -------------------------------------------------------------------------------- /examples/unit_tests/Makefile: -------------------------------------------------------------------------------- 1 | INSTALL?=install 2 | 3 | SRCDIR:=src 4 | 5 | INSTALL_DATA:=ignored_functions.txt Makefile Makefile.cfi Makefile.common Makefile.no_cfi 6 | INSTALL_DATA_SRC:=$(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/*.c)) 7 | 8 | TARGET?=all 9 | 10 | %: 11 | $(MAKE) both TARGET=$@ 12 | 13 | both: 14 | $(MAKE) -f Makefile.no_cfi $(TARGET) 15 | $(MAKE) -f Makefile.cfi $(TARGET) 16 | 17 | install: 18 | $(INSTALL) -m 0755 -d $(EXAMPLES_DESTDIR)/unit_tests; \ 19 | $(INSTALL) -m 0755 -d $(EXAMPLES_DESTDIR)/unit_tests/src; \ 20 | for file in $(INSTALL_DATA); do \ 21 | $(INSTALL) -m 0644 "$${file}" $(EXAMPLES_DESTDIR)/unit_tests; \ 22 | done ; \ 23 | for file in $(INSTALL_DATA_SRC); do \ 24 | $(INSTALL) -m 0644 "$(SRCDIR)/$${file}" $(EXAMPLES_DESTDIR)/unit_tests/src; \ 25 | done 26 | 27 | 28 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #export DH_VERBOSE = 1 5 | 6 | # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* 7 | DPKG_EXPORT_BUILDFLAGS = 1 8 | include /usr/share/dpkg/default.mk 9 | 10 | # see FEATURE AREAS in dpkg-buildflags(1) 11 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 12 | 13 | # see ENVIRONMENT in dpkg-buildflags(1) 14 | # package maintainers to append CFLAGS 15 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 16 | # package maintainers to append LDFLAGS 17 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 18 | 19 | 20 | # main packaging script based on dh7 syntax 21 | %: 22 | dh $@ 23 | 24 | override_dh_compress: 25 | dh_compress -Xunit_tests -Xshared_libs 26 | -------------------------------------------------------------------------------- /examples/shared_libs/Makefile: -------------------------------------------------------------------------------- 1 | INSTALL?=install 2 | 3 | SRCDIR:=src 4 | 5 | INSTALL_DATA:=ignored_functions.txt Makefile Makefile.cfi Makefile.common Makefile.no_cfi 6 | INSTALL_DATA_SRC:=$(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/*.c)) 7 | 8 | TARGET?=all 9 | 10 | %: 11 | $(MAKE) both TARGET=$@ 12 | 13 | both: 14 | $(MAKE) -f Makefile.no_cfi $(TARGET) 15 | $(MAKE) -f Makefile.cfi $(TARGET) 16 | 17 | install: 18 | $(INSTALL) -m 0755 -d $(EXAMPLES_DESTDIR)/shared_libs; \ 19 | $(INSTALL) -m 0755 -d $(EXAMPLES_DESTDIR)/shared_libs/src; \ 20 | for file in $(INSTALL_DATA); do \ 21 | $(INSTALL) -m 0644 "$${file}" $(EXAMPLES_DESTDIR)/shared_libs; \ 22 | done ; \ 23 | for file in $(INSTALL_DATA_SRC); do \ 24 | $(INSTALL) -m 0644 "$(SRCDIR)/$${file}" $(EXAMPLES_DESTDIR)/shared_libs/src; \ 25 | done 26 | 27 | 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | export LLVM_CONFIG:=llvm-config-3.8 3 | export OPT:=opt-3.8 4 | 5 | 6 | export MKDIR:=mkdir 7 | export CMAKE:=cmake 8 | export INSTALL:=install 9 | 10 | ################## 11 | 12 | export PROJECTDIR:=$(CURDIR) 13 | export CFI_PASS:=$(PROJECTDIR)/llvm_pass/build/CFI/libCFI.so 14 | export CFI_PRELINK:=$(PROJECTDIR)/prelink/picon-prelink 15 | export CFI_INCLUDE:=$(PROJECTDIR)/include 16 | 17 | 18 | SUBDIRS:=llvm_pass monitor prelink 19 | 20 | 21 | TARGET?=all 22 | 23 | %: 24 | $(MAKE) recursive TARGET=$@ 25 | 26 | recursive: 27 | for DIR in $(SUBDIRS) ; do $(MAKE) -C $${DIR} $(TARGET) || exit 1 ; done 28 | 29 | install: 30 | $(MAKE) recursive TARGET=$@ 31 | $(MAKE) -C examples $@ 32 | $(INSTALL) -m 0755 -d $(DESTDIR)/usr/include/picon ; \ 33 | for i in include/picon/* ; do \ 34 | $(INSTALL) -m 0644 "$${i}" $(DESTDIR)/usr/include/picon/ ; \ 35 | done 36 | 37 | 38 | .PHONY: install recursive 39 | -------------------------------------------------------------------------------- /examples/shared_libs/Makefile.no_cfi: -------------------------------------------------------------------------------- 1 | BUILDDIR:=build.no_cfi 2 | 3 | include Makefile.common 4 | 5 | 6 | ############## 7 | 8 | $(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR) 9 | $(CC) $(CFLAGS) -c -o $@ $< 10 | 11 | define build_template_so = 12 | 13 | $(BUILDDIR)/$(1).so: $(BUILDDIR)/$(1).o 14 | $(LD) $(LDFLAGS) -shared -o "$$@" "$$<" 15 | 16 | endef 17 | 18 | define build_template_bin = 19 | 20 | $(BUILDDIR)/$(1): $($(1)_OBJ) 21 | $(LD) $(LDFLAGS) $($(1)_LDFLAGS) -o "$$@" $$^ 22 | 23 | endef 24 | 25 | 26 | define build_template_o = 27 | 28 | $(BUILDDIR)/$(1).o: $(SRCDIR)/$(1).c | $(BUILDDIR) 29 | $(CC) $(CFLAGS) -c -o "$$@" "$$<" 30 | 31 | endef 32 | 33 | 34 | $(foreach BASENAME_SO,$(BASENAMES_SO),$(eval $(call build_template_so,$(BASENAME_SO)))) 35 | $(foreach SRC,$(main_prog_SRC),$(eval $(call build_template_o,$(SRC:.c=),main_prog))) 36 | $(foreach BASENAME_BIN,$(BASENAMES_BIN),$(eval $(call build_template_bin,$(BASENAME_BIN)))) 37 | 38 | -------------------------------------------------------------------------------- /examples/shared_libs/Makefile.common: -------------------------------------------------------------------------------- 1 | PROJECTDIR?=../../ 2 | 3 | BUILDDIR?=build 4 | 5 | SRCDIR:=src 6 | SRC:=$(wildcard $(SRCDIR)/*.c) 7 | 8 | CFI_INCLUDE?=/usr/include 9 | 10 | CC:=clang 11 | CFLAGS+=-I$(CFI_INCLUDE) 12 | CFLAGS+=-Wall -Wextra -Wtype-limits -fstrict-overflow -Wsign-compare -DCFI_DEBUG 13 | CFLAGS+=-fPIC 14 | LD:=$(CC) 15 | 16 | 17 | BASENAMES_SO:=libmylib1 libmylib2 libmylib3 18 | TARGETS_SO:=$(addsuffix .so, $(addprefix $(BUILDDIR)/,$(BASENAMES_SO))) 19 | BASENAMES_BIN:=main_prog 20 | TARGETS_BIN:=$(addprefix $(BUILDDIR)/,$(BASENAMES_BIN)) 21 | main_prog_SRC:=main_prog.c file2.c 22 | main_prog_OBJ:=$(addprefix $(BUILDDIR)/, $(main_prog_SRC:.c=.o)) 23 | main_prog_LDFLAGS:=-L$(BUILDDIR) -lmylib1 -lmylib2 -lmylib3 24 | 25 | MKDIR?=mkdir 26 | 27 | all: clean $(TARGETS_SO) $(TARGETS_BIN) 28 | 29 | clean: 30 | $(RM) -r $(BUILDDIR) 31 | 32 | $(BUILDDIR): 33 | $(MKDIR) $@ 34 | 35 | install: 36 | 37 | .PHONY: all clean install $(BUILDDIR) 38 | -------------------------------------------------------------------------------- /examples/unit_tests/Makefile.cfi: -------------------------------------------------------------------------------- 1 | BUILDDIR:=build.cfi 2 | 3 | include Makefile.common 4 | 5 | IGNORED_FUNCTIONS:=ignored_functions.txt 6 | 7 | CFI_PASS?=/usr/lib/picon/libCFI.so 8 | CFI_PRELINK?=/usr/bin/picon-prelink 9 | 10 | OPT?=opt-3.8 11 | OPTFLAGS:=-load $(CFI_PASS) -cfi -cfi-level=1 -cfi-ignore=$(IGNORED_FUNCTIONS) 12 | 13 | 14 | ############## 15 | _INJECTED:=$(BUILDDIR)/cfi_injected 16 | 17 | 18 | .NOTPARALLEL: 19 | 20 | 21 | $(BUILDDIR)/%.bc: $(SRCDIR)/%.c $(BUILDDIR) 22 | $(CC) $(CFLAGS) -c -emit-llvm -o $@ $< 23 | 24 | $(BUILDDIR)/%_cfi.bc: $(BUILDDIR)/%.bc $(IGNORED_FUNCTIONS) 25 | $(OPT) $(OPTFLAGS) -cfi-prefix=$(basename $@) -S -o $@ $< 26 | 27 | $(BUILDDIR)/%.o: $(BUILDDIR)/%_cfi.bc 28 | $(CC) $(CFLAGS) -c -o $@ $< 29 | 30 | $(_INJECTED)_%.c: $(BUILDDIR)/%_cfi.bc 31 | $(CFI_PRELINK) $(basename $<) > $@ 32 | 33 | $(_INJECTED)_%.o: $(_INJECTED)_%.c 34 | $(CC) $(CFLAGS) -c -o $@ $< 35 | 36 | $(BUILDDIR)/%: $(_INJECTED)_%.o $(BUILDDIR)/%.o 37 | $(LD) $(LDFLAGS) -o $@ $^ 38 | -------------------------------------------------------------------------------- /llvm_pass/CFI/DebugPrintRT.hh: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef DEBUG_PRINT_RT_H__ 20 | # define DEBUG_PRINT_RT_H__ 21 | 22 | void DEBUG_PRINT_ON_RUNTIME(llvm::Value *retVal, llvm::Module& _M, llvm::Instruction *Where); 23 | 24 | #endif // !DEBUG_PRINT_RT_H__ 25 | -------------------------------------------------------------------------------- /monitor/include/monitor_dot.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __MODULE_DOT_H__ 20 | #define __MODULE_DOT_H__ 21 | 22 | #include "monitor_load.h" 23 | 24 | extern void monitor_call_graph(const module_data * const module); 25 | 26 | extern void monitor_control_flow_graph(const function_data * const fun); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /llvm_pass/CFI/Debug.hh: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef DEBUG_H__ 20 | #define DEBUG_H__ 21 | 22 | #ifndef NDEBUG 23 | #define ON_DEBUG(more_info, msg) \ 24 | if (more_info) errs() << "DEBUG" << __FILE__ << "(" << __LINE__ << ") " << msg; \ 25 | else errs() << msg; 26 | #else 27 | #define ON_DEBUG(x, msg) do {} while (0) 28 | #endif 29 | 30 | #endif // !DEBUG_H__ 31 | -------------------------------------------------------------------------------- /llvm_pass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | set(LLVM_CONFIG "llvm-config" CACHE STRING "default llvm-config command") 4 | 5 | set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 6 | 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} $ENV{CMAKE_MODULE_PATH}) 8 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{CMAKE_PREFIX_PATH}) 9 | set(CMAKE_C_COMPILER $ENV{CC}) 10 | set(CMAKE_CXX_COMPILER $ENV{CXX}) 11 | 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 13 | if (${LLVM_ENABLE_RTTI}) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti") 15 | else (${LLVM_ENABLE_RTTI}) 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") 17 | endif (${LLVM_ENABLE_RTTI}) 18 | 19 | ### should work, but actually it is not on current Debian with llvm-3.5 20 | #find_package(LLVM REQUIRED CONFIG) 21 | execute_process(COMMAND ${LLVM_CONFIG} "--cflags" RESULT_VARIABLE LLVM_CONFIG_RES OUTPUT_VARIABLE LLVM_DEFINITIONS) 22 | if (NOT LLVM_CONFIG_RES EQUAL 0) 23 | message (FATAL_ERROR "command ${LLVM_CONFIG} not found in PATH : error ${LLVM_CONFIG_RES}") 24 | endif () 25 | 26 | add_definitions(${LLVM_DEFINITIONS}) 27 | include_directories(${LLVM_INCLUDE_DIRS}) 28 | 29 | add_subdirectory(CFI) 30 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: picon 3 | Source: 4 | 5 | Files: * 6 | Copyright: 2015 Pierre Chifflier 7 | 2015 Thomas Coudray 8 | 2015 Arnaud Fontaine 9 | License: LGPL-2.1+ 10 | 11 | Files: debian/* 12 | Copyright: 2015 Arnaud Fontaine 13 | License: LGPL-2.1+ 14 | 15 | License: LGPL-2.1+ 16 | This package is free software; you can redistribute it and/or 17 | modify it under the terms of the GNU Lesser General Public 18 | License as published by the Free Software Foundation; either 19 | version 2.1 of the License, or (at your option) any later version. 20 | . 21 | This package is distributed in the hope that it will be useful, 22 | but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 | Lesser General Public License for more details. 25 | . 26 | You should have received a copy of the GNU General Public License 27 | along with this program. If not, see . 28 | . 29 | On Debian systems, the complete text of the GNU Lesser General 30 | Public License can be found in "/usr/share/common-licenses/LGPL-2.1". 31 | 32 | -------------------------------------------------------------------------------- /monitor/include/monitor_run.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __MONITOR_RUN_H__ 20 | #define __MONITOR_RUN_H__ 21 | 22 | 23 | #include "call_stack.h" 24 | #include "block_stack.h" 25 | #include "monitor_load.h" 26 | 27 | typedef enum { 28 | SM_STATE_Ready, 29 | SM_STATE_InFunction, 30 | SM_STATE_ExpectCall, 31 | SM_STATE_ExpectReturn, 32 | SM_STATE_ExpectJump, 33 | } monitor_state_t; 34 | 35 | 36 | 37 | 38 | 39 | 40 | extern int monitor_run(const monitor_data data); 41 | 42 | 43 | 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFIModulePass.hh: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef CFI_MODULE_PASS_H__ 20 | # define CFI_MODULE_PASS_H__ 21 | 22 | #include "llvm/Analysis/PostDominators.h" 23 | 24 | #include "llvm/IR/Module.h" 25 | #include "Debug.hh" 26 | 27 | using namespace llvm; 28 | 29 | class injectorCFI; 30 | 31 | typedef enum 32 | { 33 | FUNCTION = 0, 34 | BASICBLOCK = 1 35 | } cfi_level_t; 36 | 37 | struct CFIModulePass: public ModulePass { 38 | static char ID; 39 | 40 | CFIModulePass(); 41 | bool runOnModule(Module &M); 42 | 43 | virtual void getAnalysisUsage(AnalysisUsage &AU) const; 44 | }; 45 | 46 | #endif // !CFI_MODULE_PASS_H__ 47 | -------------------------------------------------------------------------------- /monitor/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDEDIR:=include 2 | SRCDIR:=src 3 | 4 | PROJECTDIR?=../ 5 | 6 | INCLUDES:=$(wildcard $(INCLUDEDIR)/*.h) 7 | SRCFILES:=\ 8 | defs.c \ 9 | call_stack.c \ 10 | block_stack.c \ 11 | monitor_dot.c \ 12 | monitor_load.c \ 13 | monitor_run.c \ 14 | main.c 15 | 16 | EXE:=picon-monitor 17 | 18 | CFLAGS+=-Wall -Wextra -Wtype-limits -fstrict-overflow -Wsign-compare -std=c89 19 | CFLAGS+=-I$(PROJECTDIR)/include 20 | CFLAGS+=-O2 21 | #CFLAGS+=-g 22 | 23 | LDFLAGS:= 24 | 25 | #CFLAGS+=-DSILENT 26 | #CFLAGS+=-DCFI_DEBUG 27 | #CFLAGS+=-DNB_PRELOADED_MONITOR_OK_ANSWERS=1 28 | #CFLAGS+=-DTIMEOUT 29 | #CFLAGS+=-DTIMEOUT_SEC_MONITOR_NO_SIGNAL=0 30 | #CFLAGS+=-DTIMEOUT_NANOSEC_MONITOR_NO_SIGNAL=500000000 31 | 32 | 33 | 34 | ################# 35 | MKDIR?=mkdir 36 | BUILDDIR:=build 37 | 38 | _SRCFILES:=$(addprefix $(SRCDIR)/,$(SRCFILES)) 39 | _OFILES:=$(addprefix $(BUILDDIR)/,$(patsubst %.c,%.o,$(filter %.c,$(SRCFILES)))) 40 | 41 | CFLAGS+=-I$(INCLUDEDIR) 42 | 43 | 44 | 45 | all: $(BUILDDIR)/$(EXE) 46 | 47 | clean: 48 | $(RM) -r $(BUILDDIR) 49 | 50 | install: 51 | $(INSTALL) -m 0755 -d $(DESTDIR)/usr/bin/ ; \ 52 | $(INSTALL) -m 0755 $(BUILDDIR)/picon-monitor $(DESTDIR)/usr/bin/ 53 | 54 | .PHONY: all clean install 55 | 56 | 57 | $(BUILDDIR)/$(EXE): $(_OFILES) 58 | $(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ 59 | 60 | $(BUILDDIR): 61 | $(MKDIR) "$@" 62 | 63 | $(BUILDDIR)/%.o: $(SRCDIR)/%.c $(BUILDDIR) $(INCLUDES) 64 | $(CC) $(CFLAGS) -c -o "$@" "$<" 65 | -------------------------------------------------------------------------------- /monitor/src/defs.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "defs.h" 20 | 21 | 22 | 23 | unsigned int OPTION_sm_trace = 0; 24 | 25 | unsigned int OPTION_sm_dump = 0; 26 | 27 | unsigned int OPTION_nb_preload_monitor_ok_answers = 28 | #ifdef NB_PRELOADED_MONITOR_OK_ANSWERS 29 | NB_PRELOADED_MONITOR_OK_ANSWERS 30 | #else 31 | 0 32 | #endif 33 | ; 34 | 35 | 36 | 37 | #ifdef TIMEOUT 38 | 39 | 40 | struct timespec OPTION_timeout_monitor_no_signal = 41 | { 42 | .tv_sec = 43 | #ifdef TIMEOUT_SEC_MONITOR_NO_SIGNAL 44 | TIMEOUT_SEC_MONITOR_NO_SIGNAL 45 | #else 46 | 0 47 | #endif 48 | , 49 | 50 | .tv_nsec = 51 | #ifdef TIMEOUT_NANOSEC_MONITOR_NO_SIGNAL 52 | TIMEOUT_NANOSEC_MONITOR_NO_SIGNAL 53 | #else 54 | 0 55 | #endif 56 | , 57 | }; 58 | 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /examples/unit_tests/src/test_no_basic_blocks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | 8 | CFI_IGNORE_BASIC_BLOCKS 9 | void 10 | fill_incr(unsigned int * const tab, 11 | const unsigned int width, 12 | const unsigned int height) { 13 | 14 | unsigned int i, j, count; 15 | 16 | count = 0; 17 | for(i = 0; i < width; ++i) { 18 | for(j = 0; j < height; ++j) { 19 | tab[i * height + j] = count++; 20 | } 21 | } 22 | } 23 | 24 | 25 | CFI_IGNORE_BASIC_BLOCKS 26 | void 27 | do_incr(unsigned int * const tab, 28 | const unsigned int width, 29 | const unsigned int height) { 30 | 31 | unsigned int i, j; 32 | 33 | for(i = 0; i < width; ++i) { 34 | for(j = 0; j < height; ++j) { 35 | ++(tab[i * height + j]); 36 | } 37 | } 38 | } 39 | 40 | 41 | 42 | 43 | #define SOME_WIDTH 4000 44 | #define SOME_HEIGHT SOME_WIDTH 45 | 46 | 47 | 48 | int main() { 49 | 50 | unsigned int *tab; 51 | 52 | fprintf(stdout, "allocating tab with %u integers\n", SOME_WIDTH * SOME_HEIGHT); 53 | fflush(stdout); 54 | if((tab = calloc(SOME_WIDTH * SOME_HEIGHT, sizeof(unsigned int))) == NULL) { 55 | perror("failed to allocate tab"); 56 | return 1; 57 | } 58 | 59 | fprintf(stdout, "filling tab\n"); 60 | fflush(stdout); 61 | fill_incr(tab, SOME_WIDTH, SOME_HEIGHT); 62 | 63 | fprintf(stdout, "incrementing tab\n"); 64 | fflush(stdout); 65 | do_incr(tab, SOME_WIDTH, SOME_HEIGHT); 66 | 67 | fprintf(stdout, "freeing tab\n"); 68 | fflush(stdout); 69 | free(tab); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFIInjector.hh: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef INJECTOR_H__ 20 | # define INJECTOR_H__ 21 | 22 | #include 23 | 24 | #include "llvm/IR/Module.h" 25 | #include "llvm/IR/Function.h" 26 | 27 | class injectorCFI { 28 | public: 29 | injectorCFI(Module &M); 30 | 31 | public: 32 | void injectPrototype(void); 33 | void injectMentry(Function& F, int FctID); 34 | void injectMexit(Function &F, int FctID); 35 | void injectMcall(ControlFlowIntegrity *, Function &F); 36 | void injectBBEnter(ControlFlowIntegrity *cfi, Function &F); 37 | void injectBBLeave(ControlFlowIntegrity *cfi, Function &F); 38 | void injectForkSon(Function &F); 39 | 40 | public: 41 | void InjectCode(ControlFlowIntegrity *, int granlvl); 42 | 43 | private: 44 | Module& _M; 45 | Value* _SavedRetAddr; 46 | }; 47 | 48 | #endif // !INJECTOR_H__ 49 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: picon 2 | Section: devel 3 | Priority: optional 4 | Maintainer: Arnaud Fontaine 5 | Build-Depends: debhelper (>= 9), make, cmake, clang-3.5, llvm-3.5-dev, llvm-3.5, python 6 | Standards-Version: 3.9.6 7 | Homepage: https://github.com/ANSSI-FR/picon 8 | 9 | Package: picon-pass 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, 12 | ${misc:Depends}, 13 | llvm-3.5, python 14 | Recommends: clang-3.5 | clang 15 | Description: Control Flow Integrity protection for LLVM IR (LLVM pass) 16 | Picon is an implementation of Control Flow Integrity protection made 17 | of two parts. This package contains the LLVM compiler pass to 18 | instrument a program to be monitored by picon-monitor in order to 19 | inject communication routines and message exchanges with the external 20 | picon-monitor. 21 | 22 | Package: picon-monitor 23 | Architecture: any 24 | Depends: ${shlibs:Depends}, 25 | ${misc:Depends} 26 | Description: Control Flow Integrity protection for LLVM IR (monitor) 27 | Picon is an implementation of Control Flow Integrity protection made 28 | of two parts. This package contains the picon-monitor that monitors a 29 | picon-instrumented program to ensure the integrity of its execution 30 | flow according to its expected control flow integrity. 31 | 32 | Package: picon 33 | Architecture: any 34 | Depends: picon, picon-monitor 35 | Description: Control Flow Integrity protection for LLVM IR (metapackage) 36 | Picon is an implementation of Control Flow Integrity protection made 37 | of two parts: the picon-pass for program instrumentation, and the 38 | picon-monitor for execution monitoring. 39 | -------------------------------------------------------------------------------- /monitor/src/monitor_dot.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "monitor_dot.h" 20 | 21 | void 22 | monitor_call_graph(const module_data * const module) { 23 | unsigned int i, j; 24 | 25 | printf("digraph{\n"); 26 | printf("\ttitle=\"Call graph of module\";\n"); 27 | 28 | for(i = 0; i < module->nb_functions; ++i) { 29 | for(j = 0; j < module->nb_functions; ++j) { 30 | if(module->call_graph[i] && 31 | module->call_graph[i][j]) { 32 | printf("\t%u -> %u;\n", i, j); 33 | } 34 | } 35 | } 36 | 37 | printf("}\n"); 38 | } 39 | 40 | 41 | void monitor_control_flow_graph(const function_data * const function) { 42 | unsigned int i, j; 43 | 44 | printf("digraph{\n"); 45 | printf("\ttitle=\"Control flow graph of function name=%s\";\n", function->name); 46 | 47 | for(i = 0; i < function->nb_blocks; ++i) { 48 | for(j = 0; j < function->nb_blocks; ++j) { 49 | if(function->control_flow_graph[i] && 50 | function->control_flow_graph[i][j]) { 51 | printf("\t%u -> %u;\n", i, j); 52 | } 53 | } 54 | } 55 | 56 | printf("}\n"); 57 | } 58 | -------------------------------------------------------------------------------- /examples/shared_libs/Makefile.cfi: -------------------------------------------------------------------------------- 1 | BUILDDIR:=build.cfi 2 | 3 | include Makefile.common 4 | 5 | IGNORED_FUNCTIONS:=ignored_functions.txt 6 | 7 | CFI_PASS?=/usr/lib/picon/libCFI.so 8 | CFI_PRELINK?=/usr/bin/picon-prelink 9 | 10 | OPT?=opt-3.8 11 | OPTFLAGS:=-load $(CFI_PASS) -cfi -cfi-level=1 -cfi-ignore=$(IGNORED_FUNCTIONS) 12 | 13 | 14 | ############## 15 | _INJECTED:=$(BUILDDIR)/cfi_injected 16 | 17 | 18 | .NOTPARALLEL: 19 | 20 | define build_template_so = 21 | 22 | $(BUILDDIR)/$(1).bc: $(SRCDIR)/$(1).c $(BUILDDIR) 23 | $(CC) $(CFLAGS) -c -emit-llvm -o "$$@" "$$<" 24 | 25 | $(BUILDDIR)/$(1).cfi.bc: $(BUILDDIR)/$(1).bc $(IGNORED_FUNCTIONS) 26 | $(OPT) $(OPTFLAGS) -cfi-prefix=$(BUILDDIR)/$(1) -S -o "$$@" "$$<" 27 | 28 | $(BUILDDIR)/$(1).o: $(BUILDDIR)/$(1).cfi.bc 29 | $(CC) $(CFLAGS) -c -o "$$@" "$$<" 30 | 31 | $(_INJECTED)_$(1).c: $(BUILDDIR)/$(1).cfi.bc 32 | $(CFI_PRELINK) $(BUILDDIR)/$(1) > "$$@" 33 | 34 | $(_INJECTED)_$(1).o: $(_INJECTED)_$(1).c 35 | $(CC) $(CFLAGS) -c -o "$$@" "$$<" 36 | 37 | $(BUILDDIR)/$(1).so: $(BUILDDIR)/$(1).o $(_INJECTED)_$(1).o 38 | $(LD) $(LDFLAGS) -shared -o $$@ $$^ 39 | 40 | endef 41 | 42 | 43 | define build_template_bin = 44 | 45 | $(_INJECTED)_$(1).c: $($(1)_OBJ:%.o=%.cfi.bc) 46 | $(CFI_PRELINK) $(BUILDDIR)/$(1) > "$$@" 47 | 48 | $(_INJECTED)_$(1).o: $(_INJECTED)_$(1).c 49 | $(CC) $(CFLAGS) -c -o "$$@" "$$<" 50 | 51 | $(BUILDDIR)/$(1): $(_INJECTED)_$(1).o $($(1)_OBJ) 52 | $(LD) $(LDFLAGS) $($(1)_LDFLAGS) -o $$@ $$^ 53 | 54 | endef 55 | 56 | 57 | define build_template_o = 58 | 59 | $(BUILDDIR)/$(1).bc: $(SRCDIR)/$(1).c | $(BUILDDIR) 60 | $(CC) $(CFLAGS) -c -emit-llvm -o "$$@" "$$<" 61 | 62 | $(BUILDDIR)/$(1).cfi.bc: $(BUILDDIR)/$(1).bc $(IGNORED_FUNCTIONS) 63 | $(OPT) $(OPTFLAGS) -cfi-prefix=$(BUILDDIR)/$(2) -S -o "$$@" "$$<" 64 | 65 | $(BUILDDIR)/$(1).o: $(BUILDDIR)/$(1).cfi.bc 66 | $(CC) $(CFLAGS) -c -o "$$@" "$$<" 67 | 68 | endef 69 | 70 | 71 | 72 | $(foreach BASENAME_SO,$(BASENAMES_SO),$(eval $(call build_template_so,$(BASENAME_SO)))) 73 | $(foreach SRC,$(main_prog_SRC),$(eval $(call build_template_o,$(SRC:.c=),main_prog))) 74 | $(foreach BASENAME_BIN,$(BASENAMES_BIN),$(eval $(call build_template_bin,$(BASENAME_BIN)))) 75 | 76 | -------------------------------------------------------------------------------- /llvm_pass/CFI/DebugPrintRT.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | // DEBUG FUNCTION only 20 | // 21 | // retVal: Function to dump the return value (for ex, the call to @llvm.returnaddress) 22 | // _M: The module 23 | // Where: where to insert the printf call 24 | // 25 | // 26 | void DEBUG_PRINT_ON_RUNTIME(llvm::Value *retVal, llvm::Module& _M, llvm::Instruction *Where) 27 | { 28 | Function* func_printf = _M.getFunction("printf"); 29 | ArrayType* arrType = ArrayType::get(IntegerType::get(_M.getContext(), 8), 12); 30 | GlobalVariable* glArrStrings = new GlobalVariable(_M, arrType, true, 31 | GlobalValue::PrivateLinkage, 0, ".str"); 32 | 33 | Constant *constPrintfStr = ConstantDataArray::getString(_M.getContext(), "salut : %x\x0A", true); 34 | ConstantInt* magicGEP = ConstantInt::get(_M.getContext(), APInt(32, StringRef("0"), 10)); 35 | 36 | std::vector ptrIdx; 37 | ptrIdx.push_back(magicGEP); 38 | ptrIdx.push_back(magicGEP); 39 | Constant* StrArgs = ConstantExpr::getGetElementPtr(glArrStrings, ptrIdx); 40 | 41 | glArrStrings->setInitializer(constPrintfStr); 42 | 43 | AllocaInst* ptr_i = new AllocaInst(IntegerType::get(_M.getContext(), 32), "i", Where); 44 | LoadInst* int32_12 = new LoadInst(ptr_i, "", false, Where); 45 | std::vector Args; 46 | Args.push_back(StrArgs); 47 | Args.push_back(retVal); 48 | CallInst* int32_call = CallInst::Create(func_printf, Args, "call_printf_debug", Where); 49 | } 50 | -------------------------------------------------------------------------------- /monitor/include/call_stack.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __CALL_STACK_H__ 20 | #define __CALL_STACK_H__ 21 | 22 | 23 | #include "block_stack.h" 24 | 25 | 26 | 27 | typedef struct { 28 | module_id module; 29 | function_id function; 30 | block_stack_element *blocks_sp; 31 | } call_stack_element; 32 | 33 | typedef struct { 34 | call_stack_element *first; 35 | call_stack_element *last; 36 | call_stack_element *top; 37 | } call_stack; 38 | 39 | 40 | 41 | extern int call_stack_init(call_stack * const call_stack); 42 | 43 | extern void call_stack_free(call_stack * const call_stack); 44 | 45 | extern int call_stack_extend(call_stack * const call_stack); 46 | 47 | extern void call_stack_trace(const call_stack * const call_stack); 48 | 49 | #define CALL_STACK_IS_EMPTY(s) ((s).top < (s).first) 50 | 51 | #define CALL_STACK_PUSH(s,v,err) \ 52 | do { \ 53 | if(unlikely((s).top >= (s).last)) { \ 54 | (err) = call_stack_extend(&(s)); \ 55 | } \ 56 | if(likely((err) == 0)) { \ 57 | *(++((s).top)) = v; \ 58 | } \ 59 | } while(0) 60 | 61 | 62 | #define CALL_STACK_POP(s,v) \ 63 | do { \ 64 | (v) = *((s).top--); \ 65 | } while(0) 66 | 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/picon/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | 6 | 7 | 8 | #define _LOG_STR_ERROR "\033[31;01m[error]\033[00m" 9 | #define _LOG_STR_DEBUG "\033[34;01m[debug]\033[00m" 10 | #define _LOG_STR_TRACE "\033[33;01m[trace]\033[00m" 11 | 12 | #define _LOG_STR_MONITOR "\033[35;01m[monitor]\033[00m" 13 | #define _LOG_STR_CLIENT "\033[36;01m[ client]\033[00m" 14 | 15 | 16 | 17 | #ifdef SILENT 18 | #define _LOG(...) 19 | #else 20 | #define _LOG(...) \ 21 | do { \ 22 | fprintf(stderr, __VA_ARGS__); \ 23 | } while(0) 24 | #endif 25 | 26 | 27 | #define _LOG_ERROR(...) \ 28 | do { \ 29 | _LOG(_LOG_STR_ERROR "\t" __VA_ARGS__); \ 30 | } while(0) 31 | 32 | 33 | 34 | #define LOG_ERROR_CLIENT(...) \ 35 | do { \ 36 | _LOG_ERROR(_LOG_STR_CLIENT "\t" __VA_ARGS__); \ 37 | } while(0) 38 | 39 | #define LOG_ERROR_MONITOR(...) \ 40 | do { \ 41 | _LOG_ERROR(_LOG_STR_MONITOR "\t" __VA_ARGS__); \ 42 | } while(0) 43 | 44 | 45 | 46 | 47 | 48 | #if defined CFI_DEBUG 49 | #define _LOG_DEBUG(...) \ 50 | do { \ 51 | _LOG(_LOG_STR_DEBUG "\t" __VA_ARGS__); \ 52 | } while(0) 53 | #else 54 | #define _LOG_DEBUG(...) 55 | #endif 56 | 57 | 58 | 59 | 60 | 61 | #define LOG_DEBUG_CLIENT(...) \ 62 | do { \ 63 | _LOG_DEBUG(_LOG_STR_CLIENT "\t" __VA_ARGS__); \ 64 | } while(0) 65 | 66 | #define LOG_DEBUG_MONITOR(...) \ 67 | do { \ 68 | _LOG_DEBUG(_LOG_STR_MONITOR "\t" __VA_ARGS__); \ 69 | } while(0) 70 | 71 | 72 | 73 | #define _LOG_TRACE(...) \ 74 | do { \ 75 | _LOG(_LOG_STR_TRACE "\t" __VA_ARGS__); \ 76 | } while(0) 77 | #else 78 | 79 | #define LOG_TRACE_MONITOR(...) \ 80 | do { \ 81 | _LOG_TRACE(_LOG_STR_MONITOR "\t" __VA_ARGS__); \ 82 | } while(0) 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /monitor/include/defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __DEFS_H__ 20 | #define __DEFS_H__ 21 | 22 | #define _GNU_SOURCE 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | 31 | 32 | 33 | #define ENV_SM_TRACE "CFI_TRACE" 34 | 35 | #define ENV_SM_DUMP "CFI_DUMP" 36 | 37 | 38 | #define CALL_STACK_EXTEND_SIZE 512 39 | 40 | #define BLOCK_STACK_EXTEND_SIZE 4096 41 | 42 | 43 | 44 | 45 | #define FUNCTION_ENTRY_BLOCK_ID (function_id)0 46 | 47 | 48 | 49 | extern unsigned int OPTION_sm_trace; 50 | extern unsigned int OPTION_sm_dump; 51 | extern unsigned int OPTION_nb_preload_monitor_ok_answers; 52 | 53 | 54 | 55 | 56 | #ifdef TIMEOUT 57 | 58 | extern struct timespec OPTION_timeout_monitor_no_signal; 59 | 60 | #define MONITOR_SIGNAL_FDRS(fd,fdrs) \ 61 | do { \ 62 | FD_ZERO(&(fdrs)); \ 63 | FD_SET((fd), (&(fdrs))); \ 64 | } while(0) 65 | 66 | #define MONITOR_SIGNAL_TIMEOUT(fd,fdrs,err) \ 67 | do { \ 68 | if(unlikely(pselect((fd)+1, &(fdrs), NULL, NULL, \ 69 | &OPTION_timeout_monitor_no_signal, NULL) != 1)) { \ 70 | (err) = 1; \ 71 | } \ 72 | } while(0) 73 | 74 | #else 75 | 76 | #define MONITOR_SIGNAL_FDRS(fd,fdrs) 77 | 78 | #define MONITOR_SIGNAL_TIMEOUT(fd,fdrs,err) 79 | 80 | #endif 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /monitor/src/block_stack.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "defs.h" 20 | #include "block_stack.h" 21 | 22 | #include 23 | 24 | 25 | int block_stack_init(block_stack * const block_stack) { 26 | const unsigned int msize = BLOCK_STACK_EXTEND_SIZE; 27 | 28 | if((block_stack->first = calloc(msize, sizeof(block_stack_element))) == NULL) { 29 | LOG_DEBUG_MONITOR("failed to allocate block_stack\n"); 30 | return -1; 31 | } 32 | block_stack->last = block_stack->first + (msize - 1); 33 | block_stack->top = block_stack->first - 1; /* invalid ptr */ 34 | 35 | return 0; 36 | } 37 | 38 | void block_stack_free(block_stack * const block_stack) { 39 | if(block_stack->first) { 40 | free(block_stack->first); 41 | block_stack->first = NULL; 42 | block_stack->top = NULL; 43 | block_stack->last = NULL; 44 | } 45 | } 46 | 47 | int block_stack_extend(block_stack * const block_stack) { 48 | ssize_t msize = (block_stack->last - block_stack->first + 1) + BLOCK_STACK_EXTEND_SIZE; 49 | const ssize_t rsize = msize * sizeof(block_stack_element); 50 | 51 | if((block_stack->first = realloc(block_stack->first, rsize)) == NULL) { 52 | LOG_DEBUG_MONITOR("failed to reallocate block_stack\n"); 53 | return -1; 54 | } 55 | 56 | block_stack->last = block_stack->first + (msize - 1); 57 | 58 | return 0; 59 | } 60 | 61 | 62 | void block_stack_trace(const block_stack * const block_stack) { 63 | block_stack_element *ptr; 64 | 65 | if(BLOCK_STACK_IS_EMPTY(*block_stack)) { 66 | return; 67 | } 68 | 69 | ptr = block_stack->top; 70 | while(ptr >= block_stack->first) { 71 | LOG_TRACE_MONITOR("@0x%p block=%6u\n", ptr, *ptr); 72 | --ptr; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /monitor/src/call_stack.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "defs.h" 20 | #include "call_stack.h" 21 | 22 | #include 23 | 24 | 25 | 26 | int call_stack_init(call_stack * const call_stack) { 27 | const unsigned int msize = CALL_STACK_EXTEND_SIZE; 28 | 29 | if((call_stack->first = calloc(msize,sizeof(call_stack_element))) == NULL) { 30 | LOG_DEBUG_MONITOR("failed to allocate call_stack\n"); 31 | return -1; 32 | } 33 | call_stack->last = call_stack->first + (msize - 1); 34 | call_stack->top = call_stack->first - 1; /* invalid ptr */ 35 | 36 | return 0; 37 | } 38 | 39 | void call_stack_free(call_stack * const call_stack) { 40 | if(call_stack->first) { 41 | free(call_stack->first); 42 | call_stack->first = NULL; 43 | call_stack->top = NULL; 44 | call_stack->last = NULL; 45 | } 46 | } 47 | 48 | int call_stack_extend(call_stack * const call_stack) { 49 | ssize_t msize = (call_stack->last - call_stack->first + 1) + CALL_STACK_EXTEND_SIZE; 50 | const ssize_t rsize = msize * sizeof(call_stack_element); 51 | 52 | if((call_stack->first = realloc(call_stack->first, rsize)) == NULL) { 53 | LOG_DEBUG_MONITOR("failed to reallocate call_stack\n"); 54 | return -1; 55 | } 56 | 57 | call_stack->last = call_stack->first + (msize - 1); 58 | 59 | return 0; 60 | } 61 | 62 | void call_stack_trace(const call_stack * const call_stack) { 63 | call_stack_element *ptr; 64 | 65 | if(CALL_STACK_IS_EMPTY(*call_stack)) { 66 | return; 67 | } 68 | 69 | ptr = call_stack->top; 70 | while(ptr >= call_stack->first) { 71 | LOG_TRACE_MONITOR("module=%6u function=%6u blocks_sp=0x%p\n", ptr->module, ptr->function, ptr->blocks_sp); 72 | --ptr; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /monitor/include/block_stack.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __BLOCK_STACK_H__ 20 | #define __BLOCK_STACK_H__ 21 | 22 | #include "defs.h" 23 | 24 | typedef block_id block_stack_element; 25 | 26 | typedef struct { 27 | block_stack_element *first; 28 | block_stack_element *last; 29 | block_stack_element *top; 30 | } block_stack; 31 | 32 | 33 | 34 | extern int block_stack_init(block_stack * const block_stack); 35 | 36 | extern void block_stack_free(block_stack * const block_stack); 37 | 38 | extern int block_stack_extend(block_stack * const block_stack); 39 | 40 | extern void block_stack_trace(const block_stack * const call_stack); 41 | 42 | #define BLOCK_STACK_IS_EMPTY(s) ((s).top < (s).first) 43 | 44 | #define BLOCK_STACK_TOP_PTR(s) ((s).top) 45 | 46 | #define BLOCK_STACK_RESTORE_TOP(s,t) \ 47 | do { \ 48 | (s).top = t; \ 49 | } while(0) 50 | 51 | #define BLOCK_STACK_PUSH(s,v,err) \ 52 | do { \ 53 | if(unlikely((s).top >= (s).last)) { \ 54 | (err) = block_stack_extend(&(s)); \ 55 | } \ 56 | if(likely((err) == 0)) { \ 57 | *(++((s).top)) = v; \ 58 | } \ 59 | } while(0) 60 | 61 | #define BLOCK_STACK_POP(s,v) \ 62 | do { \ 63 | (v) = *((s).top--); \ 64 | } while(0) 65 | 66 | #define BLOCK_STACK_IS_NOT_COHERENT_OR_IS_EMPTY(s) \ 67 | (((s).top < (s).first) || ((s).last < (s).top)) 68 | 69 | 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /monitor/include/monitor_load.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef __MONITOR_LOAD_H__ 20 | #define __MONITOR_LOAD_H__ 21 | 22 | 23 | #include "defs.h" 24 | 25 | #include 26 | #include 27 | 28 | 29 | 30 | 31 | typedef struct { 32 | char *name; 33 | fct_flag_t flags; 34 | unsigned int nb_blocks; 35 | uint8_t **control_flow_graph; /* block_id -> block_id -> bool */ 36 | block_id *immediate_post_dominator; /* block_id -> block_id */ 37 | } function_data; 38 | 39 | 40 | #define FUNCTION_IS_ENTRYPOINT_MAIN(fdata) ((fdata).flags == FCT_MAIN) 41 | #define FUNCTION_IS_ENTRYPOINT_INIT(fdata) ((fdata).flags == FCT_INIT) 42 | #define FUNCTION_IS_ENTRYPOINT_FINI(fdata) ((fdata).flags == FCT_FINI) 43 | #define FUNCTION_IS_ENTRYPOINT(fdata) (FUNCTION_IS_ENTRYPOINT_MAIN((fdata)) || \ 44 | FUNCTION_IS_ENTRYPOINT_INIT((fdata)) || \ 45 | FUNCTION_IS_ENTRYPOINT_FINI((fdata))) 46 | 47 | #define FUNCTION_IS_EXTERNAL(fdata) ((fdata).flags == FCT_EXTERNAL) 48 | 49 | 50 | typedef struct { 51 | unsigned int nb_functions; 52 | unsigned int nb_entrypoint_inits; 53 | unsigned int nb_entrypoint_finis; 54 | uint8_t **call_graph; /* local_fun_id -> local_fun_id -> bool */ 55 | module_function_ids *relocations; /* local_fun_id -> (module_id,local_fun_id) */ 56 | function_data *functions; /* local_fun_id -> function_data */ 57 | } module_data; 58 | 59 | 60 | typedef struct { 61 | pid_t client_pid; 62 | 63 | int fd_client_to_monitor; 64 | int fd_monitor_to_client; 65 | int fd_loading_to_monitor; 66 | int fd_monitor_to_loading; 67 | 68 | unsigned int nb_modules; 69 | module_data *modules; 70 | } monitor_data; 71 | 72 | 73 | extern int monitor_load(const pid_t client_pid, 74 | const int fd_client_to_monitor, 75 | const int fd_monitor_to_client, 76 | const int fd_loading_to_monitor, 77 | const int fd_monitor_to_loading, 78 | monitor_data * const data); 79 | 80 | extern void monitor_data_free(monitor_data * const data); 81 | 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFIModulePass.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "CFI.hh" 20 | #include "CFIInjector.hh" 21 | #include "CFIModulePass.hh" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | static cl::opt level("cfi-level", cl::desc("Specify the CFI instrumentation level: [0/1] 0: functions, 1: functions and basic blocks"), cl::value_desc("cfi-level")); 29 | static cl::opt prefix("cfi-prefix", cl::desc("Specify the prefix used to load/store CFI temporary files"), cl::value_desc("[dirname/]basename")); 30 | static cl::opt IgnoredFctFileName("cfi-ignore", cl::desc("Specify file containing functions ignored by CFI"), cl::value_desc("filename")); 31 | 32 | CFIModulePass::CFIModulePass() : ModulePass(ID) { } 33 | 34 | bool CFIModulePass::runOnModule(Module &M) { 35 | 36 | std::string s_fctid, s_trans, s_bbtrans, s_ipdom; 37 | std::string s_lock; 38 | int fd, rc; 39 | 40 | s_fctid = prefix + ".fctid"; 41 | s_trans = prefix + ".trans"; 42 | s_bbtrans = prefix + ".bbtrans"; 43 | s_ipdom = prefix + ".ipdom"; 44 | s_lock = prefix + ".lock"; 45 | 46 | fd = open(s_lock.c_str(), O_RDWR | O_CREAT, 0666); 47 | if (fd < 0) { 48 | errs() << "Could not create lock file\n"; 49 | assert( fd < 0 && "Could not create lock file\n"); 50 | } 51 | rc = flock(fd, LOCK_EX); 52 | if (rc < 0) { 53 | errs() << "flock() failed\n"; 54 | assert( rc < 0 && "flock() failed\n"); 55 | } 56 | 57 | ControlFlowIntegrity RCFI(M, s_fctid, s_ipdom, s_trans, s_bbtrans, IgnoredFctFileName); 58 | 59 | RCFI.ParseAnnotations(); 60 | 61 | RCFI.IdentifyFunctions(); 62 | 63 | #ifndef NDEBUG 64 | RCFI.IdentifyBB(); 65 | #endif // !NDEBUG 66 | 67 | RCFI.PatchCtorFunctions(); 68 | RCFI.PatchDtorFunctions(); 69 | 70 | RCFI.writeTransToFile(level); 71 | RCFI.writeFunctionIDs(); 72 | RCFI.writeIPDOMToFile(this); 73 | 74 | 75 | (void)flock(fd, LOCK_UN); 76 | 77 | injectorCFI ICFI(M); 78 | ICFI.InjectCode(&RCFI, level); 79 | 80 | return true; // module was modified 81 | } 82 | 83 | void CFIModulePass::getAnalysisUsage(AnalysisUsage &AU) const { 84 | AU.setPreservesAll(); 85 | AU.addRequired(); 86 | } 87 | 88 | char CFIModulePass::ID = 0; 89 | static RegisterPass U("cfi", "control flow integrity"); 90 | -------------------------------------------------------------------------------- /include/picon/injected_code.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define UNUSED __attribute__((unused)) 14 | #define HIDDEN __attribute__((visibility("hidden"))) 15 | #define INTERNAL __attribute__((visibility("internal"))) 16 | 17 | static int _fd_client_to_monitor = -1; 18 | static int _fd_monitor_to_client = -1; 19 | 20 | static INTERNAL client_signal _cs = { .module = (uint16_t)-1 }; 21 | 22 | __attribute__((always_inline)) static inline void send_monitor(const client_signal cs) { 23 | monitor_answer ma; 24 | int err = 0; 25 | 26 | WRITE_CLIENT_SIGNAL(_fd_client_to_monitor,cs,err); 27 | if (err) abort(); 28 | 29 | READ_MONITOR_ANSWER(_fd_monitor_to_client,ma,err); 30 | if (err) abort(); 31 | if (ma.event != CFI_OK) abort(); 32 | } 33 | 34 | #if 0 35 | void __CFI_INTERNAL_FORK_SON(uint32_t nFct, uint32_t nModule) { 36 | const char *s = getenv("CFI_FD_1"); 37 | const char *sr = getenv("CFI_FD_R_1"); 38 | char *ptr = NULL; 39 | int ofd = fd; 40 | int ofdr = fd_r; 41 | 42 | if (s == NULL) { 43 | assert(0 && "CFI_FD not set in ENV"); 44 | } else if (sr == NULL) { 45 | assert(0 && "CFI_FD_R not set in ENV"); 46 | } 47 | 48 | fd = strtol(s, &ptr, 10); 49 | assert(ptr != NULL && "CFI_FD bad format"); 50 | fd_r = strtol(sr, &ptr, 10); 51 | assert(ptr != NULL && "CFI_FD_R bad format"); 52 | 53 | unsetenv("CFI_FD"); 54 | unsetenv("CFI_FD_R"); 55 | 56 | bzero(&p, sizeof(p)); 57 | 58 | p.id = FORK_SON; 59 | p.param1 = fd_r; 60 | p.param2 = fd; 61 | 62 | owrite(ofd, (packet *) &p , sizeof(p)); 63 | } 64 | #endif 65 | 66 | void HIDDEN __CFI_SET_FDS(int fd_client_to_monitor, int fd_monitor_to_client) 67 | { 68 | _fd_client_to_monitor = fd_client_to_monitor; 69 | _fd_monitor_to_client = fd_monitor_to_client; 70 | } 71 | 72 | void HIDDEN __CFI_SET_MODULE_ID(uint16_t m_id) 73 | { 74 | _cs.module = m_id; 75 | } 76 | 77 | void HIDDEN __CFI_INTERNAL_ENTER(uint32_t nFct, void * UNUSED retaddr) { 78 | _cs.event = CFI_ENTER; 79 | _cs.function = nFct; 80 | _cs.block = 0; 81 | 82 | send_monitor(_cs); 83 | } 84 | 85 | void HIDDEN __CFI_INTERNAL_EXIT(uint32_t nFct, void * UNUSED retaddr) { 86 | _cs.event = CFI_EXIT; 87 | _cs.function = nFct; 88 | _cs.block = 0; 89 | 90 | send_monitor(_cs); 91 | } 92 | 93 | void HIDDEN __CFI_INTERNAL_CALL(uint32_t nFct) { 94 | _cs.event = CFI_CALL; 95 | _cs.function = nFct; 96 | _cs.block = 0; 97 | 98 | send_monitor(_cs); 99 | } 100 | 101 | void HIDDEN __CFI_INTERNAL_RETURNED(uint32_t nFct) { 102 | _cs.event = CFI_RETURNED; 103 | _cs.function = nFct; 104 | _cs.block = 0; 105 | 106 | send_monitor(_cs); 107 | } 108 | 109 | void HIDDEN __CFI_INTERNAL_BB_BEFORE_BR(uint32_t f_id, uint32_t idBB) { 110 | _cs.event = CFI_BEFORE_JUMP; 111 | _cs.function = f_id; 112 | _cs.block = idBB; 113 | 114 | send_monitor(_cs); 115 | } 116 | 117 | void HIDDEN __CFI_INTERNAL_BB_AFTER_BR(uint32_t f_id, uint32_t idBB) { 118 | _cs.event = CFI_AFTER_JUMP; 119 | _cs.function = f_id; 120 | _cs.block = idBB; 121 | 122 | send_monitor(_cs); 123 | } 124 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFI.hh: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015-2017 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #ifndef CFI_H__ 20 | # define CFI_H__ 21 | 22 | #include 23 | #include 24 | 25 | #include "llvm/IR/Constants.h" 26 | #include "llvm/IR/Function.h" 27 | #include "llvm/IR/GlobalVariable.h" 28 | #include "llvm/IR/Instructions.h" 29 | #include "llvm/IR/InstIterator.h" 30 | #include "llvm/IR/Intrinsics.h" 31 | #include "llvm/IR/IntrinsicInst.h" 32 | #include "llvm/IR/Module.h" 33 | #include "llvm/ADT/StringMap.h" 34 | #include "llvm/ADT/StringSet.h" 35 | 36 | #include "llvm/Pass.h" 37 | 38 | #include "llvm/Support/CommandLine.h" 39 | #include "llvm/Support/raw_ostream.h" 40 | 41 | #include "DebugPrintRT.hh" 42 | #include "CFIModulePass.hh" 43 | 44 | using namespace llvm; 45 | 46 | class CFIModulePass; 47 | class ControlFlowIntegrity; 48 | 49 | #define ANNOTATION_IGNORE_BLOCK "cfi_ignore_blocks\00" 50 | 51 | struct CFIFct { 52 | llvm::Function* fun; 53 | uint32_t id; 54 | std::map bb_map; 55 | }; 56 | 57 | class ControlFlowIntegrity { 58 | 59 | public: 60 | ControlFlowIntegrity(Module &M, const std::string& execName, 61 | const std::string& ipdom, 62 | const std::string& trans_table_file, 63 | const std::string& trans_tablebb_file, 64 | const std::string& ignoredFctF); 65 | 66 | void ParseAnnotations(void); 67 | 68 | bool isIgnoredFunction(const std::string &fName); 69 | bool isInitFunction(const std::string &fName); 70 | bool isFiniFunction(const std::string &fName); 71 | bool isIgnoredBlocksFunction(const std::string &fName); 72 | 73 | void writeFunctionIDs(void); 74 | 75 | void writeTransToFile(int granlvl); 76 | void writeCallgraph(std::fstream &fs); 77 | void writeAllowedBBTrans(std::fstream &fs); 78 | void writeIPDOMToFile(CFIModulePass* cfi); 79 | 80 | int IdentifyFunction(const Function& F); 81 | int AddIdentifiedFunction(const std::string name, uint32_t id); 82 | bool HasAlreadyBeenIdentified_id(const Function& F); 83 | int getIdentifier(Function *F); 84 | void IdentifyFunctions(void); 85 | void PatchCtorFunctions(void); 86 | void PatchDtorFunctions(void); 87 | 88 | void IdentifyBB(void); 89 | 90 | public: 91 | llvm::StringMap::iterator fun_map_begin() { return _FunctionMap.begin(); } 92 | llvm::StringMap::iterator fun_map_end() { return _FunctionMap.end(); } 93 | 94 | private: 95 | Module& _M; 96 | llvm::StringMap _FunctionMap; 97 | //! _IdentifiedFunctions contains *all* known (local) functions and IDs, even from other files of the same binary 98 | llvm::StringMap _IdentifiedFunctions; 99 | llvm::StringSet<> _IgnoredFunctions; 100 | llvm::StringSet<> _InitFunctions; 101 | llvm::StringSet<> _FiniFunctions; 102 | llvm::StringSet<> _IgnoredBlocksFunctions; 103 | std::string _fun_id_file; 104 | std::string _transTableFile; 105 | std::string _transTableBBFile; 106 | std::string _IgnoredFctFileName; 107 | std::string _ipdom_file; 108 | 109 | uint32_t _fun_id_ctr; 110 | }; 111 | 112 | #endif // ! CFI_H__ 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PICON 2 | 3 | ## Overview 4 | 5 | Picon is an implementation of Control Flow Integrity protection made 6 | of two parts. The first part is a standalone program, called 7 | picon-monitor, that monitors program execution to ensure the integrity 8 | of its execution flow according to its expected control flow 9 | integrity. The last part is a LLVM compiler pass to instrument a 10 | program to be monitored in order to inject communication routines and 11 | message exchanges with the external picon-monitor. 12 | 13 | Picon has been published in SSTIC 2015. Article, video and slides are 14 | [available here](https://www.sstic.org/2015/presentation/control_flow_integrity_on_llvm_ir/) 15 | 16 | ## Prerequisites 17 | 18 | A working LLVM installation (either installed from LLVM sources, or 19 | from the packages of a Linux distribution) is required to build the 20 | LLVM pass. A C compiler is required to build the monitor. Clang is 21 | also used to build examples, and Python to run the prelink script. 22 | 23 | The current code has been developed and tested against 24 | version 3.8. More recent versions are expected to work, but may 25 | require some changes to match the changes in LLVM API. 26 | 27 | ## Building the project 28 | 29 | The toplevel `Makefile` can be used to build the LLVM pass and the 30 | monitor. Run `make` to build the projects. 31 | 32 | The following files can be edited to change or set options: 33 | 34 | * `Makefile`: 35 | * Name of the `llvm-config` and `opt` tools (with versions if 36 | needed) 37 | * `monitor/Makefile`: 38 | * `TIMEOUT`: if set, enables the timeout feature of the monitor, 39 | that is the maximum delay before the monitor kills the program 40 | if no signal is received; in this case the variables 41 | `TIMEOUT_SEC_MONITOR_NO_SIGNAL` and 42 | `TIMEOUT_NANOSEC_MONITOR_NO_SIGNAL` must also be set (see 43 | `struct timespec` in `man 2 nanosleep`) 44 | * `NB_PRELOADED_MONITOR_OK_ANSWERS=`: preload `n` answers in 45 | the monitor answer pipe, that is the number of signals the 46 | program will send and be able to continue processing in parallel 47 | (i.e. control flow integrity checks in the monitor are 48 | desynchronized by exactly `n` signals) 49 | * `SILENT` : if set, no output (debug or error) is produced by the 50 | monitor, even in case of compromission of control flow integrity 51 | of the monitored program 52 | * `CFI_DEBUG` : if set, the monitor will display (a lot of) debug 53 | output 54 | 55 | ## Usage 56 | 57 | The overall process is: 58 | 59 | * build each source file into LLVM bitcode, using `clang -emit-llvm` 60 | * run the Picon LLVM pass on each bitcode file, to produced the 61 | processed bitcode file, and the temporary Picon files 62 | * run `picon-prelink` on the temporary picon files to produce the 63 | injected source code 64 | * build the injected source code, and all processed bitcode files to 65 | object files 66 | * link all object files (including the injected code) 67 | 68 | The resulting binary *must* be executed by the Picon monitor. 69 | 70 | As depicted in `examples/unit_tests/Makefile.cfi`, the Picon LLVM pass 71 | requires several options: 72 | 73 | * `-cfi` instructs the `opt` tool to actually pass through the Picon 74 | instrumentation 75 | * `-cfi-prefix=`: path + basename of all files produced 76 | by the LLVM pass. LLVM must have the permission to write files in this 77 | path, and the same path and basename options must be used for all 78 | files built that will be part of the same binary (shared library or 79 | executable) 80 | * `-cfi-level=[0|1]` defines the level of instrumentation/protection 81 | * 0 : protection of functions calls only 82 | * 1 : protection of functions calls and basic blocks transitions 83 | * `-cfi-ignore=` gives a list of function names (one per line) 84 | which were not been instrumented/protected with Picon LLVM pass and 85 | for which functions calls cannot be protected 86 | 87 | The LLVM pass is an incremental process: files produced using the 88 | `-cfi-prefix` option are read and updated by each compilation. These 89 | files must be deleted when cleaning the project, to ensure that a 90 | rebuild will work properly. 91 | 92 | After the compilation of all source files of a project, the files 93 | produced by the `-cfi-prefix` option must be analyzed before linking the 94 | binary. This is done by the `picon-prelink` script, which takes the 95 | `path/basename` option as argument. 96 | `picon-prelink` parses the files and will produced a source file in its 97 | standard output, containing the structures and code required by the 98 | Picon monitor at runtime. This source file must be compiled, and 99 | included in the link process of the binary. 100 | 101 | 102 | ## Examples 103 | 104 | The examples can be built by running `make` in the `examples` 105 | directory, after building and installing the main project. 106 | 107 | Note that some examples are expected to fail. 108 | 109 | The example file `unit_tests/src/test_no_basic_blocks.c` shows how to 110 | suspend basic blocks transitions in a given function using the 111 | `CFI_IGNORE_BASIC_BLOCKS` directive (declared in `picon/picon.h`). 112 | 113 | ## Authors 114 | 115 | Picon has been developed by the following authors: 116 | 117 | * Pierre Chifflier 118 | * Thomas Coudray 119 | * Arnaud Fontaine 120 | 121 | ## License 122 | 123 | Picon is licensed under the GNU Lesser General Public License, 124 | version 2.1 or (at your option) any later version. As such, it is 125 | provided without any warranty, and in the hope that it will be useful. 126 | 127 | -------------------------------------------------------------------------------- /monitor/src/main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "defs.h" 20 | #include "monitor_load.h" 21 | #include "monitor_run.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | 34 | static 35 | int mask_sigpipe() { 36 | struct sigaction sa; 37 | sa.sa_handler = SIG_IGN; 38 | sa.sa_flags = 0; 39 | return sigaction(SIGPIPE, &sa, 0); 40 | } 41 | 42 | 43 | 44 | int main (int argc, char *argv[]) { 45 | char buffer[128]; 46 | int fd_client_to_monitor[2]; 47 | int fd_monitor_to_client[2]; 48 | int fd_loading_to_monitor[2]; 49 | int fd_monitor_to_loading[2]; 50 | 51 | pid_t child_pid; 52 | 53 | unsigned int err = 0; 54 | monitor_data data; 55 | 56 | if(getenv("LD_PRELOAD")) { 57 | LOG_ERROR_MONITOR("LD_PRELOAD detected, aborting\n"); 58 | return -1; 59 | } 60 | 61 | if((getenv(ENV_FD_CLIENT_TO_MONITOR)) || 62 | (getenv(ENV_FD_MONITOR_TO_CLIENT)) || 63 | (getenv(ENV_FD_LOADING_TO_MONITOR)) || 64 | (getenv(ENV_FD_MONITOR_TO_LOADING))) { 65 | LOG_ERROR_MONITOR("inception of monitored programs is not supported\n"); 66 | return -1; 67 | } 68 | 69 | if(argc < 2) { 70 | LOG_ERROR_MONITOR("usage: %s prog [prog_args ...]\n", argv[0]); 71 | return -2; 72 | } 73 | 74 | if(getenv(ENV_SM_TRACE)) { 75 | LOG_DEBUG_MONITOR("%s set, so we are keeping traces\n", ENV_SM_TRACE); 76 | OPTION_sm_trace = 1; 77 | } 78 | 79 | if(getenv(ENV_SM_DUMP)) { 80 | OPTION_sm_dump = 1; 81 | } 82 | 83 | if(pipe2(fd_client_to_monitor, O_DIRECT)) { 84 | LOG_ERROR_MONITOR("failed to create client to monitor pipe : %s\n", strerror(errno)); 85 | return -3; 86 | } 87 | 88 | if(pipe2(fd_monitor_to_client, O_DIRECT)) { 89 | LOG_ERROR_MONITOR("failed to create monitor to client pipe : %s\n", strerror(errno)); 90 | return -3; 91 | } 92 | 93 | if(pipe2(fd_loading_to_monitor, O_DIRECT)) { 94 | LOG_ERROR_MONITOR("failed to create loading to monitor pipe : %s\n", strerror(errno)); 95 | return -3; 96 | } 97 | 98 | if(pipe2(fd_monitor_to_loading, O_DIRECT)) { 99 | LOG_ERROR_MONITOR("failed to create monitor to loading pipe : %s\n", strerror(errno)); 100 | return -3; 101 | } 102 | 103 | 104 | LOG_DEBUG_MONITOR("forking\n"); 105 | 106 | if((child_pid = fork()) > 0) { 107 | /* monitor process */ 108 | close(fd_client_to_monitor[1]); 109 | close(fd_monitor_to_client[0]); 110 | close(fd_loading_to_monitor[1]); 111 | close(fd_monitor_to_loading[0]); 112 | 113 | if((err = mask_sigpipe())) { 114 | LOG_ERROR_MONITOR("cannot mask SIGPIPE\n"); 115 | } else if((err = monitor_load(child_pid, 116 | fd_client_to_monitor[0], 117 | fd_monitor_to_client[1], 118 | fd_loading_to_monitor[0], 119 | fd_monitor_to_loading[1], 120 | &data))) { 121 | LOG_ERROR_MONITOR("failed to load monitor data\n"); 122 | } else { 123 | 124 | if(OPTION_nb_preload_monitor_ok_answers > 0) { 125 | const monitor_answer ok_resp = { .event = CFI_OK }; 126 | unsigned int i = 0; 127 | LOG_DEBUG_MONITOR("preloading %u OK answers\n", OPTION_nb_preload_monitor_ok_answers); 128 | while((i < OPTION_nb_preload_monitor_ok_answers) && !err) { 129 | WRITE_MONITOR_ANSWER(data.fd_monitor_to_client, ok_resp, err); 130 | ++i; 131 | } 132 | } 133 | 134 | LOG_DEBUG_MONITOR("main loop\n"); 135 | err = monitor_run(data); 136 | if(!err) { 137 | unsigned int i; 138 | unsigned int nb = 0; 139 | for(i = 0; i < data.nb_modules; ++i) { 140 | nb += data.modules[i].nb_entrypoint_finis; 141 | } 142 | i = 0; 143 | LOG_DEBUG_MONITOR("%u finis are expected\n", nb); 144 | while((i < nb) && !err) { 145 | err = monitor_run(data); 146 | ++i; 147 | } 148 | } 149 | } 150 | 151 | LOG_DEBUG_MONITOR("exits with status = %i\n", err); 152 | 153 | if(err) { 154 | LOG_DEBUG_MONITOR("killing client\n"); 155 | kill(child_pid, SIGKILL); 156 | } 157 | 158 | monitor_data_free(&data); 159 | 160 | return err; 161 | 162 | } else if(child_pid == 0) { 163 | 164 | /* client process */ 165 | close(fd_client_to_monitor[0]); 166 | close(fd_monitor_to_client[1]); 167 | close(fd_loading_to_monitor[0]); 168 | close(fd_monitor_to_loading[1]); 169 | 170 | snprintf(buffer, sizeof(buffer), "%u", fd_client_to_monitor[1]); 171 | setenv(ENV_FD_CLIENT_TO_MONITOR, buffer, 1); 172 | 173 | snprintf(buffer, sizeof(buffer), "%u", fd_monitor_to_client[0]); 174 | setenv(ENV_FD_MONITOR_TO_CLIENT, buffer, 1); 175 | 176 | snprintf(buffer, sizeof(buffer), "%u", fd_loading_to_monitor[1]); 177 | setenv(ENV_FD_LOADING_TO_MONITOR, buffer, 1); 178 | 179 | snprintf(buffer, sizeof(buffer), "%u", fd_monitor_to_loading[0]); 180 | setenv(ENV_FD_MONITOR_TO_LOADING, buffer, 1); 181 | 182 | LOG_DEBUG_CLIENT("exec\n"); 183 | ++argv; 184 | (void)execve(argv[0], argv, environ); 185 | 186 | LOG_ERROR_MONITOR("failed to exec : %s\n", strerror(errno)); 187 | return -4; 188 | } 189 | 190 | /* error during fork */ 191 | LOG_ERROR_MONITOR("failed to fork : %s\n", strerror(errno)); 192 | return -5; 193 | } 194 | -------------------------------------------------------------------------------- /monitor/src/monitor_run.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "defs.h" 20 | #include "call_stack.h" 21 | #include "block_stack.h" 22 | 23 | #include "monitor_load.h" 24 | #include "monitor_run.h" 25 | 26 | #include 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | int monitor_run(const monitor_data data) { 37 | 38 | register monitor_state_t state; 39 | register module_id current_module = 0; 40 | register function_id current_function = 0; 41 | register block_stack_element curblock = 0; 42 | register const module_data *current_module_data = NULL; 43 | register const function_data *current_function_data = NULL; 44 | 45 | unsigned int error; 46 | call_stack calls; 47 | block_stack blocks; 48 | 49 | block_stack_element topblock = curblock; 50 | 51 | call_stack_element ncall; 52 | 53 | #ifdef TIMEOUT 54 | fd_set fdrs; 55 | #endif 56 | 57 | client_signal sig; 58 | const monitor_answer ok_resp = { .event = CFI_OK }; 59 | 60 | LOG_DEBUG_MONITOR("entering monitor_run loop\n"); 61 | 62 | state = SM_STATE_Ready; 63 | error = 0; 64 | 65 | if(call_stack_init(&calls)) { 66 | return 1; 67 | } 68 | if(block_stack_init(&blocks)) { 69 | call_stack_free(&calls); 70 | return 1; 71 | } 72 | 73 | MONITOR_SIGNAL_FDRS(data.fd_client_to_monitor, fdrs); 74 | 75 | MONITOR_SIGNAL_TIMEOUT(data.fd_client_to_monitor, fdrs, error); 76 | if(unlikely(error)) { 77 | LOG_ERROR_MONITOR("timeout waiting for client signal\n"); 78 | goto monitor_run_exit; 79 | } 80 | READ_CLIENT_SIGNAL(data.fd_client_to_monitor, sig, error); 81 | 82 | while(1) { 83 | 84 | switch(sig.event) { 85 | 86 | case CFI_BEFORE_JUMP: /**/ 87 | LOG_DEBUG_MONITOR("received BEFORE_JUMP (%u,%u,%u)\n", sig.module, sig.function, sig.block); 88 | if(unlikely((state != SM_STATE_InFunction) || 89 | (current_module != sig.module) || 90 | (current_function != sig.function) || 91 | (curblock != sig.block))) { 92 | error = 4; 93 | goto monitor_run_exit; 94 | } 95 | state = SM_STATE_ExpectJump; 96 | break; 97 | 98 | 99 | case CFI_AFTER_JUMP: /**/ 100 | LOG_DEBUG_MONITOR("received AFTER_JUMP (%u,%u,%u)\n", sig.module, sig.function, sig.block); 101 | if(unlikely((state != SM_STATE_ExpectJump) || 102 | (current_module != sig.module) || 103 | (current_function != sig.function) || 104 | (sig.block >= current_function_data->nb_blocks) || 105 | (!(current_function_data->control_flow_graph[curblock][sig.block])))) { 106 | error = 4; 107 | goto monitor_run_exit; 108 | } 109 | if(unlikely(OPTION_sm_trace && 110 | (current_function_data->immediate_post_dominator[topblock] == sig.block))) { 111 | BLOCK_STACK_PUSH(blocks, topblock, error); 112 | topblock = sig.block; 113 | } 114 | curblock = sig.block; 115 | state = SM_STATE_InFunction; 116 | break; 117 | 118 | 119 | case CFI_CALL: /**/ 120 | LOG_DEBUG_MONITOR("received CALL (%u,%u)\n", sig.module, sig.function); 121 | if(unlikely((state != SM_STATE_InFunction) || 122 | (sig.function >= current_module_data->nb_functions) || 123 | (!(current_module_data->call_graph[current_function][sig.function])))) { 124 | error = 4; 125 | goto monitor_run_exit; 126 | } 127 | if(unlikely(OPTION_sm_trace)) { 128 | BLOCK_STACK_PUSH(blocks, topblock, error); 129 | } 130 | BLOCK_STACK_PUSH(blocks, curblock, error); 131 | curblock = topblock = FUNCTION_ENTRY_BLOCK_ID; 132 | ncall = (call_stack_element) 133 | { 134 | .module = current_module, 135 | .function = current_function, 136 | .blocks_sp = BLOCK_STACK_TOP_PTR(blocks) 137 | }; 138 | CALL_STACK_PUSH(calls, ncall, error); 139 | if(FUNCTION_IS_EXTERNAL(current_module_data->functions[sig.function])) { 140 | const module_function_ids some_reloc = current_module_data->relocations[sig.function]; 141 | LOG_DEBUG_MONITOR("\trelocated CALL (%u,%u)\n", MODULE_FUNCTION_GET_MODULE(some_reloc), MODULE_FUNCTION_GET_FUNCTION(some_reloc)); 142 | current_module = MODULE_FUNCTION_GET_MODULE(some_reloc); 143 | current_function = MODULE_FUNCTION_GET_FUNCTION(some_reloc); 144 | current_module_data = &(data.modules[current_module]); 145 | } else { 146 | current_function = sig.function; 147 | } 148 | current_function_data = &(current_module_data->functions[current_function]); 149 | state = SM_STATE_ExpectCall; 150 | break; 151 | 152 | 153 | case CFI_ENTER: /**/ 154 | LOG_DEBUG_MONITOR("received ENTER (%u,%u)\n", sig.module, sig.function); 155 | if(unlikely(state == SM_STATE_Ready)) { 156 | if(unlikely(sig.module >= data.nb_modules)) { 157 | error = 6; 158 | goto monitor_run_exit; 159 | } 160 | current_module_data = &(data.modules[sig.module]); 161 | if(unlikely((sig.function >= current_module_data->nb_functions) || 162 | (!FUNCTION_IS_ENTRYPOINT(current_module_data->functions[sig.function])))) { 163 | error = 7; 164 | goto monitor_run_exit; 165 | } else { 166 | curblock = topblock = FUNCTION_ENTRY_BLOCK_ID; 167 | current_module = sig.module; 168 | current_function = sig.function; 169 | current_function_data = &(current_module_data->functions[sig.function]); 170 | } 171 | } else if(unlikely((state != SM_STATE_ExpectCall) || 172 | (current_module != sig.module) || 173 | (current_function != sig.function) || 174 | (curblock != FUNCTION_ENTRY_BLOCK_ID))) { 175 | error = 4; 176 | goto monitor_run_exit; 177 | } 178 | state = SM_STATE_InFunction; 179 | break; 180 | 181 | 182 | case CFI_EXIT: /**/ 183 | LOG_DEBUG_MONITOR("received EXIT (%u,%u)\n", sig.module, sig.function); 184 | if(unlikely((state != SM_STATE_InFunction) || 185 | (current_module != sig.module) || 186 | (current_function != sig.function))) { 187 | error = 4; 188 | goto monitor_run_exit; 189 | } 190 | if(unlikely(CALL_STACK_IS_EMPTY(calls))) { 191 | if(unlikely(!FUNCTION_IS_ENTRYPOINT(current_module_data->functions[current_function]))) { 192 | error = 7; 193 | goto monitor_run_exit; 194 | } 195 | state = SM_STATE_Ready; 196 | /* simplify this case since unlikely */ 197 | WRITE_MONITOR_ANSWER(data.fd_monitor_to_client, ok_resp, error); 198 | goto monitor_run_exit; 199 | /**/ 200 | } else { 201 | CALL_STACK_POP(calls, ncall); 202 | current_module = ncall.module; 203 | current_function = ncall.function; 204 | current_module_data = &(data.modules[current_module]); 205 | current_function_data = &(current_module_data->functions[current_function]); 206 | BLOCK_STACK_RESTORE_TOP(blocks, ncall.blocks_sp); 207 | if(unlikely(BLOCK_STACK_IS_EMPTY(blocks))) { 208 | error = 7; 209 | goto monitor_run_exit; 210 | } 211 | BLOCK_STACK_POP(blocks, curblock); 212 | if(unlikely(OPTION_sm_trace)) { 213 | BLOCK_STACK_POP(blocks, topblock); 214 | } 215 | state = SM_STATE_ExpectReturn; 216 | } 217 | break; 218 | 219 | 220 | case CFI_RETURNED: /**/ 221 | LOG_DEBUG_MONITOR("received RETURNED (%u,%u)\n", sig.module, sig.function); 222 | if(unlikely((state != SM_STATE_ExpectReturn) || 223 | (sig.function >= current_module_data->nb_functions) || 224 | (!(current_module_data->call_graph[current_function][sig.function])))) { 225 | error = 4; 226 | goto monitor_run_exit; 227 | } 228 | state = SM_STATE_InFunction; 229 | break; 230 | 231 | 232 | default: 233 | LOG_ERROR_MONITOR("malformed sig received\n"); 234 | error = 5; 235 | goto monitor_run_exit; 236 | } 237 | 238 | WRITE_MONITOR_ANSWER(data.fd_monitor_to_client, ok_resp, error); 239 | 240 | MONITOR_SIGNAL_TIMEOUT(data.fd_client_to_monitor, fdrs, error); 241 | if(unlikely(error)) { 242 | LOG_ERROR_MONITOR("timeout waiting for client signal\n"); 243 | goto monitor_run_exit; 244 | } 245 | READ_CLIENT_SIGNAL(data.fd_client_to_monitor, sig, error); 246 | } 247 | 248 | 249 | monitor_run_exit: 250 | if(error) { 251 | LOG_ERROR_MONITOR("run failed with error = %u\n", error); 252 | if(OPTION_sm_trace) { 253 | unsigned int err = 0; 254 | BLOCK_STACK_PUSH(blocks, curblock, err); 255 | ncall = (call_stack_element) 256 | { 257 | .module = current_module, 258 | .function = current_function, 259 | .blocks_sp = BLOCK_STACK_TOP_PTR(blocks) 260 | }; 261 | CALL_STACK_PUSH(calls, ncall, err); 262 | 263 | call_stack_trace(&calls); 264 | block_stack_trace(&blocks); 265 | 266 | BLOCK_STACK_POP(blocks, curblock); 267 | CALL_STACK_POP(calls, ncall); 268 | } 269 | } 270 | 271 | call_stack_free(&calls); 272 | block_stack_free(&blocks); 273 | 274 | return error; 275 | } 276 | -------------------------------------------------------------------------------- /include/picon/shared.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHARED_H__ 2 | #define __SHARED_H__ 3 | 4 | 5 | 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | 12 | 13 | 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | 21 | 22 | 23 | #define likely(x) __builtin_expect(!!(x), 1) 24 | #define unlikely(x) __builtin_expect(!!(x), 0) 25 | 26 | 27 | 28 | 29 | 30 | #define ENV_FD_MONITOR_TO_LOADING "CFI_MONITOR_TO_LOADING" 31 | #define ENV_FD_LOADING_TO_MONITOR "CFI_LOADING_TO_MONITOR" 32 | #define ENV_FD_CLIENT_TO_MONITOR "CFI_CLIENT_TO_MONITOR" 33 | #define ENV_FD_MONITOR_TO_CLIENT "CFI_MONITOR_TO_CLIENT" 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | typedef enum { 45 | CFI_BEFORE_JUMP, 46 | CFI_AFTER_JUMP, 47 | CFI_CALL, 48 | CFI_ENTER, 49 | CFI_EXIT, 50 | CFI_RETURNED, 51 | } client_event; 52 | 53 | 54 | 55 | typedef uint16_t module_id; 56 | typedef uint32_t function_id; 57 | typedef uint32_t block_id; 58 | 59 | 60 | 61 | 62 | typedef uint64_t module_function_ids; 63 | 64 | #define MODULE_FUNCTION_GET_MODULE(r) ((module_id)((r)>>32)) 65 | #define MODULE_FUNCTION_GET_FUNCTION(r) ((function_id)((r) & 0xffffffff)) 66 | 67 | #define MODULE_FUNCTION(m,f) ((((uint64_t)(m)) << 32) | (((uint64_t)(f)) & 0xffffffff)) 68 | 69 | 70 | typedef struct { 71 | client_event event : 8; 72 | module_id module; 73 | function_id function; 74 | block_id block; 75 | } __attribute__((packed)) client_signal; 76 | 77 | 78 | #define READ_CLIENT_SIGNAL(fd,dst,err) \ 79 | do { \ 80 | LOG_DEBUG_MONITOR("waiting for client signal\n"); \ 81 | if(unlikely(read((fd),&(dst),sizeof(client_signal)) != \ 82 | sizeof(client_signal))) { \ 83 | (err) = 1; \ 84 | } \ 85 | } while(0) 86 | 87 | 88 | #define WRITE_CLIENT_SIGNAL(fd,dst,err) \ 89 | do { \ 90 | LOG_DEBUG_CLIENT("sending signal\n"); \ 91 | if(unlikely(write((fd),&(dst),sizeof(client_signal)) != \ 92 | sizeof(client_signal))) { \ 93 | (err) = 1; \ 94 | } \ 95 | } while(0) 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | typedef enum { 107 | CFI_OK = 0x42, 108 | } monitor_event; 109 | 110 | 111 | typedef struct { 112 | monitor_event event : 8; 113 | } __attribute__((packed)) monitor_answer; 114 | 115 | 116 | #define READ_MONITOR_ANSWER(fd,dst,err) \ 117 | do { \ 118 | LOG_DEBUG_CLIENT("waiting for answer\n"); \ 119 | if(unlikely(read((fd),&(dst),sizeof(monitor_answer)) != \ 120 | sizeof(monitor_answer))) { \ 121 | (err) = 1; \ 122 | } \ 123 | } while(0) 124 | 125 | 126 | #define WRITE_MONITOR_ANSWER(fd,dst,err) \ 127 | do { \ 128 | LOG_DEBUG_MONITOR("sending answer\n"); \ 129 | if(unlikely(write((fd),&(dst),sizeof(monitor_answer)) != \ 130 | sizeof(monitor_answer))) { \ 131 | (err) = 1; \ 132 | } \ 133 | } while(0) 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | typedef enum { 144 | FCT_INTERNAL, 145 | FCT_EXTERNAL, 146 | FCT_INIT, 147 | FCT_FINI, 148 | FCT_MAIN, 149 | } fct_flag_t; 150 | 151 | typedef struct { 152 | function_id f_id; 153 | fct_flag_t f_flags; 154 | const char * const f_name; 155 | } __attribute((packed)) fctid_t; 156 | 157 | typedef struct { 158 | function_id id; 159 | uint32_t num_callees; 160 | const char * const callees; 161 | } __attribute((packed)) callgraph_entry_t; 162 | 163 | 164 | 165 | /* PROTOCOL DEFINITION 166 | * for each message, this is the format of the 'value' field of the loading packet 167 | */ 168 | 169 | /* CFI_LOADING_MODULE_BEGIN */ 170 | typedef struct { 171 | uint32_t num_fcts; 172 | } __attribute__((packed)) msg_begin_t; 173 | 174 | /* CFI_LOADING_SECTION_FUNCTION_ID */ 175 | typedef struct { 176 | function_id f_id; 177 | fct_flag_t f_flags; 178 | char f_name[0]; /* NULL-terminated string */ 179 | } __attribute__((packed)) msg_fct_t; 180 | 181 | typedef struct { 182 | uint32_t num_fcts; 183 | msg_fct_t fcts[0]; /* list of (non-fixed size) msg_fct_t */ 184 | } __attribute__((packed)) msg_fct_l; 185 | 186 | /* CFI_LOADING_SECTION_FUNCTION_TRANSITION */ 187 | typedef struct { 188 | function_id f_id; 189 | uint32_t f_num_calls; 190 | function_id f_calls[0]; /* array of size f_num_calls */ 191 | } __attribute__((packed)) msg_fct_trans_t; 192 | 193 | typedef struct { 194 | uint32_t num_fct_trans; 195 | msg_fct_trans_t fct_trans[0]; /* list of (non-fixed size) msg_fct_trans_t */ 196 | } __attribute__((packed)) msg_fct_trans_l; 197 | 198 | /* CFI_LOADING_SECTION_BLOCK_TRANSITION */ 199 | typedef struct { 200 | block_id b_id; 201 | uint32_t b_num_succ; 202 | block_id b_succ[0]; /* array of size b_num_succ */ 203 | } __attribute__((packed)) msg_block_trans_t; 204 | 205 | typedef struct { 206 | function_id f_id; 207 | uint32_t num_block; /* total number of blocks in function */ 208 | uint32_t num_block_trans; /* number of msg_block_trans_t elements */ 209 | msg_block_trans_t block_trans[0]; /* list of (non-fixed size) msg_block_trans_t */ 210 | } __attribute__((packed)) msg_block_trans_l; 211 | 212 | /* CFI_LOADING_SECTION_BLOCK_IPD */ 213 | typedef struct { 214 | function_id f_id; 215 | block_id b_id; 216 | block_id b_ipd_id; 217 | block_id b_last_id; 218 | } __attribute__((packed)) msg_block_ipd_t; 219 | 220 | typedef struct { 221 | uint32_t num_ipd; /* total number of ipd in function */ 222 | msg_block_ipd_t block_ipd[0]; /* list of (non-fixed size) msg_block_ipd_t */ 223 | } __attribute__((packed)) msg_block_ipd_l; 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | typedef enum { 232 | CFI_LOADING_MODULE_BEGIN, 233 | CFI_LOADING_SECTION_FUNCTION_ID, 234 | CFI_LOADING_SECTION_FUNCTION_TRANSITION, 235 | CFI_LOADING_SECTION_BLOCK_TRANSITION, 236 | CFI_LOADING_SECTION_BLOCK_IPD, 237 | CFI_LOADING_MODULE_END, 238 | CFI_LOADING_TERMINATED, 239 | } loading_event; 240 | 241 | typedef union { 242 | msg_begin_t begin; 243 | msg_fct_l fct; 244 | msg_fct_trans_l fct_trans; 245 | msg_block_trans_l block_trans; 246 | msg_block_ipd_l block_ipd; 247 | } loading_packet_value; 248 | 249 | typedef struct { 250 | loading_event event; 251 | uint32_t size; 252 | loading_packet_value *value; 253 | } loading_packet; 254 | 255 | 256 | 257 | #define READ_LOADING_PACKET(fd,dst,err) \ 258 | do { \ 259 | LOG_DEBUG_MONITOR("waiting for loading packet\n"); \ 260 | (dst).size = 0; \ 261 | (dst).value = NULL; \ 262 | if(read((fd),&((dst).event),sizeof(loading_event)) != \ 263 | sizeof(loading_event)) { \ 264 | (err) = 1; \ 265 | } else if(read((fd),&((dst).size),sizeof(uint32_t)) != \ 266 | sizeof(uint32_t)) { \ 267 | (err) = 2; \ 268 | } else if((dst).size == 0) { \ 269 | } else if(((dst).value = calloc((dst).size, sizeof(char))) == NULL) { \ 270 | (err) = 3; \ 271 | } else if(read((fd),(dst).value,(dst).size) != \ 272 | (dst).size) { \ 273 | (dst).size = 0; \ 274 | free((dst).value); \ 275 | (err) = 4; \ 276 | } \ 277 | } while(0) 278 | 279 | 280 | #define FREE_LOADING_PACKET(pkt) \ 281 | do { \ 282 | if((pkt).value) { \ 283 | free((pkt).value); \ 284 | (pkt).value = NULL; \ 285 | } \ 286 | } while(0) 287 | 288 | 289 | #define WRITE_LOADING_PACKET(fd,src,err) \ 290 | do { \ 291 | LOG_DEBUG_CLIENT("sending loading packet (size = %u)\n", (src).size); \ 292 | if(write((fd),&((src).event),sizeof(loading_event)) != \ 293 | sizeof(loading_event)) { \ 294 | (err) = 1; \ 295 | } else if(write((fd),&((src).size),sizeof(uint32_t)) != \ 296 | sizeof(uint32_t)) { \ 297 | (err) = 2; \ 298 | } else if((src).size) { \ 299 | if(write((fd),(src).value,(src).size) != (src).size) { \ 300 | (err) = 3; \ 301 | } \ 302 | } \ 303 | } while(0) 304 | 305 | 306 | 307 | 308 | 309 | 310 | typedef struct { 311 | module_id id; 312 | } monitor_to_loading_packet; 313 | 314 | 315 | #define READ_MONITOR_TO_LOADING_PACKET(fd,dst,err) \ 316 | do { \ 317 | LOG_DEBUG_CLIENT("waiting for monitor to loading packet\n"); \ 318 | if(read((fd),&((dst).id),sizeof(module_id)) != sizeof(module_id)) { \ 319 | (err) = 1; \ 320 | } \ 321 | } while(0) 322 | 323 | #define WRITE_MONITOR_TO_LOADING_PACKET(fd,src,err) \ 324 | do { \ 325 | LOG_DEBUG_MONITOR("sending monitor to loading packet\n"); \ 326 | if(write((fd),&((src).id),sizeof(module_id)) != sizeof(module_id)) { \ 327 | (err) = 1; \ 328 | } \ 329 | } while(0) 330 | 331 | 332 | 333 | 334 | 335 | 336 | #ifdef __cplusplus 337 | } 338 | #endif 339 | 340 | 341 | 342 | 343 | #endif /* __SHARED_H__ */ 344 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFIInjector.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015-2017 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include "CFI.hh" 20 | #include "CFIInjector.hh" 21 | 22 | injectorCFI::injectorCFI(Module &M) 23 | : _M(M), _SavedRetAddr() { 24 | } 25 | 26 | void injectorCFI::injectPrototype(void) { 27 | 28 | // extern pid_t __FORK_WRAPPER(void); 29 | 30 | std::vectorFuncTy_0_args; 31 | 32 | FuncTy_0_args.push_back(IntegerType::get(_M.getContext(), 32)); 33 | FunctionType* FuncTy_0 = FunctionType::get( 34 | IntegerType::get(_M.getContext(), 32), 35 | IntegerType::get(_M.getContext(), 32), 36 | /*isVarArg=*/false); 37 | 38 | Function *func___FORK_WRAPPER = Function::Create( 39 | /*Type=*/FuncTy_0, 40 | /*Linkage=*/GlobalValue::ExternalLinkage, 41 | /*Name=*/"__FORK_WRAPPER", &_M); // (external, no body) 42 | 43 | 44 | // extern void __CFI_INTERNAL_BB_AFTER_BR(uint32_t f_id, uint32_t idBB); 45 | // extern void __CFI_INTERNAL_BB_BEFORE_BR(uint32_t f_id, uint32_t idBB); 46 | 47 | std::vectorFuncTy_1_args; 48 | 49 | FuncTy_1_args.push_back(IntegerType::get(_M.getContext(), 32)); 50 | FuncTy_1_args.push_back(IntegerType::get(_M.getContext(), 32)); 51 | FunctionType* FuncTy_1 = FunctionType::get( 52 | /*Result=*/Type::getVoidTy(_M.getContext()), 53 | /*Params=*/FuncTy_1_args, 54 | /*isVarArg=*/false); 55 | 56 | Function *func___CFI_INTERNAL_BB_AFTER_BR = Function::Create( 57 | /*Type=*/FuncTy_1, 58 | /*Linkage=*/GlobalValue::ExternalLinkage, 59 | /*Name=*/"__CFI_INTERNAL_BB_AFTER_BR", &_M); // (external, no body) 60 | 61 | Function *func___CFI_INTERNAL_BB_BEFORE_BR = Function::Create( 62 | /*Type=*/FuncTy_1, 63 | /*Linkage=*/GlobalValue::ExternalLinkage, 64 | /*Name=*/"__CFI_INTERNAL_BB_BEFORE_BR", &_M); // (external, no body) 65 | 66 | // extern void __CFI_INTERNAL_ENTER(uint32_t IdCurFct, void *retaddr); 67 | // extern void __CFI_INTERNAL_EXIT(uint32_t IdCurFct, void *retaddr); 68 | 69 | PointerType* PointerTy = PointerType::get(IntegerType::get(_M.getContext(), 8), 0); 70 | 71 | std::vector FuncTy_2_args; 72 | FuncTy_2_args.push_back(IntegerType::get(_M.getContext(), 32)); 73 | FuncTy_2_args.push_back(PointerTy); 74 | 75 | FunctionType* FuncTy_2 = FunctionType::get( 76 | /*Result=*/Type::getVoidTy(_M.getContext()), 77 | /*Params=*/FuncTy_2_args, 78 | /*isVarArg=*/false); 79 | 80 | Function* func___CFI_INTERNAL_ENTER = Function::Create( 81 | /*Type=*/FuncTy_2, 82 | /*Linkage=*/GlobalValue::ExternalLinkage, 83 | /*Name=*/"__CFI_INTERNAL_ENTER", &_M); // (external, no body) 84 | 85 | Function* func___CFI_INTERNAL_EXIT = Function::Create( 86 | /*Type=*/FuncTy_2, 87 | /*Linkage=*/GlobalValue::ExternalLinkage, 88 | /*Name=*/"__CFI_INTERNAL_EXIT", &_M); // (external, no body) 89 | 90 | // extern void __CFI_INTERNAL_CALL(uint32_t idFctCalled); 91 | // extern void __CFI_INTERNAL_RETURNED(uint32_t idFctCalled); 92 | // extern void __CFI_INTERNAL_FORK_SON(uint32_t idFctCalled); 93 | 94 | std::vectorFuncTy_3_args; 95 | 96 | FuncTy_3_args.push_back(IntegerType::get(_M.getContext(), 32)); 97 | 98 | FunctionType* FuncTy_3 = FunctionType::get( 99 | /*Result=*/Type::getVoidTy(_M.getContext()), 100 | /*Params=*/FuncTy_3_args, 101 | /*isVarArg=*/false); 102 | 103 | Function *func___CFI_INTERNAL_CALL = Function::Create( 104 | /*Type=*/FuncTy_3, 105 | /*Linkage=*/GlobalValue::ExternalLinkage, 106 | /*Name=*/"__CFI_INTERNAL_CALL", &_M); // (external, no body) 107 | 108 | Function *func___CFI_INTERNAL_RETURNED = Function::Create( 109 | /*Type=*/FuncTy_3, 110 | /*Linkage=*/GlobalValue::ExternalLinkage, 111 | /*Name=*/"__CFI_INTERNAL_RETURNED", &_M); // (external, no body) 112 | 113 | Function *func___CFI_INTERNAL_FORK_SON= Function::Create( 114 | /*Type=*/FuncTy_3, 115 | /*Linkage=*/GlobalValue::ExternalLinkage, 116 | /*Name=*/"__CFI_INTERNAL_FORK_SON", &_M); // (external, no body) 117 | } 118 | 119 | void injectorCFI::injectMentry(Function& F, int FctID) { 120 | Function *retAddrFct = Intrinsic::getDeclaration(&_M, Intrinsic::returnaddress); 121 | Value *Zero = ConstantInt::get(Type::getInt32Ty(_M.getContext()), 0); 122 | Instruction *EntryPos = dyn_cast(F.getEntryBlock().getFirstInsertionPt()); 123 | CallInst *retAddrCall = NULL; 124 | 125 | if (retAddrFct != NULL) { 126 | retAddrCall = CallInst::Create(retAddrFct, Zero, "saved_retaddr_prolog", EntryPos); 127 | _SavedRetAddr = retAddrCall; 128 | } else { 129 | assert(0 && "intrinsic returnaddress not found"); 130 | } 131 | 132 | Function *funcEnter = _M.getFunction("__CFI_INTERNAL_ENTER"); 133 | std::vector Args; 134 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, FctID, true)); 135 | Args.push_back(ID); 136 | Args.push_back(retAddrCall); 137 | 138 | if (funcEnter != NULL) { 139 | CallInst* callfctEnter = CallInst::Create(funcEnter, Args, "", EntryPos); 140 | } else { 141 | assert(0 && "__CFI_INTERNAL_ENTER must be defined"); 142 | } 143 | } 144 | 145 | void injectorCFI::injectMexit(Function &F, int FctID) { 146 | Function *retAddrFct = Intrinsic::getDeclaration(&_M, Intrinsic::returnaddress); 147 | Value *Zero = ConstantInt::get(Type::getInt32Ty(_M.getContext()), 0); 148 | TerminatorInst *ExitPos = NULL; 149 | BasicBlock *Last; 150 | 151 | for (auto &BB : F) { 152 | Last = &BB; 153 | } 154 | 155 | ExitPos = Last->getTerminator(); 156 | CallInst *retAddrCall = NULL; 157 | if (retAddrFct != NULL) { 158 | retAddrCall = CallInst::Create(retAddrFct, Zero, "saved_retaddr_epilog", ExitPos); 159 | } else { 160 | assert(0 && "intrinsic returnaddress not found"); 161 | } 162 | 163 | Function *funcEnter = _M.getFunction("__CFI_INTERNAL_EXIT"); 164 | std::vector Args; 165 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, FctID, true)); 166 | Args.push_back(ID); 167 | Args.push_back(retAddrCall); 168 | 169 | if (funcEnter != NULL) { 170 | CallInst* callfctEnter = CallInst::Create(funcEnter, Args, "", ExitPos); 171 | } else { 172 | assert(0 && "__CFI_INTERNAL_EXIT must be defined"); 173 | } 174 | } 175 | 176 | 177 | void injectorCFI::injectForkSon(Function &F) { 178 | Function *funcforkWrpr = _M.getFunction("__FORK_WRAPPER"); 179 | 180 | for (auto &BB : F) { 181 | for (auto &I : BB) { 182 | if (CallInst* CI = dyn_cast(&I)) { 183 | Function *NF = CI->getCalledFunction(); 184 | if (NF->getName() == "fork") { 185 | std::vector Args; 186 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, 42, true)); 187 | Args.push_back(ID); 188 | CallInst* callfctEnter = CallInst::Create(funcforkWrpr, Args, "", CI); 189 | CI->replaceAllUsesWith(callfctEnter); 190 | CI->eraseFromParent(); 191 | return ; 192 | } 193 | } 194 | } 195 | } 196 | } 197 | 198 | void injectorCFI::injectMcall(ControlFlowIntegrity *cfi, Function &F) { 199 | Instruction *BeforeCall; 200 | Instruction *AfterCall;; 201 | bool insertAfter = false; 202 | Function *NF = NULL; 203 | Function *funcCall = _M.getFunction("__CFI_INTERNAL_CALL"); 204 | Function *funcReturned = _M.getFunction("__CFI_INTERNAL_RETURNED"); 205 | 206 | if (funcCall == NULL) 207 | assert(0 && "__CFI_INTERNAL_CALL must be defined"); 208 | 209 | if (funcReturned == NULL) 210 | assert(0 && "__CFI_INTERNAL_RETURNED must be defined"); 211 | 212 | if (cfi->isIgnoredFunction(F.getName()) == true) { 213 | errs() << "don't inject INTERNAL_CALL & INTERNAL_RETURNED for " << F.getName() << "\n"; 214 | return ; 215 | } 216 | 217 | for (auto &BB : F) { 218 | for (auto &I : BB) { 219 | if (insertAfter == true) { 220 | std::vector Args; 221 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, cfi->getIdentifier(NF), true)); 222 | Args.push_back(ID); 223 | CallInst* callfctEnter = CallInst::Create(funcReturned, Args, "", &I); 224 | insertAfter = false; 225 | } 226 | 227 | if (InvokeInst* _II = dyn_cast(&I)) { 228 | assert(0 && "Invoke not yet implemented"); 229 | } else if (IntrinsicInst * _II = dyn_cast(&I)) { 230 | continue ; 231 | } else if (CallInst* CI = dyn_cast(&I)) { 232 | if (CI->isInlineAsm()) { 233 | errs() << "Picon warning: inline asm detected\n"; 234 | continue; 235 | } 236 | NF = CI->getCalledFunction(); 237 | if (NF == NULL) { 238 | CI->dump(); 239 | report_fatal_error("Called function is NULL", true); 240 | } 241 | if (cfi->isIgnoredFunction(NF->getName()) == true) { 242 | continue ; 243 | } 244 | std::vector Args; 245 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, cfi->getIdentifier(NF), true)); 246 | Args.push_back(ID); 247 | CallInst* callfctEnter = CallInst::Create(funcCall, Args, "", CI); 248 | insertAfter = true; 249 | } 250 | } 251 | } 252 | } 253 | 254 | void injectorCFI::injectBBEnter(ControlFlowIntegrity *cfi, Function &F) { 255 | Function *funcBBEnter = _M.getFunction("__CFI_INTERNAL_BB_AFTER_BR"); 256 | unsigned int idBB = 0; 257 | 258 | if (funcBBEnter == NULL) 259 | assert(0 && "__CFI_INTERNAL_BB_AFTER_BR must be defined"); 260 | 261 | // n'injecte pas si le BB est le premier BB de la fonction 262 | for (auto &BB : F) { 263 | if (&BB == F.begin()) { 264 | ++idBB; 265 | continue ; 266 | } 267 | std::vector Args; 268 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, cfi->getIdentifier(&F), true)); 269 | Args.push_back(ID); 270 | ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, idBB, true)); 271 | Args.push_back(ID); 272 | CallInst* callfctBBEnter = CallInst::Create(funcBBEnter, Args, "", BB.getFirstNonPHIOrDbg()); 273 | ++idBB; 274 | } 275 | } 276 | 277 | void injectorCFI::injectBBLeave(ControlFlowIntegrity *cfi, Function &F) { 278 | Function *funcBBLeave = _M.getFunction("__CFI_INTERNAL_BB_BEFORE_BR"); 279 | unsigned int idBB = 0; 280 | 281 | if (funcBBLeave == NULL) 282 | assert(0 && "__CFI_INTERNAL_BB_BEFORE_BR must be defined"); 283 | // injecte avant chaque instructions terminator 284 | // (ret, br, switch, indirectbr, invoke, resume, unreachable) la fonction 285 | // avec aucun parametre, afin de notifier le moniteur du nouvel état. 286 | // (a.k.a: attente d'un BBEnter) 287 | 288 | // n'injecte pas si le BB est le dernier BB de la fonction 289 | for (auto &BB : F) { 290 | if (&BB == &F.back()) { 291 | break ; 292 | } 293 | std::vector Args; 294 | Value *ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, cfi->getIdentifier(&F), true)); 295 | Args.push_back(ID); 296 | ID = llvm::ConstantInt::get(_M.getContext(), llvm::APInt(32, idBB, true)); 297 | Args.push_back(ID); 298 | CallInst *callfctBBLeave = CallInst::Create(funcBBLeave, Args, "", BB.getTerminator()); 299 | ++idBB; 300 | } 301 | } 302 | 303 | void injectorCFI::InjectCode(ControlFlowIntegrity *cfi, int level) { 304 | 305 | injectPrototype(); 306 | 307 | for (auto it = cfi->fun_map_begin(); it!=cfi->fun_map_end(); it++) { 308 | 309 | llvm::Function &F = *(it->getValue().fun); 310 | uint32_t id = it->getValue().id; 311 | 312 | injectMcall(cfi, F); 313 | if (F.isDeclaration()) 314 | continue ; 315 | if (level == BASICBLOCK && 316 | !cfi->isIgnoredBlocksFunction(F.getName())) 317 | { 318 | 319 | injectBBEnter(cfi, F); 320 | injectBBLeave(cfi, F); 321 | } 322 | injectMentry(F, id); 323 | injectMexit(F, id); 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /prelink/picon-prelink: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 ANSSI 3 | # 4 | # This file is part of the Picon project. 5 | # 6 | # This file is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public 8 | # License as published by the Free Software Foundation; either 9 | # version 2.1 of the License, or (at your option) any later version. 10 | # 11 | # This file is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this file; if not, see 18 | # . 19 | 20 | import os 21 | import re 22 | import struct 23 | import sys 24 | import array 25 | 26 | INIT_NAME = "_init_cfi" 27 | INIT_WRAPPER_NAME = "_init_wrapper" 28 | FINI_NAME = "_fini_cfi" 29 | FINI_WRAPPER_NAME = "_fini_wrapper" 30 | 31 | TEMPLATE_HEADER = """ 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | void __CFI_SET_FDS(int fd_client_to_monitor, int fd_monitor_to_client); 40 | void __CFI_SET_MODULE_ID(uint16_t m_id); 41 | 42 | typedef struct { 43 | uint32_t len; 44 | const char * const data; 45 | } __attribute__((packed)) data_t; 46 | 47 | """ 48 | 49 | TEMPLATE_MAIN = """ 50 | int fd_loading_to_monitor; 51 | int fd_monitor_to_loading; 52 | int fd_client_to_monitor; 53 | int fd_monitor_to_client; 54 | int err = 0; 55 | loading_packet pkt; 56 | monitor_to_loading_packet m2l_pkt; 57 | char *ptr = NULL, *s; 58 | 59 | s = getenv(ENV_FD_LOADING_TO_MONITOR); 60 | assert(s != NULL && "ENV_FD_LOADING_TO_MONITOR not set"); 61 | fd_loading_to_monitor = strtol(s, &ptr, 10); 62 | assert(ptr != NULL && "invalid ENV_FD_LOADING_TO_MONITOR"); 63 | if (fd_loading_to_monitor < 0) abort(); 64 | 65 | s = getenv(ENV_FD_MONITOR_TO_LOADING); 66 | assert(s != NULL && "ENV_FD_MONITOR_TO_LOADING not set"); 67 | fd_monitor_to_loading = strtol(s, &ptr, 10); 68 | assert(ptr != NULL && "invalid ENV_FD_MONITOR_TO_LOADING"); 69 | if (fd_monitor_to_loading < 0) abort(); 70 | 71 | s = getenv(ENV_FD_CLIENT_TO_MONITOR); 72 | assert(s != NULL && "ENV_FD_CLIENT_TO_MONITOR not set"); 73 | fd_client_to_monitor = strtol(s, &ptr, 10); 74 | assert(ptr != NULL && "invalid ENV_FD_CLIENT_TO_MONITOR"); 75 | if (fd_client_to_monitor < 0) abort(); 76 | 77 | s = getenv(ENV_FD_MONITOR_TO_CLIENT); 78 | assert(s != NULL && "ENV_FD_MONITOR_TO_CLIENT not set"); 79 | fd_monitor_to_client = strtol(s, &ptr, 10); 80 | assert(ptr != NULL && "invalid ENV_FD_MONITOR_TO_CLIENT"); 81 | if (fd_monitor_to_client < 0) abort(); 82 | 83 | __CFI_SET_FDS(fd_client_to_monitor, fd_monitor_to_client); 84 | 85 | pkt.event=CFI_LOADING_MODULE_BEGIN; 86 | pkt.size=sizeof(_s_cfi); 87 | pkt.value=(loading_packet_value*)_s_cfi; 88 | WRITE_LOADING_PACKET(fd_loading_to_monitor,pkt,err); 89 | if (err) abort(); 90 | 91 | READ_MONITOR_TO_LOADING_PACKET(fd_monitor_to_loading,m2l_pkt,err); 92 | if (err) abort(); 93 | 94 | __CFI_SET_MODULE_ID(m2l_pkt.id); 95 | 96 | pkt.event=CFI_LOADING_SECTION_FUNCTION_ID; 97 | pkt.size=sizeof(_s_fctids); 98 | pkt.value=(loading_packet_value*)_s_fctids; 99 | WRITE_LOADING_PACKET(fd_loading_to_monitor,pkt,err); 100 | if (err) abort(); 101 | 102 | pkt.event=CFI_LOADING_SECTION_FUNCTION_TRANSITION; 103 | pkt.size=sizeof(_s_callgraph); 104 | pkt.value=(loading_packet_value*)_s_callgraph; 105 | WRITE_LOADING_PACKET(fd_loading_to_monitor,pkt,err); 106 | if (err) abort(); 107 | 108 | 109 | """ 110 | 111 | TEMPLATE_MAIN_TERMINATED = """ 112 | 113 | pkt.event=CFI_LOADING_TERMINATED; 114 | pkt.size=0; 115 | pkt.value=NULL; 116 | WRITE_LOADING_PACKET(fd_loading_to_monitor,pkt,err); 117 | if (err) abort(); 118 | """ 119 | 120 | TEMPLATE_MAIN_END = """ 121 | 122 | pkt.event=CFI_LOADING_MODULE_END; 123 | pkt.size=0; 124 | pkt.value=NULL; 125 | WRITE_LOADING_PACKET(fd_loading_to_monitor,pkt,err); 126 | if (err) abort(); 127 | """ 128 | 129 | TEMPLATE_SEND_BB = """ 130 | 131 | { 132 | uint32_t i, num_fcts; 133 | num_fcts = sizeof(_s_bb)/sizeof(_s_bb[0]); 134 | 135 | for (i=0; i0: 206 | ID = int(line.split()[0][1:-1]) 207 | next_bbs = [int(x) for x in line.split()[1:]] 208 | bb[current_fct][ID] = next_bbs 209 | #print_err(bb) 210 | return bb,fct_num_blocks 211 | 212 | def parse_bb_ipd(filename): 213 | bb_ipd = [] 214 | with open(filename,'r') as f: 215 | for line in f: 216 | line = line.rstrip() 217 | l_ipd = line.split() 218 | l_ipd = map(int,l_ipd) 219 | bb_ipd.append(tuple(l_ipd)) 220 | #print_err(bb_ipd) 221 | return bb_ipd 222 | 223 | def gen_header(): 224 | """generate the header of the file 225 | """ 226 | lbuf = [] 227 | lbuf = lbuf + TEMPLATE_HEADER.split("\n") 228 | return '\n'.join(lbuf) 229 | 230 | def flag_to_enum(s): 231 | if s == 'External': 232 | return "FCT_EXTERNAL" 233 | elif s == 'Init': 234 | return "FCT_INIT" 235 | elif s == 'Fini': 236 | return "FCT_FINI" 237 | elif s == 'Main': 238 | return "FCT_MAIN" 239 | else: 240 | return "FCT_INTERNAL" 241 | 242 | def flag_to_int(s): 243 | """ WARNING: values must match enum fct_flag_t 244 | """ 245 | if s == 'External': 246 | return 1 247 | elif s == 'Init': 248 | return 2 249 | elif s == 'Fini': 250 | return 3 251 | elif s == 'Main': 252 | return 4 253 | else: 254 | return 0 255 | 256 | def gen_packed_cfi(fcts): 257 | """generate the packed structure for cfi 258 | """ 259 | lbuf = [] 260 | s = '' 261 | s = struct.pack(' 0: 335 | s = s + packed_dict_uint32(d) 336 | 337 | length = len(s) 338 | s = map(lambda c : "\\x%.2x" % ord(c),s) 339 | s = ''.join(s) 340 | n = 64 341 | l2 = ['"%s"' % s[i:i+n] for i in range(0,len(s),n)] 342 | s = '\n'.join(l2) 343 | s = '{' + '%d, ' % length + s 344 | s = s + '},' 345 | lbuf.append(s) 346 | lbuf.append('};\n') 347 | return '\n'.join(lbuf) 348 | 349 | def gen_packed_bb_ipd(bb_ipd): 350 | """generate the packed structure for basic blocks / immediate post-dominators 351 | """ 352 | lbuf = [] 353 | ## uncomment to insert human-readable structure 354 | #lbuf.append("static const msg_block_ipd_t _bb_ipd[] = {"); 355 | #lbuf = lbuf + [' {{{0[0]}, {0[1]}, {0[2]}, {0[3]}}},'.format(ipd_def) for ipd_def in bb_ipd] 356 | #lbuf.append('};') 357 | s = '' 358 | s = s + struct.pack('. */ 18 | 19 | #include "defs.h" 20 | #include "monitor_dot.h" 21 | #include "monitor_load.h" 22 | #include "monitor_run.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | 35 | 36 | static 37 | int load_section_function_id(const msg_fct_l *const fct, 38 | module_data * const data) { 39 | const msg_fct_t *ptr = NULL; 40 | unsigned int i; 41 | 42 | if(data->nb_functions) { 43 | LOG_ERROR_MONITOR("already processed section\n"); 44 | return 1; 45 | } 46 | 47 | data->nb_functions = fct->num_fcts; 48 | if(((data->call_graph = calloc(data->nb_functions, sizeof(uint8_t*))) == NULL) || 49 | ((data->relocations = calloc(data->nb_functions, sizeof(module_function_ids))) == NULL) || 50 | ((data->functions = calloc(data->nb_functions, sizeof(function_data))) == NULL)) { 51 | LOG_ERROR_MONITOR("failed to allocate memory\n"); 52 | return 2; 53 | } 54 | 55 | LOG_DEBUG_MONITOR("module has %u function references\n", data->nb_functions); 56 | 57 | ptr = fct->fcts; 58 | for(i = 0; i < data->nb_functions; ++i) { 59 | if(ptr->f_id >= data->nb_functions) { 60 | LOG_ERROR_MONITOR("invalid function_id\n"); 61 | return 3; 62 | } 63 | function_data * const fd = &(data->functions[ptr->f_id]); 64 | fd->name = strdup(ptr->f_name); 65 | fd->flags = ptr->f_flags; 66 | fd->nb_blocks = 0; 67 | fd->control_flow_graph = NULL; 68 | fd->immediate_post_dominator = NULL; 69 | if(FUNCTION_IS_ENTRYPOINT_INIT(*fd)) { 70 | ++(data->nb_entrypoint_inits); 71 | } 72 | if(FUNCTION_IS_ENTRYPOINT_FINI(*fd)) { 73 | ++(data->nb_entrypoint_finis); 74 | } 75 | LOG_DEBUG_MONITOR("\tid=%6u main=%s init=%s fini=%s external=%s name=%s\n", 76 | ptr->f_id, 77 | FUNCTION_IS_ENTRYPOINT_MAIN(*fd) ? "YES" : "NO ", 78 | FUNCTION_IS_ENTRYPOINT_INIT(*fd) ? "YES" : "NO ", 79 | FUNCTION_IS_ENTRYPOINT_FINI(*fd) ? "YES" : "NO ", 80 | FUNCTION_IS_EXTERNAL(*fd) ? "YES" : "NO ", 81 | fd->name); 82 | ptr = (const msg_fct_t*)(1+strchr(ptr->f_name,'\0')); 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | static 89 | int load_section_function_transition(const msg_fct_trans_l * const trans, 90 | module_data * const data) { 91 | const msg_fct_trans_t *ptr = NULL; 92 | unsigned int i; 93 | 94 | if(!data->call_graph) { 95 | LOG_ERROR_MONITOR("call_graph not allocated\n"); 96 | return 1; 97 | } 98 | 99 | if(data->nb_functions <= 0) { 100 | LOG_ERROR_MONITOR("missing functions count\n"); 101 | return 1; 102 | } 103 | 104 | ptr = trans->fct_trans; 105 | for(i = 0; i < trans->num_fct_trans; ++i) { 106 | unsigned int j; 107 | const function_id * cptr = NULL; 108 | 109 | if(ptr->f_id >= data->nb_functions) { 110 | LOG_ERROR_MONITOR("invalid function_id\n"); 111 | return 3; 112 | } 113 | 114 | if(data->call_graph[ptr->f_id]) { 115 | LOG_ERROR_MONITOR("already processed function id=%u\n", ptr->f_id); 116 | return 3; 117 | } 118 | 119 | if((data->call_graph[ptr->f_id] = calloc(data->nb_functions, sizeof(uint8_t))) == NULL) { 120 | LOG_ERROR_MONITOR("failed to allocate memory\n"); 121 | return 2; 122 | } 123 | cptr = ptr->f_calls; 124 | for(j = 0; j < ptr->f_num_calls; ++j) { 125 | if(*cptr >= data->nb_functions) { 126 | LOG_ERROR_MONITOR("invalid function_id = %u\n", *cptr); 127 | return 3; 128 | } 129 | LOG_DEBUG_MONITOR("\tcall from->to = %6u -> %6u\n", ptr->f_id, *cptr); 130 | data->call_graph[ptr->f_id][*cptr] = 1; 131 | ++cptr; 132 | } 133 | 134 | ptr = (const msg_fct_trans_t *)((const char*)ptr + sizeof(msg_fct_trans_t) + ptr->f_num_calls*sizeof(uint32_t)); 135 | } 136 | 137 | return 0; 138 | } 139 | 140 | static 141 | int load_section_block_transition(const msg_block_trans_l * const trans, 142 | module_data * const data) { 143 | const msg_block_trans_t *ptr = NULL; 144 | function_data *fdata = NULL; 145 | unsigned int i; 146 | 147 | if(!data->functions) { 148 | LOG_ERROR_MONITOR("functions not allocated\n"); 149 | return 1; 150 | } 151 | 152 | if(data->nb_functions <= 0) { 153 | LOG_ERROR_MONITOR("missing functions count\n"); 154 | return 2; 155 | } 156 | 157 | if(trans->f_id >= data->nb_functions) { 158 | LOG_ERROR_MONITOR("invalid function_id\n"); 159 | return 3; 160 | } 161 | 162 | fdata = &(data->functions[trans->f_id]); 163 | 164 | if(fdata->nb_blocks) { 165 | LOG_ERROR_MONITOR("already processed function id=%u\n", trans->f_id); 166 | return 4; 167 | } 168 | 169 | if(trans->num_block <= 0) { 170 | LOG_ERROR_MONITOR("missing block count\n"); 171 | return 5; 172 | } 173 | 174 | fdata->nb_blocks = trans->num_block; 175 | if(((fdata->control_flow_graph = calloc(fdata->nb_blocks, sizeof(uint8_t*))) == NULL) || 176 | ((fdata->immediate_post_dominator = calloc(fdata->nb_blocks, sizeof(block_id))) == NULL)) { 177 | LOG_ERROR_MONITOR("failed to allocate memory\n"); 178 | return 6; 179 | } 180 | 181 | ptr = trans->block_trans; 182 | for(i = 0; i < trans->num_block_trans; ++i) { 183 | unsigned int j; 184 | const block_id * cptr = NULL; 185 | 186 | if(ptr->b_id >= fdata->nb_blocks) { 187 | LOG_ERROR_MONITOR("invalid block_id %u\n", ptr->b_id); 188 | return 7; 189 | } 190 | 191 | if(fdata->control_flow_graph[ptr->b_id] == NULL) { 192 | if((fdata->control_flow_graph[ptr->b_id] = calloc(fdata->nb_blocks, sizeof(uint8_t))) == NULL) { 193 | LOG_ERROR_MONITOR("failed to allocate memory\n"); 194 | return 9; 195 | } 196 | } 197 | 198 | cptr = ptr->b_succ; 199 | for(j = 0; j < ptr->b_num_succ; ++j) { 200 | if(*cptr >= fdata->nb_blocks) { 201 | LOG_ERROR_MONITOR("invalid block_id %u (nb_blocks = %u)\n", *cptr, fdata->nb_blocks); 202 | return 10; 203 | } 204 | LOG_DEBUG_MONITOR("\tjump from->to = %6u -> %6u\n", ptr->b_id, *cptr); 205 | fdata->control_flow_graph[ptr->b_id][*cptr] = 1; 206 | ++cptr; 207 | } 208 | 209 | ptr = (const msg_block_trans_t*)((const char*)ptr + sizeof(msg_block_trans_t) + ptr->b_num_succ*(sizeof(uint32_t))); 210 | } 211 | 212 | return 0; 213 | } 214 | 215 | static 216 | int load_section_block_ipd(const msg_block_ipd_l * const ipd, 217 | module_data * const data) { 218 | const msg_block_ipd_t *ptr = NULL; 219 | unsigned int i; 220 | 221 | if(!data->functions) { 222 | LOG_ERROR_MONITOR("functions not allocated\n"); 223 | return 1; 224 | } 225 | 226 | ptr = ipd->block_ipd; 227 | for(i = 0; i < ipd->num_ipd; ++i) { 228 | const function_data *fdata = NULL; 229 | 230 | if(ptr->f_id >= data->nb_functions) { 231 | LOG_ERROR_MONITOR("invalid function_id\n"); 232 | return 2; 233 | } 234 | 235 | fdata = &(data->functions[ptr->f_id]); 236 | 237 | if(!(fdata->immediate_post_dominator)) { 238 | LOG_ERROR_MONITOR("immediate_post_dominator not allocated\n"); 239 | return 4; 240 | } 241 | 242 | if(ptr->b_id >= fdata->nb_blocks) { 243 | LOG_ERROR_MONITOR("invalid block_id\n"); 244 | return 5; 245 | } 246 | 247 | LOG_DEBUG_MONITOR("\tfunction=%6u block=%6u ipd=%6u\n", ptr->f_id, ptr->b_id, ptr->b_ipd_id); 248 | fdata->immediate_post_dominator[ptr->b_id] = ptr->b_ipd_id; 249 | 250 | ++ptr; 251 | } 252 | 253 | 254 | return 0; 255 | } 256 | 257 | int monitor_load_module(monitor_data * const mon) { 258 | loading_packet pkt; 259 | monitor_to_loading_packet mpkt; 260 | module_data *modata = NULL; 261 | int err = 0; 262 | int terminated = 0; 263 | 264 | LOG_DEBUG_MONITOR("waiting for new module\n"); 265 | 266 | pkt.size = 0; 267 | pkt.value = NULL; 268 | 269 | READ_LOADING_PACKET(mon->fd_loading_to_monitor, pkt, err); 270 | if(err) { 271 | LOG_ERROR_MONITOR("failed to read loading packet (err = %u)\n", err); 272 | } else { 273 | switch(pkt.event) { 274 | case CFI_LOADING_MODULE_BEGIN: 275 | LOG_DEBUG_MONITOR("received CFI_LOADING_MODULE_BEGIN\n"); 276 | if(mon->nb_modules) { 277 | ++(mon->nb_modules); 278 | mon->modules = realloc(mon->modules, sizeof(module_data) * mon->nb_modules); 279 | } else { 280 | mon->nb_modules = 1; 281 | mon->modules = calloc(1, sizeof(module_data)); 282 | } 283 | if(mon->modules == NULL) { 284 | LOG_ERROR_MONITOR("failed to allocate memory\n"); 285 | err = 10; 286 | } else { 287 | modata = &(mon->modules[mon->nb_modules - 1]); 288 | modata->nb_functions = 0; 289 | modata->nb_entrypoint_inits = 0; 290 | modata->nb_entrypoint_finis = 0; 291 | modata->call_graph = NULL; 292 | modata->relocations = NULL; 293 | modata->functions = NULL; 294 | 295 | mpkt.id = mon->nb_modules - 1; 296 | WRITE_MONITOR_TO_LOADING_PACKET(mon->fd_monitor_to_loading, mpkt, err); 297 | } 298 | break; 299 | 300 | case CFI_LOADING_TERMINATED: 301 | LOG_DEBUG_MONITOR("received CFI_LOADING_TERMINATED\n"); 302 | terminated = 1; 303 | break; 304 | 305 | default: 306 | LOG_ERROR_MONITOR("unexpected loading event\n"); 307 | err = 5; 308 | break; 309 | } 310 | } 311 | 312 | 313 | 314 | while((err == 0) && 315 | (terminated == 0) && 316 | (pkt.event != CFI_LOADING_MODULE_END)) { 317 | 318 | FREE_LOADING_PACKET(pkt); 319 | 320 | READ_LOADING_PACKET(mon->fd_loading_to_monitor, pkt, err); 321 | 322 | if(err) { 323 | LOG_ERROR_MONITOR("failed to read loading packet\n"); 324 | err = 4; 325 | 326 | } else { 327 | 328 | switch(pkt.event) { 329 | case CFI_LOADING_SECTION_FUNCTION_ID: 330 | LOG_DEBUG_MONITOR("received CFI_LOADING_SECTION_FUNCTION_ID\n"); 331 | err = load_section_function_id(&(pkt.value->fct), modata); 332 | break; 333 | 334 | case CFI_LOADING_SECTION_FUNCTION_TRANSITION: 335 | LOG_DEBUG_MONITOR("received CFI_LOADING_SECTION_FUNCTION_TRANSITION\n"); 336 | err = load_section_function_transition(&(pkt.value->fct_trans), modata); 337 | break; 338 | 339 | case CFI_LOADING_SECTION_BLOCK_TRANSITION: 340 | LOG_DEBUG_MONITOR("received CFI_LOADING_SECTION_BLOCK_TRANSITION\n"); 341 | err = load_section_block_transition(&(pkt.value->block_trans), modata); 342 | break; 343 | 344 | case CFI_LOADING_SECTION_BLOCK_IPD: 345 | LOG_DEBUG_MONITOR("received CFI_LOADING_SECTION_BLOCK_IPD\n"); 346 | err = load_section_block_ipd(&(pkt.value->block_ipd), modata); 347 | break; 348 | 349 | case CFI_LOADING_MODULE_END: 350 | LOG_DEBUG_MONITOR("received CFI_LOADING_MODULE_END\n"); 351 | if(OPTION_sm_dump) { 352 | unsigned int i; 353 | monitor_call_graph(modata); 354 | for(i = 0; i < modata->nb_functions; ++i) { 355 | monitor_control_flow_graph(&(modata->functions[i])); 356 | } 357 | } 358 | break; 359 | 360 | default: 361 | LOG_ERROR_MONITOR("unexpected loading event\n"); 362 | err = 5; 363 | break; 364 | } 365 | } 366 | } 367 | 368 | FREE_LOADING_PACKET(pkt); 369 | 370 | if(terminated) return 1; 371 | if(err) return -1; 372 | 373 | return 0; 374 | } 375 | 376 | 377 | 378 | static 379 | int compute_relocations_of_module(monitor_data * const data, 380 | const module_id mid, 381 | const int unresolved_is_fatal) { 382 | 383 | unsigned int j; 384 | module_data * const midata = &(data->modules[mid]); 385 | 386 | LOG_DEBUG_MONITOR("computing relocation of module id=%u\n", mid); 387 | 388 | for(j = 0; j < midata->nb_functions; ++j) { 389 | if(FUNCTION_IS_EXTERNAL(midata->functions[j])) { 390 | int k = data->nb_modules - 1; 391 | int not_resolved = 1; 392 | 393 | while(not_resolved && (k >= 0)) { 394 | module_data * const mkdata = &(data->modules[k]); 395 | unsigned int l = 0; 396 | 397 | if(mid != k) { 398 | while(not_resolved && (l < mkdata->nb_functions)) { 399 | if(!FUNCTION_IS_EXTERNAL(mkdata->functions[l]) && 400 | (strcmp(midata->functions[j].name, mkdata->functions[l].name) == 0)) { 401 | midata->relocations[j] = MODULE_FUNCTION(k, l); 402 | not_resolved = 0; 403 | LOG_DEBUG_MONITOR("\trelocate %6u -> (%3u,%6u)\n", j, mid, l); 404 | } 405 | ++l; 406 | } 407 | } 408 | --k; 409 | } 410 | 411 | if(not_resolved) { 412 | LOG_DEBUG_MONITOR("\tno relocation found for id=%u (name=%s)\n", j, midata->functions[j].name); 413 | if(unresolved_is_fatal) { 414 | LOG_ERROR_MONITOR("unresolved external function : %s\n", midata->functions[j].name); 415 | return 1; 416 | } 417 | } 418 | } 419 | } 420 | 421 | return 0; 422 | } 423 | 424 | 425 | int monitor_load(const pid_t client_pid, 426 | const int fd_client_to_monitor, 427 | const int fd_monitor_to_client, 428 | const int fd_loading_to_monitor, 429 | const int fd_monitor_to_loading, 430 | monitor_data * const data) { 431 | unsigned int i; 432 | int err, terminated; 433 | 434 | data->client_pid = client_pid; 435 | data->fd_client_to_monitor = fd_client_to_monitor; 436 | data->fd_monitor_to_client = fd_monitor_to_client; 437 | data->fd_loading_to_monitor = fd_loading_to_monitor; 438 | data->fd_monitor_to_loading = fd_monitor_to_loading; 439 | 440 | data->nb_modules = 0; 441 | data->modules = NULL; 442 | 443 | terminated = 0; 444 | do { 445 | err = monitor_load_module(data); 446 | if(err > 0) { 447 | terminated = 1; 448 | err = 0; 449 | } 450 | if(!err && !terminated) { 451 | err = compute_relocations_of_module(data, data->nb_modules - 1, 0); 452 | if(!err) { 453 | const unsigned int nb = data->modules[data->nb_modules - 1].nb_entrypoint_inits; 454 | i = 0; 455 | LOG_DEBUG_MONITOR("%u inits are expected\n", nb); 456 | while((i < nb) && !err) { 457 | err = monitor_run(*data); 458 | ++i; 459 | } 460 | } 461 | } 462 | } while(!terminated && !err); 463 | 464 | i = 0; 465 | while(!err && (i < data->nb_modules)) { 466 | err = compute_relocations_of_module(data, i, 1); 467 | ++i; 468 | } 469 | 470 | return err; 471 | } 472 | 473 | 474 | void monitor_data_free(monitor_data * const data) { 475 | unsigned int i; 476 | 477 | for(i = 0; i < data->nb_modules; ++i) { 478 | module_data *mdata = &(data->modules[i]); 479 | unsigned int j; 480 | 481 | for(j = 0; j < mdata->nb_functions; ++j) { 482 | function_data *fdata = &(mdata->functions[j]); 483 | unsigned int k; 484 | 485 | if(mdata->call_graph[j]) { 486 | free(mdata->call_graph[j]); 487 | mdata->call_graph[j] = NULL; 488 | } 489 | 490 | for(k = 0; k < fdata->nb_blocks; ++k) { 491 | if(fdata->control_flow_graph[k]) { 492 | free(fdata->control_flow_graph[k]); 493 | fdata->control_flow_graph[k] = NULL; 494 | } 495 | } 496 | 497 | free(fdata->name); 498 | free(fdata->control_flow_graph); 499 | free(fdata->immediate_post_dominator); 500 | fdata->name = NULL; 501 | fdata->control_flow_graph = NULL; 502 | fdata->immediate_post_dominator = NULL; 503 | fdata->nb_blocks = 0; 504 | } 505 | 506 | if(mdata->nb_functions) { 507 | free(mdata->functions); 508 | free(mdata->call_graph); 509 | free(mdata->relocations); 510 | mdata->functions = NULL; 511 | mdata->call_graph = NULL; 512 | mdata->relocations = NULL; 513 | mdata->nb_functions = 0; 514 | } 515 | } 516 | 517 | if(data->nb_modules) { 518 | free(data->modules); 519 | data->modules = NULL; 520 | data->nb_modules = 0; 521 | } 522 | } 523 | -------------------------------------------------------------------------------- /llvm_pass/CFI/CFI.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015-2017 ANSSI 2 | 3 | This file is part of the Picon project. 4 | 5 | This file is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This file is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this file; if not, see 17 | . */ 18 | 19 | #include 20 | #include 21 | 22 | #include "CFI.hh" 23 | 24 | class ValueOpRange { 25 | User &U; 26 | typedef User::value_op_iterator iter; 27 | public: 28 | ValueOpRange(User &U) : U(U) {} 29 | iter begin() { return U.value_op_begin(); } 30 | iter end() { return U.value_op_end(); } 31 | }; 32 | 33 | ControlFlowIntegrity::ControlFlowIntegrity(Module &M, 34 | const std::string& fun_id_file, 35 | const std::string& ipdom_file, 36 | const std::string& trans_table_file, 37 | const std::string& trans_tablebb_file, 38 | const std::string& IgnoredFctFileName) 39 | : _M(M), 40 | _FunctionMap(), 41 | _IdentifiedFunctions(), 42 | _IgnoredFunctions(), 43 | _InitFunctions(), 44 | _FiniFunctions(), 45 | _IgnoredBlocksFunctions(), 46 | _fun_id_file(fun_id_file), 47 | _transTableFile(trans_table_file), _transTableBBFile(trans_tablebb_file), 48 | _IgnoredFctFileName(IgnoredFctFileName), _ipdom_file(ipdom_file), 49 | _fun_id_ctr(0) { 50 | if (!_IgnoredFctFileName.empty()) { 51 | std::fstream fs; 52 | fs.open(_IgnoredFctFileName, std::fstream::in); 53 | 54 | if (!fs.is_open()) { 55 | std::cerr << strerror(errno) << std::endl; 56 | assert(0 && "Can't open file to read the ignored functions\n"); 57 | } 58 | 59 | std::string line; 60 | while (std::getline(fs, line)) { 61 | _IgnoredFunctions.insert(line); 62 | } 63 | } 64 | } 65 | 66 | bool ControlFlowIntegrity::isIgnoredFunction(const std::string &fName) { 67 | return (_IgnoredFunctions.find(fName) != _IgnoredFunctions.end()); 68 | } 69 | 70 | bool ControlFlowIntegrity::isInitFunction(const std::string &fName) { 71 | return (_InitFunctions.find(fName) != _InitFunctions.end()); 72 | } 73 | 74 | bool ControlFlowIntegrity::isFiniFunction(const std::string &fName) { 75 | return (_FiniFunctions.find(fName) != _FiniFunctions.end()); 76 | } 77 | 78 | bool ControlFlowIntegrity::isIgnoredBlocksFunction(const std::string &fName) { 79 | return (_IgnoredBlocksFunctions.find(fName) != _IgnoredBlocksFunctions.end()); 80 | } 81 | 82 | // writeTransToFile: 83 | // This function must be called after IdentifyFunctions. 84 | // This function is not reentrant, we need to lock the 85 | // _transTableFile to handle multiple compilation jobs. 86 | // 87 | // It is responsible of writing functions and/or basic blocks 88 | // transitions to the file specified by the option -trans-table 89 | // of the `opt` command. 90 | // 91 | // In case of multiple source files (existing transition file), this function 92 | // will append new discovered transition to the end of the file. 93 | // 94 | void ControlFlowIntegrity::writeTransToFile(int level) { 95 | std::fstream fs; 96 | 97 | fs.open(_transTableFile, std::fstream::out | std::fstream::app); 98 | 99 | if (!fs.is_open()) { 100 | std::cerr << strerror(errno) << std::endl; 101 | assert(0 && "Can't open file to write the transitions of functions."); 102 | } 103 | 104 | writeCallgraph(fs); 105 | fs.close(); 106 | 107 | if (level == BASICBLOCK) { 108 | fs.open(_transTableBBFile, std::fstream::out | std::fstream::app); 109 | 110 | if (!fs.is_open()) { 111 | std::cerr << strerror(errno) << std::endl; 112 | assert(0 && "Can't open file to write the transitions of basic blocks."); 113 | } 114 | 115 | writeAllowedBBTrans(fs); 116 | 117 | fs.close(); 118 | } 119 | } 120 | 121 | int ControlFlowIntegrity::IdentifyFunction(const Function& F) { 122 | uint32_t id; 123 | if (_IdentifiedFunctions.find(F.getName()) != _IdentifiedFunctions.end()) { 124 | id = _IdentifiedFunctions[F.getName()]; 125 | } else { 126 | id = _fun_id_ctr++; 127 | _IdentifiedFunctions[F.getName()] = id; 128 | } 129 | return id; 130 | } 131 | 132 | int ControlFlowIntegrity::AddIdentifiedFunction(const std::string name, uint32_t id) { 133 | if (_IdentifiedFunctions.find(name) != _IdentifiedFunctions.end()) { 134 | std::cerr << "Function already present: " << name << std::endl; 135 | assert(0 && "Function already present"); 136 | } else { 137 | _IdentifiedFunctions[name] = id; 138 | } 139 | if (_fun_id_ctr <= id) 140 | _fun_id_ctr = id + 1; 141 | return id; 142 | } 143 | 144 | bool ControlFlowIntegrity::HasAlreadyBeenIdentified_id(const Function& F) { 145 | return (_IdentifiedFunctions.find(F.getName()) != _IdentifiedFunctions.end()); 146 | } 147 | 148 | // writeFunctionIDs 149 | // This function updates the file specified by the option -fun-id 150 | // of the `opt` command with the list of function ID and known modules/flags. 151 | // 152 | // The format of the file is: 153 | // function_name function_identifier [Ignored|External|File] 154 | // where File is the -fun-id command line parameter. 155 | // 156 | void ControlFlowIntegrity::writeFunctionIDs(void) { 157 | uint32_t id; 158 | llvm::StringMap> oldMap; 159 | llvm::StringMap alreadyAdded; 160 | 161 | std::string fctName; 162 | std::string flags; 163 | std::ostringstream tmpbuf; 164 | std::ifstream fs(_fun_id_file); 165 | 166 | if (fs.good() == true) { 167 | // file was present, read previously known function IDs and flags 168 | if (!fs.is_open()) { 169 | report_fatal_error("Could not open the Function ID file", false); 170 | assert(0 && "Can't open the CFI function ID file."); 171 | } 172 | 173 | while (fs >> fctName >> id >> flags) { 174 | oldMap[fctName] = std::make_pair(id,flags); 175 | } 176 | fs.close(); 177 | } 178 | 179 | for (auto &it : _FunctionMap) { 180 | std::string fct_name = it.getKey(); 181 | CFIFct cfi_f = it.second; 182 | llvm::Function &F = *cfi_f.fun; 183 | std::string flags; 184 | 185 | id = cfi_f.id; 186 | 187 | // debug only check: new ID must be the same as the previous one 188 | if (oldMap.find(fct_name) != oldMap.end()) { 189 | std::pair &E = oldMap[fct_name]; 190 | assert(E.first == id && "ID of function in file is different from ID to be written"); 191 | } 192 | 193 | if (isIgnoredFunction(fct_name)) { 194 | flags.append("Ignored"); 195 | alreadyAdded[fct_name] = true; 196 | } else if (isInitFunction(fct_name)) { 197 | flags.append("Init"); 198 | alreadyAdded[fct_name] = true; 199 | } else if (isFiniFunction(fct_name)) { 200 | flags.append("Fini"); 201 | alreadyAdded[fct_name] = true; 202 | } else if (fct_name == "main") { 203 | flags.append("Main"); 204 | alreadyAdded[fct_name] = true; 205 | } else if (F.isDeclaration()) { 206 | auto it = oldMap.find(fct_name); 207 | if (it != oldMap.end()) { 208 | if (it->getValue().second != "External") { 209 | // the old file knows more about the function - use it 210 | flags.append(it->getValue().second); 211 | } else { 212 | flags.append("External"); 213 | } 214 | } else { 215 | flags.append("External"); 216 | } 217 | alreadyAdded[fct_name] = true; 218 | } else if (HasAlreadyBeenIdentified_id(F)) { 219 | id = IdentifyFunction(F); 220 | alreadyAdded[fct_name] = true; 221 | flags.append(_fun_id_file); 222 | } else if (F.isDeclaration()) { 223 | assert(0 && "should not be here"); 224 | flags.append(_fun_id_file); 225 | } else { 226 | assert(0 && "should not be here"); 227 | } 228 | tmpbuf << fct_name.data() << " " << id << " " << flags << "\n"; 229 | } 230 | 231 | for (auto it=oldMap.begin(); it!=oldMap.end(); it++) { 232 | if (alreadyAdded.find(it->getKey()) == alreadyAdded.end()) { 233 | tmpbuf << it->getKey().data() << " " << it->getValue().first << " " << it->getValue().second << "\n"; 234 | } 235 | } 236 | 237 | std::ofstream ffs(_fun_id_file, std::fstream::out); 238 | // will overwrite previous _fun_id_file 239 | 240 | if (!ffs.is_open()) { 241 | std::cerr << strerror(errno) << std::endl; 242 | assert(0 && "Can't open file to write the CFI Function ID file."); 243 | } 244 | 245 | ffs << tmpbuf.str(); 246 | ffs.close(); 247 | } 248 | 249 | // getIdentifier: 250 | // Returns the identifier for the given function. 251 | // the function Map is constructed in IdentifyFunctions 252 | // method. 253 | // 254 | int ControlFlowIntegrity::getIdentifier(Function *F) { 255 | if (_IdentifiedFunctions.find(F->getName()) != _IdentifiedFunctions.end()) { 256 | return _IdentifiedFunctions[F->getName()]; 257 | } 258 | std::cerr << "getIdentifier out-of-range!\n"; 259 | assert(0 && "Function Identifier out of range!"); 260 | return -1; 261 | } 262 | 263 | 264 | // writeCallgraph: 265 | // This function finds all call instructions of the module 266 | // being processed. For each call instruction we retrieve 267 | // the Function ID of the called function and save it to 268 | // the file specified by @fs. 269 | // @fs is a map with a function ID as a key. 270 | // The value of the map is a vector of 271 | // function ID that are called by the 272 | // function specified in the key. 273 | // The format is: 274 | // (ID_FCT_0) ID_FCT_1 ID_FCT_3 275 | // (ID_FCT_1) ID_FCT_0 ID_FCT_2 276 | // where ID_FCT_0 calls ID_FCT_1 and ID_FCT_3 277 | // and ID_FCT_1 calls ID_FCT_0 and ID_FCT_2. 278 | // 279 | void ControlFlowIntegrity::writeCallgraph(std::fstream &fs) { 280 | std::map> _AllowedMapTrans; 281 | 282 | for (auto &it : _FunctionMap) { 283 | CFIFct cfi_f = it.second; 284 | llvm::Function &F = *cfi_f.fun; 285 | uint32_t id = cfi_f.id; 286 | 287 | if (F.isDeclaration()) 288 | continue; 289 | 290 | for (auto &BB : F) { 291 | for (auto &I : BB) { 292 | if (isa(I)) { 293 | report_fatal_error("Invoke instructions not yet supported in Picon", false); 294 | } 295 | assert (!isa(I) && "Invoke instructions not supported"); 296 | 297 | if (CallInst* CI = dyn_cast(&I)) { 298 | if (CI->isInlineAsm()) 299 | continue; 300 | 301 | Function *CF = CI->getCalledFunction(); 302 | 303 | // Check if dynamic call 304 | if (CF == NULL) { 305 | report_fatal_error("Indirect calls not yet supported in Picon", false); 306 | } 307 | assert (CF != NULL && "Indirect calls not supported"); 308 | 309 | if (isIgnoredFunction(CF->getName())) 310 | continue; 311 | if (CF->getIntrinsicID() != Intrinsic::not_intrinsic) 312 | continue; 313 | 314 | 315 | // we have F -> CF 316 | // now find IDs of these functions 317 | if (_IdentifiedFunctions.find(CF->getName()) != _IdentifiedFunctions.end()) { 318 | uint32_t id_cf = _IdentifiedFunctions[CF->getName()]; 319 | _AllowedMapTrans[id].insert(id_cf); 320 | } 321 | else { 322 | std::cerr << "Could not find ID for callee " << CF->getName().data() << ", called by " << F.getName().data() << std::endl; 323 | } 324 | } 325 | } 326 | } 327 | } 328 | 329 | // append map to file 330 | // note: previous content is not updated, the only functions added 331 | // are those from the current file 332 | // If this pass is called twice, information will be present twice 333 | for (auto &X : _AllowedMapTrans) { 334 | fs << "(" << X.first << ") "; 335 | for (auto &XX : X.second) 336 | fs << XX << " "; 337 | fs << "\n"; 338 | } 339 | } 340 | 341 | // WriteAllowedBBTrans: 342 | // This functions looks for all basic blocks transition, builds a map, 343 | // and writes it to the stream given as parameter. 344 | // 345 | void ControlFlowIntegrity::writeAllowedBBTrans(std::fstream &fs) { 346 | for (auto &it : _FunctionMap) { 347 | CFIFct cfi_f = it.second; 348 | llvm::Function &F = *cfi_f.fun; 349 | uint32_t fct_id = cfi_f.id; 350 | std::map &bb_map = cfi_f.bb_map; 351 | 352 | if (isIgnoredFunction(F.getName())) 353 | continue; 354 | if (isIgnoredBlocksFunction(F.getName())) 355 | continue; 356 | if (F.isDeclaration()) 357 | continue; 358 | 359 | unsigned int numBB = F.size(); 360 | 361 | fs << ";{" << fct_id << "} " << numBB << "\n"; 362 | 363 | if (numBB == 1) 364 | continue; 365 | 366 | for (auto &BB : F) { 367 | auto it = succ_begin(&BB), et = succ_end(&BB); 368 | 369 | if (it == et) 370 | continue; 371 | 372 | fs << "(" << bb_map[&BB] << ") "; 373 | 374 | for (; it != et; ++it) { 375 | BasicBlock *successor = *it; 376 | 377 | fs << bb_map[successor] << " "; 378 | } 379 | fs << "\n"; 380 | } 381 | 382 | fs << "\n"; 383 | } 384 | } 385 | 386 | void ControlFlowIntegrity::IdentifyFunctions(void) { 387 | std::string is_defined; 388 | std::string fctName; 389 | uint32_t id, iid; 390 | 391 | ON_DEBUG(true, "IdentifyFunctions: " << _fun_id_file << "\n"); 392 | std::ifstream fs(_fun_id_file); 393 | if (fs) { 394 | while (fs >> fctName >> iid >> is_defined) { 395 | (void)AddIdentifiedFunction(fctName,iid); 396 | } 397 | if (fs.peek()!=EOF) { 398 | report_fatal_error("IdentifyFunctions: bad input file", false); 399 | assert(0 && "IdentifyFunctions: bad input file"); 400 | } 401 | } 402 | fs.close(); 403 | 404 | for (auto &F : _M) { 405 | if (isIgnoredFunction(F.getName())) 406 | continue; 407 | 408 | if (F.getIntrinsicID() != Intrinsic::not_intrinsic) 409 | continue; 410 | 411 | id = IdentifyFunction(F); 412 | 413 | std::map bb_map; 414 | uint32_t bb_id = 0; 415 | for (auto &BB : F) { 416 | bb_map[&BB] = bb_id++; 417 | } 418 | 419 | _FunctionMap[F.getName()] = {.fun=&F, .id=id, .bb_map=bb_map}; 420 | ON_DEBUG(true, F.getName() << " with identifier " << id << "\n"); 421 | } 422 | } 423 | 424 | // IdentifyBB: 425 | // Since the identification for basic blocks is trivial 426 | // and easily predictable, this function is only used 427 | // for debugging purpose to dump the Basic Block Label 428 | // and the attached Identifier. 429 | void ControlFlowIntegrity::IdentifyBB(void) { 430 | for (auto &F : _M) { 431 | int Identifier = 0; 432 | if (!F.isDeclaration()) { 433 | errs() << "\n\nIdentifier BB of " << F.getName() << "\n\n"; 434 | for (auto &BB : F) { 435 | errs() << BB.getName() << " with identifier " << Identifier << 436 | " has " << BB.size() << " Instructions" << "\n"; 437 | ++Identifier; 438 | } 439 | } else { 440 | errs() << F.getName() << " is a declaration\n"; 441 | } 442 | } 443 | errs() << "\n"; 444 | } 445 | 446 | // writeIPDOMToFile: 447 | // This functions looks for the immediate post-dominator (IPD) of every basic 448 | // block of every basic block of every function, and writes it to _ipdom_file 449 | void ControlFlowIntegrity::writeIPDOMToFile(CFIModulePass* cfi) { 450 | std::fstream IPDOMFS; 451 | 452 | IPDOMFS.open(_ipdom_file, std::fstream::out | std::fstream::app); 453 | 454 | if (!IPDOMFS.is_open()) { 455 | std::cerr << strerror(errno) << std::endl; 456 | assert(0 && "Can't open file to write ipdom!"); 457 | } 458 | 459 | for (auto &it : _FunctionMap) { 460 | CFIFct cfi_f = it.second; 461 | llvm::Function &F = *cfi_f.fun; 462 | std::map &bb_map = cfi_f.bb_map; 463 | 464 | if (F.isDeclaration()) 465 | continue ; 466 | if (isIgnoredFunction(F.getName())) 467 | continue; 468 | if (isIgnoredBlocksFunction(F.getName())) 469 | continue; 470 | 471 | PostDominatorTree &PDT = cfi->getAnalysis(F); 472 | for (BasicBlock &bb : F) { 473 | TerminatorInst* term = (bb).getTerminator(); 474 | 475 | if (isa(term)) { 476 | report_fatal_error("Invoke Instruction detected!", false); 477 | continue; 478 | } 479 | 480 | BasicBlock* posdom = NULL; 481 | if (term->getNumSuccessors() >= 1) { 482 | succ_iterator si = succ_begin(&bb); 483 | posdom = *si; 484 | si++; 485 | for (succ_iterator se = succ_end(&bb); si != se; si++) { 486 | BasicBlock* su2 = *si; 487 | posdom = PDT.findNearestCommonDominator(posdom, su2); 488 | if (posdom == NULL) 489 | break; 490 | } 491 | } 492 | IPDOMFS << getIdentifier(&F) << " "; 493 | IPDOMFS << bb_map[&(bb)] << " "; 494 | if (posdom != NULL) { 495 | IPDOMFS << bb_map[posdom] << " "; 496 | } else { 497 | IPDOMFS << "0 "; 498 | } 499 | IPDOMFS << bb_map[&F.back()] << "\n"; 500 | } 501 | } 502 | IPDOMFS.close(); 503 | } 504 | 505 | void ControlFlowIntegrity::ParseAnnotations(void) { 506 | GlobalVariable *global_ctors = _M.getNamedGlobal("llvm.global.annotations"); 507 | 508 | // check for ctor section 509 | if (!global_ctors || !global_ctors->getOperand(0)) { 510 | return; 511 | } 512 | 513 | Constant *c = global_ctors->getInitializer(); 514 | if (!c) 515 | report_fatal_error("llvm.global.annotations without initializer!", false); 516 | 517 | ConstantArray *CA = dyn_cast(c); 518 | if (!CA) 519 | report_fatal_error("Cast to ConstantArray failed", true); 520 | 521 | for (Value *Op : ValueOpRange(*CA)) { 522 | ConstantStruct *CS = dyn_cast(Op); 523 | if (!CS) 524 | report_fatal_error("Cast to ConstantStruct failed", true); 525 | 526 | Constant *FP = CS->getOperand(0); 527 | if (FP->isNullValue()) 528 | break; // found a NULL termintator, stop here 529 | 530 | ConstantExpr *CE; 531 | Function *F = dyn_cast_or_null(FP); 532 | 533 | if (F == NULL) { 534 | // Strip off constant expression cast 535 | CE = dyn_cast(FP); 536 | if (!CE) 537 | report_fatal_error("Cast to ConstantExpr failed", true); 538 | if (CE->isCast()) { 539 | FP = CE->getOperand(0); 540 | F = dyn_cast_or_null(FP); 541 | } 542 | } 543 | 544 | if (!F) 545 | report_fatal_error("Cast to Function failed", true); 546 | 547 | Constant *SP = CS->getOperand(1); 548 | if (SP->isNullValue()) 549 | break; // found a NULL termintator, stop here 550 | 551 | // Strip off constant expression cast 552 | CE = dyn_cast(SP); 553 | if (!CE) 554 | report_fatal_error("Cast to ConstantExpr failed", true); 555 | if (CE->isCast()) { 556 | SP = CE->getOperand(0); 557 | } 558 | 559 | Value *V = SP->getOperand(0); 560 | GlobalVariable *GV = dyn_cast_or_null(V); 561 | if (!GV) 562 | report_fatal_error("Cast to GlobalVariable failed", false); 563 | assert(GV && "cast to GlobalVariable failed"); 564 | 565 | Constant *cval = GV->getInitializer(); 566 | const StringRef s = (cast(cval))->getAsCString(); 567 | if (s == ANNOTATION_IGNORE_BLOCK) { 568 | _IgnoredBlocksFunctions.insert(F->getName()); 569 | } 570 | } 571 | 572 | if (global_ctors->getNumUses() > 0) 573 | report_fatal_error("llvm.global.annotations uses count is > 0", false); 574 | } 575 | 576 | void ControlFlowIntegrity::PatchCtorFunctions(void) { 577 | GlobalVariable *global_ctors = _M.getNamedGlobal("llvm.global_ctors"); 578 | 579 | // check for ctor section 580 | if (!global_ctors || !global_ctors->getOperand(0)) { 581 | return; 582 | } 583 | 584 | Constant *c = global_ctors->getInitializer(); 585 | if (!c) 586 | report_fatal_error("llvm.global_ctors without initializer!", false); 587 | 588 | ConstantArray *CA = dyn_cast(c); 589 | if (!CA) 590 | report_fatal_error("Cast to ConstantArray failed", true); 591 | 592 | for (Value *Op : ValueOpRange(*CA)) { 593 | ConstantStruct *CS = dyn_cast(Op); 594 | if (!CS) 595 | report_fatal_error("Cast to ConstantStruct failed", true); 596 | 597 | Constant *FP = CS->getOperand(1); 598 | if (FP->isNullValue()) 599 | break; // found a NULL termintator, stop here 600 | 601 | Function *F = dyn_cast_or_null(FP); 602 | if (F == NULL) { 603 | // Strip off constant expression cast 604 | ConstantExpr *CE = dyn_cast(FP); 605 | if (!CE) 606 | report_fatal_error("Cast to ConstantExpr failed", true); 607 | if (CE->isCast()) { 608 | FP = CE->getOperand(0); 609 | } 610 | F = dyn_cast_or_null(FP); 611 | } 612 | 613 | if (!F) 614 | report_fatal_error("Cast to Function failed", true); 615 | 616 | // set visibility to hidden (do not export), unless it is already 617 | // local (for ex. static), in which case we have to make it non-static 618 | if (F->hasLocalLinkage()) { 619 | F->setLinkage(llvm::GlobalValue::ExternalLinkage); 620 | } 621 | F->setVisibility(GlobalValue::HiddenVisibility); 622 | 623 | _InitFunctions.insert(F->getName()); 624 | } 625 | 626 | if (global_ctors->getNumUses() > 0) 627 | report_fatal_error("llvm.global_ctors uses count is > 0!", false); 628 | 629 | global_ctors->removeFromParent(); 630 | 631 | } 632 | 633 | void ControlFlowIntegrity::PatchDtorFunctions(void) { 634 | GlobalVariable *global_dtors = _M.getNamedGlobal("llvm.global_dtors"); 635 | 636 | // check for dtor section 637 | if (!global_dtors || !global_dtors->getOperand(0)) { 638 | return; 639 | } 640 | 641 | Constant *c = global_dtors->getInitializer(); 642 | if (!c) 643 | report_fatal_error("llvm.global_dtors without initializer!", false); 644 | 645 | ConstantArray *CA = dyn_cast(c); 646 | if (!CA) 647 | report_fatal_error("Cast to ConstantArray failed", true); 648 | 649 | for (Value *Op : ValueOpRange(*CA)) { 650 | ConstantStruct *CS = dyn_cast(Op); 651 | if (!CS) 652 | report_fatal_error("Cast to ConstantStruct failed", true); 653 | 654 | Constant *FP = CS->getOperand(1); 655 | if (FP->isNullValue()) 656 | break; // found a NULL termintator, stop here 657 | 658 | Function *F = dyn_cast_or_null(FP); 659 | if (F == NULL) { 660 | // Strip off constant expression cast 661 | ConstantExpr *CE = dyn_cast(FP); 662 | if (!CE) 663 | report_fatal_error("Cast to ConstantExpr failed", true); 664 | if (CE->isCast()) { 665 | FP = CE->getOperand(0); 666 | } 667 | F = dyn_cast_or_null(FP); 668 | } 669 | 670 | if (!F) 671 | report_fatal_error("Cast to Function failed", true); 672 | 673 | // set visibility to hidden (do not export), unless it is already 674 | // local (for ex. static), in which case we have to make it non-static 675 | if (F->hasLocalLinkage()) { 676 | F->setLinkage(llvm::GlobalValue::ExternalLinkage); 677 | } 678 | F->setVisibility(GlobalValue::HiddenVisibility); 679 | 680 | _FiniFunctions.insert(F->getName()); 681 | } 682 | 683 | if (global_dtors->getNumUses() > 0) 684 | report_fatal_error("llvm.global_dtors uses count is > 0!", false); 685 | 686 | global_dtors->removeFromParent(); 687 | 688 | } 689 | 690 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | --------------------------------------------------------------------------------