@@ -29,7 +29,24 @@ ifdef CONFIG_GCC_PLUGINS
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
+ ifdef CONFIG_X86_INTEL_MPX_KERNEL
+ MPXK_PLUGIN := -fplugin=$(objtree)/scripts/gcc-plugins/mpxk.so
+ gcc-plugin-$(CONFIG_X86_INTEL_MPX_KERNEL) += mpxk.so
+
+ MPXK_CFLAGS := -mmpx -fcheck-pointer-bounds $(MPXK_PLUGIN)
+ MPXK_CFLAGS += -fno-chkp-store-bounds
+ MPXK_CFLAGS += -fno-chkp-use-wrappers
+
+ MPXK_LIB_CFLAGS := $(MPXK_CFLAGS)
+ MPXK_LIB_CFLAGS += -fno-chkp-narrow-bounds
+ MPXK_LIB_CFLAGS += -fno-chkp-check-read
+ MPXK_LIB_CFLAGS += -fno-chkp-check-write
+
+ export MPXK_PLUGIN MPXK_LIB_CFLAGS MPXK_CFLAGS
+ endif
+
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
+ GCC_PLUGINS_CFLAGS := $(filter-out $(MPXK_PLUGIN), $(GCC_PLUGINS_CFLAGS))
export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN
@@ -23,6 +23,12 @@ always := $($(HOSTLIBS)-y)
$(foreach p,$($(HOSTLIBS)-y:%.so=%),$(eval $(p)-objs := $(p).o))
+mpxk-objs += mpxk_builtins.o
+mpxk-objs += mpxk_pass_wrappers.o
+mpxk-objs += mpxk_pass_bnd_store.o
+mpxk-objs += mpxk_pass_cfun_args.o
+mpxk-objs += mpxk_pass_sweeper.o
+
subdir-y := $(GCC_PLUGIN_SUBDIR)
subdir- += $(GCC_PLUGIN_SUBDIR)
new file mode 100644
@@ -0,0 +1,171 @@
+/*
+ * scripts/gcc-plugins/mpxk.c
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+#include <tree-chkp.h>
+#include <ipa-chkp.h>
+
+static void mpxk_plugin_finish(void *gcc_data, void *user_data);
+static tree get_load_fndecl(void);
+
+struct mpxk_bound_store_stats mpxk_stats = {
+ .dropped_ldx = 0,
+ .dropped_stx = 0,
+ .dropped_stx_brute = 0,
+ .wrappers_added = 0,
+ .sweep_ldx = 0,
+ .cfun_ldx = 0,
+ .sweep_stx = 0
+};
+
+#ifndef __visible
+#define __visible
+#endif
+__visible int plugin_is_GPL_compatible;
+
+static struct plugin_info mpxk_plugin_info = {
+ .version = "20170308",
+ .help = "MPX support for kernel space\n"
+};
+
+__visible int plugin_init(
+ struct plugin_name_args *plugin_info,
+ struct plugin_gcc_version *version)
+{
+ const char * const plugin_name = plugin_info->base_name;
+
+ if (!plugin_default_version_check(version, &gcc_version)) {
+ error(G_("incompatible gcc/plugin versions"));
+ return 1;
+ }
+
+ /* First run some sanity checks... */
+ mpxk_builitins_sanity_check();
+
+ /* Register some generic plugin callbacks */
+ register_callback(plugin_name, PLUGIN_INFO, NULL, &mpxk_plugin_info);
+ register_callback(plugin_name, PLUGIN_FINISH,
+ &mpxk_plugin_finish, NULL);
+
+ /* Insert the specialized MPXK passes */
+
+ /* Replace wrappables with mpxk_wrappers. */
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ get_mpxk_wrappers_pass_info());
+
+ /* Remove bndldx/bndstx calls.*/
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ get_mpxk_bnd_store_pass_info());
+
+ /* Handle incoming bounds arguments. */
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ get_mpxk_cfun_args_pass_info());
+
+ /* Brute force removal of all BNDSTX/BNDLDX instructions */
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ get_mpxk_sweeper_pass_info());
+
+
+ return 0;
+}
+
+/**
+ * mpxk_plugin_finish - display some debug data on plugin finish.
+ */
+static void mpxk_plugin_finish(void *gcc_data, void *user_data)
+{
+ (void) gcc_data;
+ (void) user_data;
+
+#ifdef MPXK_DEBUG
+ expanded_location loc = expand_location(input_location);
+
+ fprintf(stderr,
+ "SUMMARY:bndstx[%d+%d=>%d],bndldx[%d+%d=>%d],wraps[%d](%s)\n",
+ mpxk_stats.dropped_stx, mpxk_stats.dropped_stx_brute,
+ mpxk_stats.sweep_stx, mpxk_stats.dropped_ldx,
+ mpxk_stats.cfun_ldx, mpxk_stats.sweep_ldx,
+ mpxk_stats.wrappers_added, loc.file);
+#endif
+}
+
+bool skip_execute(const char *attr)
+{
+ if (attr != NULL && lookup_attribute(attr,
+ DECL_ATTRIBUTES(cfun->decl)) != NULL)
+ return true;
+ return false;
+}
+
+/**
+ * insert_mpxk_bound_load - insert all to the MPXK bound function and bndret.
+ * @gsi: The gimple_stmt_iterator for the insert location.
+ * @pointer: The pointer based on which the bounds are loaded.
+ * @bounds: The bounds variable for storing the loaded bounds.
+ *
+ * This inserts two GIMPLE statements, a gcall to the bounds load function and
+ * a subsequent bndret to store the bounds. The iterator is left on the latter
+ * bndret stmt.
+ */
+void insert_mpxk_bound_load(
+ gimple_stmt_iterator *gsi, tree pointer, tree bounds)
+{
+ tree load_fndecl, tmp_ptr;
+ gcall *load_call;
+
+ /* Prepare mpxk load_bounds call => tmp_ptr = load_call(pointer) */
+ load_fndecl = get_load_fndecl();
+ load_call = gimple_build_call(load_fndecl, 1, pointer);
+
+ /* We need the returned pointer for the latter bndret call */
+ tmp_ptr = create_tmp_var(ptr_type_node, "tmp_ptr");
+ gimple_call_set_lhs(load_call, tmp_ptr);
+
+ /* Set chkp instrumentation stuff */
+ gimple_call_set_with_bounds(load_call, true);
+ gimple_set_plf(load_call, GF_PLF_1, false);
+
+ /* Some error checking */
+ gcc_assert((load_call->subcode & GF_CALL_INTERNAL) == 0);
+ gcc_assert((load_call->subcode & GF_CALL_WITH_BOUNDS) != 0);
+
+ gsi_insert_before(gsi, load_call, GSI_NEW_STMT);
+ chkp_insert_retbnd_call(bounds, tmp_ptr, gsi);
+
+ chkp_set_bounds(pointer, bounds);
+ gimple_call_with_bounds_p(load_call);
+
+ update_stmt(load_call);
+}
+
+/**
+ * get_load_fndecl - Return fndecl for the MPXK bounds load function
+ */
+static tree get_load_fndecl(void)
+{
+ tree parm_type_list, fntype, fndecl;
+
+ parm_type_list = build_tree_list_stat(NULL_TREE, ptr_type_node);
+
+ fntype = build_function_type(ptr_type_node, parm_type_list);
+ fntype = chkp_copy_function_type_adding_bounds(fntype);
+
+ fndecl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
+ get_identifier(MPXK_LOAD_BOUNDS_FN_NAME), fntype);
+
+ DECL_EXTERNAL(fndecl) = 1;
+
+ DECL_RESULT(fndecl) = build_decl(UNKNOWN_LOCATION, RESULT_DECL,
+ NULL_TREE, ptr_type_node);
+
+ DECL_ATTRIBUTES(fndecl) = tree_cons(get_identifier("bnd_legacy"),
+ NULL, DECL_ATTRIBUTES(fndecl));
+
+ TREE_PUBLIC(DECL_RESULT(fndecl)) = 1;
+
+ return fndecl;
+}
new file mode 100644
@@ -0,0 +1,60 @@
+/*
+ * mpxk.h - MPXK plugin main header
+ *
+ * Copyright (C) 2017 Hans Liljestrand <LiljestrandH@gmail.com>
+ *
+ * This file is released under the GPLv2.
+ */
+#ifndef PLUGIN_MPX_PLUGIN_H
+#define PLUGIN_MPX_PLUGIN_H
+
+#include "gcc-common.h"
+
+#define BND_LEGACY "bnd_legacy"
+
+#define MPXK_BND_REGS 4
+#define MPXK_LOAD_BOUNDS_FN_NAME "mpxk_load_bounds"
+#define MPXK_WRAPPER_PREFIX "mpxk_wrapper_"
+
+/* #define MPXK_DEBUG */
+
+struct mpxk_bound_store_stats {
+ int dropped_ldx;
+ int dropped_stx;
+ int dropped_stx_brute;
+ int wrappers_added;
+ int sweep_ldx;
+ int cfun_ldx;
+ int sweep_stx;
+};
+
+/* Store some shared stats on current unit. */
+extern struct mpxk_bound_store_stats mpxk_stats;
+
+/* defined in mpxk.c */
+bool skip_execute(const char *attr);
+void insert_mpxk_bound_load(
+ gimple_stmt_iterator *gsi, tree pointer, tree bounds);
+
+/* passes are defined in the mpxk_pass*.c files */
+struct register_pass_info *get_mpxk_wrappers_pass_info(void);
+struct register_pass_info *get_mpxk_bnd_store_pass_info(void);
+struct register_pass_info *get_mpxk_cfun_args_pass_info(void);
+struct register_pass_info *get_mpxk_sweeper_pass_info(void);
+
+/* mpxk_builtins.c */
+void mpxk_builitins_sanity_check(void);
+bool mpxk_is_wrappable(const char *name);
+bool mpxk_is_wrapper(const char *name);
+const char *mpxk_get_wrapper_name(const char *name);
+
+#ifdef MPXK_DEBUG
+#define dsay_print(m, ...) fprintf(stderr, "%s (%s): " m "\n", \
+ DECL_NAME_POINTER(current_function_decl), \
+ __func__, __VA_ARGS__)
+#define dsay(...) dsay_print(__VA_ARGS__)
+#else
+#define dsay(...)
+#endif /* MPXK_DEBUG */
+
+#endif /* PLUGIN_MPX_PLUGIN_H */
new file mode 100644
@@ -0,0 +1,102 @@
+/*
+ * scripts/gcc-plugins/mpxk_builtins.c
+ *
+ * Defines various helper functions for identifying interesting functions
+ * and converting names for wrapper functions.
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+
+static int wrapper_i(const char *name);
+static int builtin_i(const char *name);
+
+struct mpxk_builtin {
+ const bool is_wrapper;
+ const bool is_loader;
+ const char *name;
+};
+
+static const struct mpxk_builtin mpxk_fndecls[] = {
+#define MPXK_BUILTIN_DEF(r, x, ...) \
+ { .is_wrapper = 0, .is_loader = 1, .name = #x },
+#define MPXK_WRAPPER_DEF(r, x, ...) \
+ { .is_wrapper = 1, .is_loader = 0, .name = MPXK_WRAPPER_PREFIX #x },
+#include "mpxk_builtins.def"
+#undef MPXK_WRAPPER_DEF
+#undef MPXK_BUILTIN_DEF
+};
+
+bool mpxk_is_wrapper(const char *name)
+{
+ gcc_assert(name != NULL);
+ return (bool) (wrapper_i(name) >= 0);
+}
+
+const char *mpxk_get_wrapper_name(const char *name)
+{
+ gcc_assert(name != NULL);
+
+ char wr_name[strlen(MPXK_WRAPPER_PREFIX) + strlen(name) + 1];
+
+ sprintf(wr_name, "%s%s", MPXK_WRAPPER_PREFIX, name);
+
+ const int i = wrapper_i(wr_name);
+
+ if (i >= 0)
+ return mpxk_fndecls[i].name;
+
+ return NULL;
+}
+
+bool mpxk_is_wrappable(const char *name)
+{
+ gcc_assert(name != NULL);
+ return (bool) (mpxk_get_wrapper_name(name) != NULL);
+}
+
+static int builtin_i(const char *name)
+{
+ gcc_assert(name != NULL);
+
+ for (int i = 0; i < ARRAY_SIZE(mpxk_fndecls); i++) {
+ gcc_assert(mpxk_fndecls[i].name != NULL);
+
+ if (strcmp(mpxk_fndecls[i].name, name) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static int wrapper_i(const char *name)
+{
+ gcc_assert(name != NULL);
+ const int i = builtin_i(name);
+
+ return (i == -1 ? -1 : (mpxk_fndecls[i].is_wrapper ? i : -1));
+}
+
+void mpxk_builitins_sanity_check(void)
+{
+ (void) gcc_version;
+
+ gcc_assert(strcmp(MPXK_WRAPPER_PREFIX "kmalloc",
+ mpxk_get_wrapper_name("kmalloc")) == 0);
+
+ gcc_assert(builtin_i(MPXK_LOAD_BOUNDS_FN_NAME) >= 0);
+ gcc_assert(builtin_i("mpxk_wrapper_kmalloc") >= 0);
+ gcc_assert(mpxk_is_wrapper("mpxk_wrapper_kmalloc"));
+ gcc_assert(mpxk_is_wrapper(MPXK_WRAPPER_PREFIX "kmalloc"));
+ gcc_assert(mpxk_is_wrappable("kmalloc"));
+
+ gcc_assert(!mpxk_is_wrapper(MPXK_LOAD_BOUNDS_FN_NAME));
+ gcc_assert(builtin_i("kmalloc") < 0);
+ gcc_assert(!mpxk_is_wrapper("kmalloc"));
+ gcc_assert(builtin_i("mpxk_wrapper_not_good_at_all") < 0);
+ gcc_assert(!mpxk_is_wrapper("mpxk_wrapper_not_good_at_all"));
+ gcc_assert(!mpxk_is_wrapper("_" MPXK_WRAPPER_PREFIX "kmalloc"));
+ gcc_assert(!mpxk_is_wrappable(MPXK_WRAPPER_PREFIX "kmalloc"));
+}
new file mode 100644
@@ -0,0 +1,41 @@
+/*
+ * scripts/gcc-plugins/mpxk_builtins.def - MPXK wrapper definitions
+ *
+ * Keep these centralized here so they are easy to pull into both the
+ * gcc-plugin and into the actual in-kernel function implementations.
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+
+MPXK_BUILTIN_DEF(void *, mpxk_load_bounds, void *p)
+
+MPXK_WRAPPER_DEF(void *, kmalloc, size_t s, gfp_t f)
+MPXK_WRAPPER_DEF(void *, krealloc, void *p, size_t s, gfp_t f)
+
+MPXK_WRAPPER_DEF(void *, memmove, void *d, const void *s, size_t c)
+MPXK_WRAPPER_DEF(void *, memcpy, void *d, const void *s, size_t c)
+MPXK_WRAPPER_DEF(void *, __memcpy, void *d, const void *s, size_t c)
+MPXK_WRAPPER_DEF(void *, __inline_memcpy, void *d, const void *s, size_t c)
+
+MPXK_WRAPPER_DEF(void *, memset, void *s, int c, size_t l)
+MPXK_WRAPPER_DEF(char *, strcat, char *d, const char *s)
+MPXK_WRAPPER_DEF(char *, strncat, char *d, const char *s, size_t c)
+MPXK_WRAPPER_DEF(char *, strcpy, char *d, const char *s)
+MPXK_WRAPPER_DEF(char *, strncpy, char *d, const char *s, size_t c)
+MPXK_WRAPPER_DEF(size_t, strlen, const char *s)
+MPXK_WRAPPER_DEF(size_t, strnlen, const char *s, size_t c)
+
+/* libmpx wrappers that MPXK doesn't provide
+__mpx_wrapper_malloc; - malloc in linux/decompress/mm.h only for pre-boot
+__mpx_wrapper_mmap; - N/A
+__mpx_wrapper_realloc; - N/A
+__mpx_wrapper_calloc; - N/A
+__mpx_wrapper_bzero; - N/A
+__mpx_wrapper_mempcpy; - N/A
+__mpx_wrapper_stpcpy; - N/A
+__mpx_wrapper_stpncpy; - N/A
+*/
+
+// vim: ft=cpp
new file mode 100644
@@ -0,0 +1,147 @@
+/*
+ * scripts/gcc-plugins/mpxk.c - Handle basic bndstx/bndldx cases.
+ *
+ * This GIMPLE, post chkp, pass removes any encountered bndstx and bndldx
+ * calls. The bndldx calls are replaces with calls to the MPXK bound load
+ * function. Note that this only catches statements added during the chkp
+ * GIMPLE passes, and does not handle stores and loads due to function
+ * arguments (and potentially other cases).
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+
+#include <ipa-chkp.h>
+#include <tree-chkp.h>
+
+static unsigned int mpxk_bnd_store_execute(void);
+
+static void handle_ldx(gimple_stmt_iterator *gsi, gcall *call);
+static void handle_stx(gimple_stmt_iterator *gsi, gcall *call);
+
+#define PASS_NAME mpxk_bnd_store
+#define NO_GATE
+#include "gcc-generate-gimple-pass.h"
+
+static struct register_pass_info pass_info_mpxk_bnd_store = {
+ .pass = make_mpxk_bnd_store_pass(),
+ .reference_pass_name = "optimized",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_BEFORE
+};
+
+struct register_pass_info *get_mpxk_bnd_store_pass_info(void)
+{
+ (void) gcc_version;
+ return &pass_info_mpxk_bnd_store;
+}
+
+static unsigned int mpxk_bnd_store_execute(void)
+{
+ basic_block bb, next;
+ gimple stmt;
+ gimple_stmt_iterator iter;
+ gcall *call;
+ tree fndecl;
+
+ if (skip_execute(BND_LEGACY))
+ return 0;
+
+ const char *name = DECL_NAME_POINTER(cfun->decl);
+
+ bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb;
+ do {
+ next = bb->next_bb;
+ for (iter = gsi_start_bb(bb); !gsi_end_p(iter); ) {
+ stmt = gsi_stmt(iter);
+
+ switch (gimple_code(stmt)) {
+ case GIMPLE_CALL:
+ call = as_a<gcall *>(gsi_stmt(iter));
+ fndecl = gimple_call_fndecl(call);
+
+ /* Wrapper functions shouldn't end up here! */
+ gcc_assert(!mpxk_is_wrapper(name));
+
+ if (!fndecl)
+ break;
+
+ if (!strcmp(DECL_NAME_POINTER(fndecl),
+ "__builtin_ia32_bndstx"))
+ handle_stx(&iter, call);
+ else if (!strcmp(DECL_NAME_POINTER(fndecl),
+ "__builtin_ia32_bndldx"))
+ handle_ldx(&iter, call);
+
+ break;
+ default:
+ break;
+ }
+
+ gsi_next(&iter);
+ }
+ bb = next;
+ } while (bb);
+
+ return 0;
+}
+
+/**
+ * handle_stx - Remove bndstx statement at iterator.
+ * @gsi - Statement iterator.
+ * @call - The call to remove.
+ */
+static void handle_stx(gimple_stmt_iterator *gsi, gcall *call)
+{
+ dsay("removed bndstx call in at %s:%d\n",
+ gimple_filename(call), gimple_lineno(call));
+ gcc_assert(!strcmp(DECL_NAME_POINTER(gimple_call_fndecl(call)),
+ "__builtin_ia32_bndstx"));
+
+ /* Remove stmt and update iterator so next item is correct */
+ gsi_remove(gsi, true);
+ gsi_prev(gsi);
+
+ unlink_stmt_vdef(call);
+
+ mpxk_stats.dropped_stx++;
+}
+
+/**
+ * handle_ldx - Remove bndldx and replace it with MPXK bound load
+ * @gsi - Statement iterator.
+ * @call - The call to remove.
+ *
+ * We want to remove:
+ * bounds = bndldx(orig_ptr)
+ * And insert:
+ * tmp_ptr = load_bounds(orig_ptr)
+ * bounds = bndret(tmp_ptr)
+ */
+static void handle_ldx(gimple_stmt_iterator *gsi, gcall *call)
+{
+ tree orig_ptr, bounds;
+
+ dsay("replaced bndldx call in at %s:%d",
+ gimple_filename(call), gimple_lineno(call));
+ gcc_assert(!strcmp(DECL_NAME_POINTER(gimple_call_fndecl(call)),
+ "__builtin_ia32_bndldx"));
+
+ /* Store what we need from the bndldx_call */
+ orig_ptr = gimple_call_arg(call, 1);
+ bounds = gimple_call_lhs(call);
+
+ /* Remove the bndldx call, which moves iterator to next stmt. */
+ gsi_remove(gsi, true);
+ unlink_stmt_vdef(call);
+
+ /* Now insert our own load bounds function */
+ insert_mpxk_bound_load(gsi, orig_ptr, bounds);
+
+ /* Make sure iterator points to last statement we worked on */
+ gsi_prev(gsi);
+
+ mpxk_stats.dropped_ldx++;
+}
new file mode 100644
@@ -0,0 +1,98 @@
+/*
+ * scripts/gcc-plugins/mpxk_pass_cfun_args.c - MPXK pass for cfun arguments
+ *
+ * Simple pass that only checks the current function (cfun) arguments for
+ * pointer bound counts that exceed the available bndreg count. Such bounds
+ * are then manually initialized at function start using the MPXK bound
+ * load function.
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+
+#include <ipa-chkp.h>
+#include <tree-chkp.h>
+
+static unsigned int mpxk_cfun_args_execute(void);
+
+#define PASS_NAME mpxk_cfun_args
+#define NO_GATE
+#include "gcc-generate-gimple-pass.h"
+
+static struct register_pass_info pass_info_mpxk_cfun_args = {
+ .pass = make_mpxk_cfun_args_pass(),
+ .reference_pass_name = "optimized",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_BEFORE
+};
+
+struct register_pass_info *get_mpxk_cfun_args_pass_info(void)
+{
+ (void) gcc_version;
+ return &pass_info_mpxk_cfun_args;
+}
+
+static unsigned int mpxk_cfun_args_execute(void)
+{
+ int bound_count = 0;
+ int arg_count = 0;
+ basic_block bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb;
+ gimple_stmt_iterator iter = gsi_start_bb(bb);
+ tree list = DECL_ARGUMENTS(cfun->decl);
+ tree prev = NULL;
+
+ if (skip_execute(BND_LEGACY))
+ return 0;
+
+ if (list == NULL || list_length(list) == 0)
+ return 0;
+
+ tree *p;
+
+ for (p = &list; *p; ) {
+ tree l = *p;
+
+ /* Keep count of the encountered bounds args */
+ if (TREE_TYPE(l) == pointer_bounds_type_node) {
+ bound_count++;
+
+ iter = gsi_start_bb(bb);
+
+ /* Replace BNDLDX loaded bounds with mpxk_load_bounds.
+ *
+ * This happens in two scenarios:
+ * - There are more bounds than available registers (>4)
+ * - The bounds are for arguments beyond the sixth
+ * argument, this is *feature* seems to be related to
+ * how non-bound arguments are treated (i.e. 6 args
+ * are passed via regs before using the stack for
+ * arguments).
+ */
+ if (bound_count > MPXK_BND_REGS || arg_count > 6) {
+ dsay("resetting bound argument #%d (ptr > #6)",
+ bound_count);
+ gcc_assert(prev != NULL);
+ insert_mpxk_bound_load(&iter, prev, l);
+ }
+
+ p = &TREE_CHAIN(l);
+ } else {
+ dsay("skipping non-bound argument #%d", arg_count);
+ prev = l;
+ arg_count++;
+ p = &TREE_CHAIN(l);
+ }
+
+ /* The previous arg is needed if we need a MPXK load. */
+ *p = TREE_CHAIN(l);
+ }
+
+ bound_count = (bound_count <= MPXK_BND_REGS ? 0 :
+ (bound_count - MPXK_BND_REGS));
+
+ mpxk_stats.cfun_ldx += bound_count;
+ dsay("replaced %d bound args with mpkx_load_bounds", bound_count);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,107 @@
+/*
+ * scripts/gcc-plugins/mpxk_pass_sweeper.c - removes BND{STX,LDX}
+ *
+ * Brute force RTL pass that removes all BNDSTX/BNDLDX instructions.
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+#include <rtl.h>
+#include <print-rtl.h>
+
+static unsigned int mpxk_sweeper_execute(void);
+static bool contains_unspec(rtx pattern, const int code);
+
+#define PASS_NAME mpxk_sweeper
+#define NO_GATE
+#include "gcc-generate-rtl-pass.h"
+
+static struct register_pass_info pass_info_mpxk_sweeper = {
+ .pass = make_mpxk_sweeper_pass(),
+ .reference_pass_name = "final",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_BEFORE
+};
+
+struct register_pass_info *get_mpxk_sweeper_pass_info(void)
+{
+ (void) gcc_version;
+ return &pass_info_mpxk_sweeper;
+}
+
+static unsigned int mpxk_sweeper_execute(void)
+{
+ expanded_location loc;
+ basic_block bb, next;
+ rtx_insn *insn;
+ rtx r;
+ int found = 0;
+
+ if (skip_execute(NULL))
+ return 0;
+
+ loc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+
+ bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb;
+ do {
+ next = bb->next_bb;
+ for (insn = BB_HEAD(bb);
+ insn != BB_END(bb);
+ insn = NEXT_INSN(insn)) {
+ r = PATTERN(insn);
+ if (INSN_LOCATION(insn) != UNKNOWN_LOCATION)
+ loc = insn_location(insn);
+
+ if (r != NULL) {
+ if (contains_unspec(r, UNSPEC_BNDSTX)) {
+ dsay("removed bndstx at %s:%d",
+ loc.file, loc.line);
+ delete_insn(insn);
+ mpxk_stats.sweep_stx++;
+ found++;
+ }
+ if (contains_unspec(r, UNSPEC_BNDLDX) ||
+ contains_unspec(r, UNSPEC_BNDLDX_ADDR)) {
+ dsay("removed bndldx at %s:%d",
+ loc.file, loc.line);
+ delete_insn(insn);
+ mpxk_stats.sweep_ldx++;
+ found++;
+ }
+ }
+ }
+ bb = next;
+ } while (bb);
+
+ loc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+ return 0;
+}
+
+static bool contains_unspec(rtx r, const int code)
+{
+ int i;
+
+ gcc_assert(r != NULL);
+
+ if (GET_CODE(r) == UNSPEC || GET_CODE(r) == UNSPEC_VOLATILE) {
+ if (XINT(r, 1) == code)
+ return true;
+ } else if (GET_CODE(r) == PARALLEL || GET_CODE(r) == SEQUENCE) {
+ for (i = 0; i < XVECLEN(r, 0); i++) {
+ if (contains_unspec(XVECEXP(r, 0, i), code))
+ return true;
+ }
+ } else if (GET_CODE(r) == UNSPEC || GET_CODE(r) == UNSPEC_VOLATILE) {
+ if (XINT(r, 1) == code)
+ return true;
+ } else if (GET_CODE(r) == SET) {
+ if (contains_unspec(SET_SRC(r), code))
+ return true;
+ if (contains_unspec(SET_DEST(r), code))
+ return true;
+ }
+
+ return false;
+}
new file mode 100644
@@ -0,0 +1,128 @@
+/*
+ * scripts/gcc-plugins/mpxk_pass_wrappers.c - insert mpxk wrappers
+ *
+ * A pre-chkp pass that inserts MPXK wrappers for covered memory altering
+ * functions such as kmalloc & friends.
+ *
+ * Copyright (C) 2017 Aalto University
+ *
+ * This file is released under the GPLv2.
+ */
+#include "mpxk.h"
+#include <ipa-chkp.h>
+
+static unsigned int mpxk_wrappers_execute(void);
+static void mpxk_wrappers_gimple_call(gimple_stmt_iterator *gsi);
+
+#define PASS_NAME mpxk_wrappers
+#define NO_GATE
+#include "gcc-generate-gimple-pass.h"
+
+struct register_pass_info pass_info_mpxk_wrappers = {
+ .pass = make_mpxk_wrappers_pass(),
+ .reference_pass_name = "cfg",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_AFTER
+};
+
+struct register_pass_info *get_mpxk_wrappers_pass_info(void)
+{
+ (void) gcc_version;
+ return &pass_info_mpxk_wrappers;
+}
+
+static unsigned int mpxk_wrappers_execute(void)
+{
+ tree fndecl;
+ basic_block bb, next;
+ gimple_stmt_iterator iter;
+ gimple stmt;
+
+ if (skip_execute(BND_LEGACY))
+ return 0;
+
+ /* Do not modify wrapper functions */
+ if (mpxk_is_wrapper(DECL_NAME_POINTER(cfun->decl)))
+ return 0;
+
+ bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb;
+ do {
+ next = bb->next_bb;
+ for (iter = gsi_start_bb(bb); !gsi_end_p(iter); ) {
+ stmt = gsi_stmt(iter);
+
+ if (gimple_code(stmt) == GIMPLE_CALL) {
+ fndecl = gimple_call_fndecl(
+ as_a<gcall *>(stmt));
+
+ if (fndecl && mpxk_is_wrappable(
+ DECL_NAME_POINTER(fndecl))) {
+ dsay("inserting wrapper for %s",
+ DECL_NAME_POINTER(fndecl));
+ mpxk_wrappers_gimple_call(&iter);
+ }
+ }
+
+ gsi_next(&iter);
+ }
+ bb = next;
+ } while (bb);
+
+ return 0;
+}
+
+/**
+ * mpxk_wrappers_gimple_call - Replace wrappables with wrappers.
+ * @param gsi
+ *
+ * Based on gcc/tree-chkp.c ~ chkp_add_bounds_to_call_stmt
+ */
+static void mpxk_wrappers_gimple_call(gimple_stmt_iterator *gsi)
+{
+ tree arg, type, new_decl, fndecl;
+ const char *new_name, *name;
+ gcall *call;
+
+ /* Get the current data */
+ call = as_a<gcall *>(gsi_stmt(*gsi));
+ fndecl = gimple_call_fndecl(call);
+ name = DECL_NAME_POINTER(fndecl);
+
+ /* Create data for new call */
+ new_decl = copy_node(fndecl);
+ new_name = mpxk_get_wrapper_name(name);
+ gcc_assert(new_name != NULL);
+
+ /* Set visibility. TODO: do we need this? */
+ DECL_VISIBILITY(new_decl) = VISIBILITY_DEFAULT;
+
+ /* Set wrapper name */
+ DECL_NAME(new_decl) = get_identifier(new_name);
+ SET_DECL_ASSEMBLER_NAME(new_decl, get_identifier(new_name));
+
+ /* Copy function arguments */
+ DECL_ARGUMENTS(new_decl) = copy_list(DECL_ARGUMENTS(fndecl));
+ for (arg = DECL_ARGUMENTS(new_decl); arg; arg = DECL_CHAIN(arg))
+ DECL_CONTEXT(arg) = new_decl;
+
+ /* Copy and modify function attributes */
+ DECL_ATTRIBUTES(new_decl) = remove_attribute("always_inline",
+ copy_list(DECL_ATTRIBUTES(fndecl)));
+
+ /* Mark the funciton external */
+ DECL_EXTERNAL(new_decl) = 1;
+
+ gimple_call_set_fndecl(call, new_decl);
+
+ /* TODO: Double check if manual fntype bounds add is needed. */
+ type = gimple_call_fntype(call);
+ type = chkp_copy_function_type_adding_bounds(type);
+ gimple_call_set_fntype(call, type);
+
+ update_stmt(call);
+
+ mpxk_stats.wrappers_added++;
+
+ dsay("inserted %s at %s:%d\n",
+ new_name, gimple_filename(call), gimple_lineno(call));
+}