linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/2] Introduce the initify gcc plugin
@ 2016-06-28 11:34 Emese Revfy
  2016-06-28 11:35 ` [PATCH v1 1/2] Add " Emese Revfy
                   ` (6 more replies)
  0 siblings, 7 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 11:34 UTC (permalink / raw)
  To: kernel-hardening
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

I would like to introduce the initify gcc plugin. The kernel already has
a mechanism to free up code and data memory that is only used during kernel
or module initialization.
This plugin will teach the compiler to find more such code and data that
can be freed after initialization. It reduces memory usage.
The initify gcc plugin can be useful for embedded systems.

It is a CII project supported by the Linux Foundation.

This plugin is the part of grsecurity/PaX.

The plugin supports all gcc versions from 4.5 to 6.0.

I made some changes on top of the PaX version (since March 6.). These are
the important ones:
 * move all local strings to init.rodata.str and exit.rodata.str
   (not just __func__)
 * report all initified strings and functions
   (GCC_PLUGIN_INITIFY_VERBOSE config option)
 * automatically discover init/exit functions and apply the __init or
   __exit attributes on them

You can find more about the changes here:
https://github.com/ephox-gcc-plugins/initify

This patch set is based on the "Add support for complex gcc plugins that
don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
e5d4798b284cd192c8b).

Some statistics about the plugin:

On allyes config (amd64, gcc-6):
* 7731 initified strings
*  231 initified functions

On allmod config (i386, gcc-6):
* 8846 initified strings
*  252 initified functions

On allyes config (amd64, gcc-6):

section         vanilla                 vanilla + initify        change
-----------------------------------------------------------------------
.rodata         39059688 (0x25400e8)    38527210 (0x24be0ea)    -532478
.data           45744128 (0x2ba0000)    45404160 (0x2b4d000)    -339968
.init.data       1361144  (0x14c4f8)     1674200  (0x198bd8)    +313056
.text           77615128 (0x4a05018)    77576664 (0x49fb9d8)     -38464
.init.text       1108455  (0x10e9e7)     1137618  (0x115bd2)     +29163


Emese Revfy (2):
 Add the initify gcc plugin
 Mark functions with the __nocapture attribute

---
 arch/Kconfig                         |   23 +
 arch/arm/include/asm/string.h        |   10 +-
 arch/arm64/include/asm/string.h      |   23 +-
 arch/powerpc/include/asm/string.h    |   19 +-
 arch/x86/boot/string.h               |    4 +-
 arch/x86/include/asm/string_32.h     |   21 +-
 arch/x86/include/asm/string_64.h     |   18 +-
 arch/x86/kernel/hpet.c               |    2 +-
 include/asm-generic/bug.h            |    6 +-
 include/asm-generic/vmlinux.lds.h    |    2 +
 include/linux/compiler-gcc.h         |   10 +-
 include/linux/compiler.h             |    4 +
 include/linux/fs.h                   |    5 +-
 include/linux/printk.h               |    2 +-
 include/linux/string.h               |   73 +--
 scripts/Makefile.gcc-plugins         |    4 +
 scripts/gcc-plugins/initify_plugin.c | 1147 ++++++++++++++++++++++++++++++++++
 17 files changed, 1283 insertions(+), 90 deletions(-)

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v1 1/2] Add the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
@ 2016-06-28 11:35 ` Emese Revfy
  2016-06-28 21:05   ` Rasmus Villemoes
  2016-06-28 11:36 ` [PATCH v1 2/2] Mark functions with the __nocapture attribute Emese Revfy
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 11:35 UTC (permalink / raw)
  To: kernel-hardening
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

The kernel already has a mechanism to free up code and data memory that
is only used during kernel or module initialization.
This plugin will teach the compiler to find more such code and data that
can be freed after initialization.
It has two passes. The first one tries to find all functions that
can be become __init/__exit. The second one moves string constants
(local variables and function string arguments marked by
the nocapture attribute) only referenced in __init/__exit functions
to the __initconst/__exitconst sections.
It reduces memory usage. This plugin can be useful for embedded systems.

The instrumentation pass of the latent_entropy plugin must run after
the initify plugin to increase coverage.

Signed-off-by: Emese Revfy <re.emese@gmail.com>
---
 arch/Kconfig                         |   23 +
 include/asm-generic/vmlinux.lds.h    |    2 +
 scripts/Makefile.gcc-plugins         |    4 +
 scripts/gcc-plugins/initify_plugin.c | 1147 ++++++++++++++++++++++++++++++++++
 4 files changed, 1176 insertions(+)
 create mode 100644 scripts/gcc-plugins/initify_plugin.c

diff --git a/arch/Kconfig b/arch/Kconfig
index 9f8c6ee..35b01a4 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -417,6 +417,29 @@ config GCC_PLUGIN_LATENT_ENTROPY
 	   * https://grsecurity.net/
 	   * https://pax.grsecurity.net/
 
+config GCC_PLUGIN_INITIFY
+	bool "Free more kernel memory after init"
+	depends on GCC_PLUGINS
+	help
+	  The kernel has a mechanism to free up code and data memory that is
+	  only used during kernel or module initialization.  Enabling this
+	  feature will teach the compiler to find more such code and data
+	  that can be freed after initialization.
+
+	  This plugin is the part of grsecurity/PaX. More information at:
+	   * https://grsecurity.net/
+	   * https://pax.grsecurity.net/
+
+config GCC_PLUGIN_INITIFY_VERBOSE
+	bool "Verbose"
+	depends on GCC_PLUGIN_INITIFY
+	help
+	  Print all initified strings and all functions which should be
+	  __init/__exit.
+	  Note that the candidates identified for __init/__exit markings
+	  depend on the current kernel configuration and thus should be verified
+	  manually before the source code is patched.
+
 config HAVE_CC_STACKPROTECTOR
 	bool
 	help
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 6a67ab9..651980b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -523,6 +523,7 @@
 	MEM_DISCARD(init.data)						\
 	KERNEL_CTORS()							\
 	MCOUNT_REC()							\
+	*(.init.rodata.str)						\
 	*(.init.rodata)							\
 	FTRACE_EVENTS()							\
 	TRACE_SYSCALLS()						\
@@ -547,6 +548,7 @@
 #define EXIT_DATA							\
 	*(.exit.data)							\
 	MEM_DISCARD(exit.data)						\
+	*(.exit.rodata.str)						\
 	MEM_DISCARD(exit.rodata)
 
 #define EXIT_TEXT							\
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 1f922df..0ce8392 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -12,6 +12,10 @@ ifdef CONFIG_GCC_PLUGINS
     DISABLE_LATENT_ENTROPY_PLUGIN			+= -fplugin-arg-latent_entropy_plugin-disable
   endif
 
+  gcc-plugin-$(CONFIG_GCC_PLUGIN_INITIFY)		+= initify_plugin.so
+  gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_INITIFY)	+= -DINITIFY_PLUGIN -fplugin-arg-initify_plugin-search_init_exit_functions
+  gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_INITIFY_VERBOSE)+= -fplugin-arg-initify_plugin-verbose
+
   ifdef CONFIG_GCC_PLUGIN_SANCOV
     ifeq ($(CFLAGS_KCOV),)
       # It is needed because of the gcc-plugin.sh and gcc version checks.
diff --git a/scripts/gcc-plugins/initify_plugin.c b/scripts/gcc-plugins/initify_plugin.c
new file mode 100644
index 0000000..d5dfce5
--- /dev/null
+++ b/scripts/gcc-plugins/initify_plugin.c
@@ -0,0 +1,1147 @@
+/*
+ * Copyright 2015-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/initify
+ *
+ * This plugin has two passes. The first one tries to find all functions that
+ * can be become __init/__exit. The second one moves string constants
+ * (local variables and function string arguments marked by
+ * the nocapture attribute) only referenced in __init/__exit functions
+ * to __initconst/__exitconst sections.
+ * Based on an idea from Mathias Krause <minipli@ld-linux.so>.
+ *
+ * The instrumentation pass of the latent_entropy plugin must run after
+ * the initify plugin to increase coverage.
+ *
+ * Options:
+ * -fplugin-arg-initify_plugin-disable
+ * -fplugin-arg-initify_plugin-verbose
+ * -fplugin-arg-initify_plugin-print_missing_attr
+ * -fplugin-arg-initify_plugin-search_init_exit_functions
+ *
+ * Attribute: __attribute__((nocapture(x, y ...)))
+ *  The nocapture gcc attribute can be on functions only.
+ *  The attribute takes one or more unsigned integer constants as parameters
+ *  that specify the function argument(s) of const char* type to initify.
+ *  If the marked argument is a vararg then the plugin initifies
+ *  all vararg arguments.
+ *
+ * Usage:
+ * $ make
+ * $ make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info initify_plugin_info = {
+	.version	=	"20160627vanilla",
+	.help		=	"disable\tturn off the initify plugin\n"
+				 "verbose\tprint all initified strings and all"
+				 " functions which should be __init/__exit\n"
+				 "print_missing_attr\tprint functions which"
+				 " can be marked by nocapture attribute\n"
+				 "search_init_exit_functions\tsearch function"
+				 " which should be marked by __init or __exit"
+				 " attribute\n"
+};
+
+static struct cgraph_2node_hook_list *node_duplication_hook_holder;
+#define ARGNUM_NONE 0
+static bool verbose, print_missing_attr, search_init_exit_functions;
+
+enum section_type {
+	INIT, EXIT, NONE
+};
+
+#if BUILDING_GCC_VERSION >= 5000
+typedef struct hash_set<const_gimple> gimple_set;
+
+static inline bool pointer_set_insert(gimple_set *visited, const_gimple stmt)
+{
+	return visited->add(stmt);
+}
+
+static inline bool pointer_set_contains(gimple_set *visited, const_gimple stmt)
+{
+	return visited->contains(stmt);
+}
+
+static inline gimple_set* pointer_set_create(void)
+{
+	return new hash_set<const_gimple>;
+}
+
+static inline void pointer_set_destroy(gimple_set *visited)
+{
+	delete visited;
+}
+#else
+typedef struct pointer_set_t gimple_set;
+#endif
+
+static void walk_def_stmt(bool *has_str_cst, gimple_set *visited, tree node);
+
+/* nocapture attribute:
+ *  * to mark nocapture function arguments. If used on a vararg argument
+ *    it applies to all of them that have no other uses.
+ *  * attribute value 0 is ignored to allow reusing print attribute arguments
+ */
+static tree handle_nocapture_attribute(tree *node, tree __unused name,
+					tree args, int __unused flags,
+					bool *no_add_attrs)
+{
+	tree orig_attr, arg;
+
+	*no_add_attrs = true;
+	switch (TREE_CODE(*node)) {
+	case FUNCTION_DECL:
+	case FUNCTION_TYPE:
+	case METHOD_TYPE:
+		break;
+
+	case TYPE_DECL: {
+		enum tree_code fn_code;
+		const_tree fntype = TREE_TYPE(*node);
+
+		fn_code = TREE_CODE(fntype);
+		if (fn_code == POINTER_TYPE)
+			fntype = TREE_TYPE(fntype);
+		fn_code = TREE_CODE(fntype);
+		if (fn_code == FUNCTION_TYPE || fn_code == METHOD_TYPE)
+			break;
+		/* FALLTHROUGH */
+	}
+
+	default:
+		debug_tree(*node);
+		error("%s: %qE attribute only applies to functions",
+			__func__, name);
+		return NULL_TREE;
+	}
+
+	for (arg = args; arg; arg = TREE_CHAIN(arg)) {
+		tree position = TREE_VALUE(arg);
+
+		if (TREE_CODE(position) != INTEGER_CST) {
+			error("%qE parameter of the %qE attribute isn't an integer (fn: %qE)",
+				position, name, *node);
+			return NULL_TREE;
+		}
+
+		if (tree_int_cst_lt(position, integer_minus_one_node)) {
+			error("%qE parameter of the %qE attribute less than 0 (fn: %qE)",
+				position, name, *node);
+			return NULL_TREE;
+		}
+	}
+
+	orig_attr = lookup_attribute("nocapture", DECL_ATTRIBUTES(*node));
+	if (orig_attr)
+		chainon(TREE_VALUE(orig_attr), args);
+	else
+		*no_add_attrs = false;
+
+	return NULL_TREE;
+}
+
+static struct attribute_spec nocapture_attr = {
+	.name				= "nocapture",
+	.min_length			= 1,
+	.max_length			= -1,
+	.decl_required			= true,
+	.type_required			= false,
+	.function_type_required		= false,
+	.handler			= handle_nocapture_attribute,
+#if BUILDING_GCC_VERSION >= 4007
+	.affects_type_identity		= false
+#endif
+};
+
+static void register_attributes(void __unused *event_data, void __unused *data)
+{
+	register_attribute(&nocapture_attr);
+}
+
+/* Determine whether the function is in the init or exit sections. */
+static enum section_type get_init_exit_section(const_tree decl)
+{
+	const char *str;
+	const_tree section, attr_value;
+
+	section = lookup_attribute("section", DECL_ATTRIBUTES(decl));
+	if (!section)
+		return NONE;
+
+	attr_value = TREE_VALUE(section);
+	gcc_assert(attr_value != NULL_TREE);
+	gcc_assert(list_length(attr_value) == 1);
+
+	str = TREE_STRING_POINTER(TREE_VALUE(attr_value));
+
+	if (!strncmp(str, ".init.", 6))
+		return INIT;
+	if (!strncmp(str, ".exit.", 6))
+		return EXIT;
+	return NONE;
+}
+
+static tree get_string_cst(tree var)
+{
+	if (var == NULL_TREE)
+		return NULL_TREE;
+
+	if (TREE_CODE(var) == STRING_CST)
+		return var;
+
+	switch (TREE_CODE_CLASS(TREE_CODE(var))) {
+	case tcc_expression:
+	case tcc_reference: {
+		int i;
+
+		for (i = 0; i < TREE_OPERAND_LENGTH(var); i++) {
+			tree ret = get_string_cst(TREE_OPERAND(var, i));
+			if (ret != NULL_TREE)
+				return ret;
+		}
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	return NULL_TREE;
+}
+
+static bool set_init_exit_section(tree decl)
+{
+	gcc_assert(DECL_P(decl));
+
+	if (get_init_exit_section(decl) != NONE)
+		return false;
+
+	if (get_init_exit_section(current_function_decl) == INIT)
+		set_decl_section_name(decl, ".init.rodata.str");
+	else
+		set_decl_section_name(decl, ".exit.rodata.str");
+	return true;
+}
+
+/* Syscalls are always nocapture functions. */
+static bool is_syscall(const_tree fn)
+{
+	if (!strncmp(DECL_NAME_POINTER(fn), "sys_", 4))
+		return true;
+
+	if (!strncmp(DECL_NAME_POINTER(fn), "sys32_", 6))
+		return true;
+
+	if (!strncmp(DECL_NAME_POINTER(fn), "compat_sys_", 11))
+		return true;
+
+	return false;
+}
+
+static bool is_nocapture_param(const_tree fndecl, int fn_arg_count)
+{
+	const_tree attr, attr_val;
+	int fntype_arg_len;
+
+	if (is_syscall(fndecl))
+		return true;
+
+	fntype_arg_len = type_num_arguments(TREE_TYPE(fndecl));
+	attr = lookup_attribute("nocapture", DECL_ATTRIBUTES(fndecl));
+	if (attr == NULL_TREE)
+		return false;
+
+	for (attr_val = TREE_VALUE(attr); attr_val;
+		attr_val = TREE_CHAIN(attr_val)) {
+		int attr_arg_val = (int)tree_to_shwi(TREE_VALUE(attr_val));
+
+		if (attr_arg_val == -1)
+			return true;
+		if (attr_arg_val == fn_arg_count)
+			return true;
+		if (attr_arg_val > fntype_arg_len &&
+					fn_arg_count >= attr_arg_val)
+			return true;
+	}
+
+	return false;
+}
+
+static bool is_same_vardecl(const_tree op, const_tree vardecl)
+{
+	const_tree decl;
+
+	if (op == vardecl)
+		return true;
+	if (TREE_CODE(op) == SSA_NAME)
+		decl = SSA_NAME_VAR(op);
+	else
+		decl = op;
+	if (decl == NULL_TREE || !DECL_P(decl))
+		return false;
+
+	return DECL_NAME(decl) &&
+		!strcmp(DECL_NAME_POINTER(decl), DECL_NAME_POINTER(vardecl));
+}
+
+static bool search_same_vardecl(const_tree value, const_tree vardecl)
+{
+	int i;
+
+	for (i = 0; i < TREE_OPERAND_LENGTH(value); i++) {
+		const_tree op = TREE_OPERAND(value, i);
+
+		if (op == NULL_TREE)
+			continue;
+		if (is_same_vardecl(op, vardecl))
+			return true;
+		if (search_same_vardecl(op, vardecl))
+			return true;
+	}
+	return false;
+}
+
+static bool check_constructor(const_tree constructor, const_tree vardecl)
+{
+	unsigned HOST_WIDE_INT cnt __unused;
+	tree value;
+
+	FOR_EACH_CONSTRUCTOR_VALUE(CONSTRUCTOR_ELTS(constructor), cnt, value) {
+		if (TREE_CODE(value) == CONSTRUCTOR)
+			return check_constructor(value, vardecl);
+		if (is_gimple_constant(value))
+			continue;
+
+		gcc_assert(TREE_OPERAND_LENGTH(value) > 0);
+		if (search_same_vardecl(value, vardecl))
+			return true;
+	}
+	return false;
+}
+
+static bool compare_ops(const_tree vardecl, tree op)
+{
+	if (TREE_CODE(op) == TREE_LIST)
+		op = TREE_VALUE(op);
+	if (TREE_CODE(op) == SSA_NAME)
+		op = SSA_NAME_VAR(op);
+	if (op == NULL_TREE)
+		return false;
+
+	switch (TREE_CODE_CLASS(TREE_CODE(op))) {
+	case tcc_declaration:
+		return is_same_vardecl(op, vardecl);
+
+	case tcc_exceptional:
+		return check_constructor(op, vardecl);
+
+	case tcc_constant:
+	case tcc_statement:
+	case tcc_comparison:
+		return false;
+
+	default:
+		break;
+	}
+
+	gcc_assert(TREE_OPERAND_LENGTH(op) > 0);
+	return search_same_vardecl(op, vardecl);
+}
+
+static bool search_capture_use(const_tree vardecl, gimple stmt)
+{
+	unsigned int i;
+
+	for (i = 0; i < gimple_num_ops(stmt); i++) {
+		unsigned int arg_count;
+		const_tree fndecl, arg;
+		tree op = *(gimple_op_ptr(stmt, i));
+
+		if (op == NULL_TREE)
+			continue;
+		if (is_gimple_constant(op))
+			continue;
+
+		if (!compare_ops(vardecl, op))
+			continue;
+
+		if (!is_gimple_call(stmt))
+			return true;
+
+		/* return, fndecl */
+		gcc_assert(i >= 3);
+		arg_count = i - 2;
+
+		arg = gimple_call_arg(stmt, arg_count - 1);
+		gcc_assert(TREE_CODE(TREE_TYPE(arg)) == POINTER_TYPE);
+
+		fndecl = gimple_call_fndecl(stmt);
+		if (is_nocapture_param(fndecl, (int)arg_count))
+			continue;
+
+		gcc_assert(fndecl != NULL_TREE);
+
+		/*
+		 * These are potentially nocapture functions that must be
+		 * checked manually.
+		 */
+		if (print_missing_attr)
+			inform(gimple_location(stmt), "nocapture attribute is missing (fn: %E, arg: %u)\n",
+							fndecl, arg_count);
+		return true;
+
+	}
+	return false;
+}
+
+static bool is_in_capture_init(const_tree vardecl)
+{
+	unsigned int i __unused;
+	tree var;
+
+	FOR_EACH_LOCAL_DECL(cfun, i, var) {
+		const_tree initial = DECL_INITIAL(var);
+
+		if (DECL_EXTERNAL(var))
+			continue;
+		if (initial == NULL_TREE)
+			continue;
+		if (TREE_CODE(initial) != CONSTRUCTOR)
+			continue;
+
+		gcc_assert(TREE_CODE(TREE_TYPE(var)) == RECORD_TYPE ||
+								DECL_P(var));
+		if (check_constructor(initial, vardecl))
+			return true;
+	}
+	return false;
+}
+
+static bool has_capture_use_local_var(const_tree vardecl)
+{
+	basic_block bb;
+
+	if (is_in_capture_init(vardecl))
+		return true;
+
+	FOR_EACH_BB_FN(bb, cfun) {
+		gimple_stmt_iterator gsi;
+
+		for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
+			if (search_capture_use(vardecl, gsi_stmt(gsi)))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/* Search local variables that have only nocapture uses. */
+static void find_local_str(void)
+{
+	unsigned int i __unused;
+	tree var;
+
+	FOR_EACH_LOCAL_DECL(cfun, i, var) {
+		tree str, init_val;
+
+		if (TREE_CODE(TREE_TYPE(var)) != ARRAY_TYPE)
+			continue;
+
+		init_val = DECL_INITIAL(var);
+		if (init_val == NULL_TREE || init_val == error_mark_node)
+			continue;
+		if (TREE_CODE(init_val) != STRING_CST)
+			continue;
+
+		if (has_capture_use_local_var(var))
+			continue;
+
+		str = get_string_cst(init_val);
+		gcc_assert(str);
+
+		if (set_init_exit_section(var) && verbose)
+			inform(DECL_SOURCE_LOCATION(var), "initified local var: %s: %s",
+				DECL_NAME_POINTER(current_function_decl),
+				TREE_STRING_POINTER(str));
+	}
+}
+
+static tree create_decl(tree node)
+{
+	tree str, decl, type, name;
+	location_t loc = DECL_SOURCE_LOCATION(current_function_decl);
+
+	str = get_string_cst(node);
+	type = TREE_TYPE(str);
+	gcc_assert(TREE_CODE(type) == ARRAY_TYPE);
+	gcc_assert(TREE_TYPE(type) != NULL_TREE &&
+			TREE_CODE(TREE_TYPE(type)) == INTEGER_TYPE);
+	name = create_tmp_var_name("initify");
+	decl = build_decl(loc, VAR_DECL, name, type);
+
+	DECL_INITIAL(decl) = str;
+	DECL_CONTEXT(decl) = current_function_decl;
+	DECL_ARTIFICIAL(decl) = 1;
+
+	TREE_STATIC(decl) = 1;
+	TREE_READONLY(decl) = 1;
+	TYPE_READONLY(TREE_TYPE(TREE_TYPE(decl))) = 1;
+	TREE_ADDRESSABLE(decl) = 1;
+	TREE_USED(decl) = 1;
+
+	add_referenced_var(decl);
+	add_local_decl(cfun, decl);
+
+	varpool_add_new_variable(decl);
+	varpool_mark_needed_node(varpool_node(decl));
+
+	DECL_CHAIN(decl) = BLOCK_VARS(DECL_INITIAL(current_function_decl));
+	BLOCK_VARS(DECL_INITIAL(current_function_decl)) = decl;
+
+	return build_fold_addr_expr_loc(loc, decl);
+}
+
+static void set_section_call_assign(gimple stmt, tree node, unsigned int num)
+{
+	tree decl;
+
+	decl = create_decl(node);
+
+	switch (gimple_code(stmt)) {
+	case GIMPLE_ASSIGN:
+		gcc_assert(gimple_num_ops(stmt) == 2);
+		gimple_assign_set_rhs1(stmt, decl);
+		break;
+
+	case GIMPLE_CALL:
+		gimple_call_set_arg(stmt, num, decl);
+		break;
+
+	default:
+		debug_gimple_stmt(stmt);
+		error("%s: unknown gimple code", __func__);
+		gcc_unreachable();
+	}
+
+	update_stmt(stmt);
+
+	if (set_init_exit_section(TREE_OPERAND(decl, 0)) && verbose)
+		inform(gimple_location(stmt), "initified function arg: %E: [%E]",
+				current_function_decl, get_string_cst(node));
+}
+
+static tree initify_create_new_var(tree type)
+{
+	tree new_var = create_tmp_var(type, "initify");
+
+	add_referenced_var(new_var);
+	mark_sym_for_renaming(new_var);
+	return new_var;
+}
+
+static void initify_create_new_phi_arg(tree ssa_var, gphi *stmt, unsigned int i)
+{
+	gassign *assign;
+	gimple_stmt_iterator gsi;
+	basic_block arg_bb;
+	tree decl, arg;
+
+	arg = gimple_phi_arg_def(stmt, i);
+	decl = create_decl(arg);
+
+	assign = gimple_build_assign(ssa_var, decl);
+
+	arg_bb = gimple_phi_arg_edge(stmt, i)->src;
+	gcc_assert(arg_bb->index != 0);
+
+	gsi = gsi_after_labels(arg_bb);
+	gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
+	update_stmt(assign);
+
+	if (set_init_exit_section(TREE_OPERAND(decl, 0)) && verbose)
+		inform(gimple_location(stmt), "initified local var, phi arg: %E: [%E]",
+			current_function_decl, get_string_cst(arg));
+}
+
+static void set_section_phi(bool *has_str_cst, gimple_set *visited, gphi *stmt)
+{
+	tree result, ssa_var;
+	unsigned int i;
+
+	result = gimple_phi_result(stmt);
+	ssa_var = initify_create_new_var(TREE_TYPE(result));
+
+	for (i = 0; i < gimple_phi_num_args(stmt); i++) {
+		tree arg = gimple_phi_arg_def(stmt, i);
+
+		if (get_string_cst(arg) == NULL_TREE)
+			walk_def_stmt(has_str_cst, visited, arg);
+		else
+			initify_create_new_phi_arg(ssa_var, stmt, i);
+	}
+}
+
+static void walk_def_stmt(bool *has_str_cst, gimple_set *visited, tree node)
+{
+	gimple def_stmt;
+	const_tree parm_decl;
+
+	if (!*has_str_cst)
+		return;
+
+	if (TREE_CODE(node) != SSA_NAME) {
+		*has_str_cst = false;
+		return;
+	}
+
+	parm_decl = SSA_NAME_VAR(node);
+	if (parm_decl != NULL_TREE && TREE_CODE(parm_decl) == PARM_DECL) {
+		*has_str_cst = false;
+		return;
+	}
+
+	def_stmt = SSA_NAME_DEF_STMT(node);
+	if (pointer_set_insert(visited, def_stmt))
+		return;
+
+	switch (gimple_code(def_stmt)) {
+	case GIMPLE_NOP:
+	case GIMPLE_CALL:
+	case GIMPLE_ASM:
+	case GIMPLE_RETURN:
+		*has_str_cst = false;
+		return;
+
+	case GIMPLE_PHI:
+		set_section_phi(has_str_cst, visited, as_a_gphi(def_stmt));
+		return;
+
+	case GIMPLE_ASSIGN: {
+		tree rhs1, str;
+
+		if (gimple_num_ops(def_stmt) != 2)
+			return;
+
+		rhs1 = gimple_assign_rhs1(def_stmt);
+		walk_def_stmt(has_str_cst, visited, rhs1);
+		if (!*has_str_cst)
+			return;
+		str = get_string_cst(rhs1);
+		if (str != NULL_TREE)
+			set_section_call_assign(def_stmt, rhs1, 0);
+		return;
+	}
+
+	default:
+		debug_gimple_stmt(def_stmt);
+		error("%s: unknown gimple code", __func__);
+		gcc_unreachable();
+	}
+}
+
+/* Search constant strings assigned to variables. */
+static void search_var_param(gcall *stmt)
+{
+	unsigned int num;
+
+	for (num = 0; num < gimple_call_num_args(stmt); num++) {
+		gimple_set *visited;
+		const_tree type, fndecl;
+		bool has_str_cst = true;
+		tree str, arg = gimple_call_arg(stmt, num);
+
+		str = get_string_cst(arg);
+		if (str != NULL_TREE)
+			continue;
+
+		if (TREE_CODE(TREE_TYPE(arg)) != POINTER_TYPE)
+			continue;
+		type = TREE_TYPE(TREE_TYPE(arg));
+		if (!TYPE_STRING_FLAG(type))
+			continue;
+		fndecl = gimple_call_fndecl(stmt);
+		if (!is_nocapture_param(fndecl, num + 1))
+			continue;
+
+		visited = pointer_set_create();
+		walk_def_stmt(&has_str_cst, visited, arg);
+		pointer_set_destroy(visited);
+	}
+}
+
+/* Search constant strings passed as arguments. */
+static void search_str_param(gcall *stmt)
+{
+	unsigned int num;
+
+	for (num = 0; num < gimple_call_num_args(stmt); num++) {
+		const_tree fndecl;
+		tree str, arg = gimple_call_arg(stmt, num);
+
+		str = get_string_cst(arg);
+		if (str == NULL_TREE)
+			continue;
+
+		fndecl = gimple_call_fndecl(stmt);
+		if (is_nocapture_param(fndecl, num + 1))
+			set_section_call_assign(stmt, arg, num);
+	}
+}
+
+static bool has_nocapture_param(const_tree fndecl)
+{
+	const_tree attr;
+
+	if (fndecl == NULL_TREE)
+		return false;
+
+	if (is_syscall(fndecl))
+		return true;
+
+	attr = lookup_attribute("nocapture", DECL_ATTRIBUTES(fndecl));
+	return attr != NULL_TREE;
+}
+
+/* Search constant strings in arguments of nocapture functions. */
+static void search_const_strs(void)
+{
+	basic_block bb;
+
+	FOR_EACH_BB_FN(bb, cfun) {
+		gimple_stmt_iterator gsi;
+
+		for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
+			gcall *call_stmt;
+			gimple stmt = gsi_stmt(gsi);
+
+			if (!is_gimple_call(stmt))
+				continue;
+
+			call_stmt = as_a_gcall(stmt);
+			if (!has_nocapture_param(gimple_call_fndecl(call_stmt)))
+				continue;
+			search_str_param(call_stmt);
+			search_var_param(call_stmt);
+		}
+	}
+}
+
+/*
+ * Find and move constant strings to the proper init or exit read-only
+ * data section.
+ */
+static unsigned int initify_execute(void)
+{
+	if (get_init_exit_section(current_function_decl) == NONE)
+		return 0;
+
+	find_local_str();
+	search_const_strs();
+
+	return 0;
+}
+
+#define PASS_NAME initify
+#define NO_GATE
+#define TODO_FLAGS_FINISH	TODO_dump_func | TODO_verify_ssa | \
+				TODO_verify_stmts | \
+				TODO_remove_unused_locals | \
+				TODO_cleanup_cfg | TODO_ggc_collect | \
+				TODO_verify_flow | TODO_update_ssa
+
+#include "gcc-generate-gimple-pass.h"
+
+static bool search_init_functions_gate(void)
+{
+	return search_init_exit_functions;
+}
+
+/*
+ * If the function is called by only __init/__exit functions then it can become
+ * an __init/__exit function as well.
+ */
+static bool should_init_exit(struct cgraph_node *callee)
+{
+	struct cgraph_edge *e;
+	bool only_init_callers;
+	const_tree callee_decl = NODE_DECL(callee);
+
+	if (NODE_SYMBOL(callee)->aux != (void *)NONE)
+		return false;
+	if (get_init_exit_section(callee_decl) != NONE)
+		return false;
+
+	/* If gcc isn't in LTO mode then we can handle only static functions. */
+	if (!in_lto_p && TREE_PUBLIC(callee_decl))
+		return false;
+
+	if (NODE_SYMBOL(callee)->address_taken)
+		return false;
+
+	e = callee->callers;
+	if (!e)
+		return false;
+
+	only_init_callers = true;
+	for (; e; e = e->next_caller) {
+		enum section_type caller_section;
+		struct cgraph_node *caller = e->caller;
+
+		caller_section = get_init_exit_section(NODE_DECL(caller));
+		if (caller_section == NONE &&
+			NODE_SYMBOL(caller)->aux == (void *)NONE)
+			only_init_callers = false;
+	}
+
+	return only_init_callers;
+}
+
+static bool inherit_section(struct cgraph_node *callee,
+				struct cgraph_node *caller,
+				enum section_type curfn_section)
+{
+	if (curfn_section == NONE)
+		curfn_section = (enum section_type)(unsigned long)
+					NODE_SYMBOL(caller)->aux;
+
+	if (curfn_section == EXIT && NODE_SYMBOL(callee)->aux == (void *)INIT)
+		goto set_section;
+
+	if (!should_init_exit(callee))
+		return false;
+
+	gcc_assert(NODE_SYMBOL(callee)->aux == (void *)NONE);
+
+set_section:
+	NODE_SYMBOL(callee)->aux = (void *)curfn_section;
+	return true;
+}
+
+/*
+ * Try to propagate __init/__exit to callees in __init/__exit functions.
+ * If a function is called by __init and __exit functions as well then it can be
+ * an __exit function at most.
+ */
+static bool search_init_exit_callers(void)
+{
+	struct cgraph_node *node;
+	bool change = false;
+
+	FOR_EACH_FUNCTION(node) {
+		struct cgraph_edge *e;
+		enum section_type section;
+		const_tree cur_fndecl = NODE_DECL(node);
+
+		if (DECL_BUILT_IN(cur_fndecl))
+			continue;
+
+		section = get_init_exit_section(cur_fndecl);
+		if (section == NONE && NODE_SYMBOL(node)->aux == (void *)NONE)
+			continue;
+
+		for (e = node->callees; e; e = e->next_callee) {
+			if (e->callee->global.inlined_to)
+				continue;
+			if (inherit_section(e->callee, node, section))
+				change = true;
+		}
+	}
+	return change;
+}
+
+/* We can't move functions to the init/exit sections from certain sections. */
+static bool can_move_to_init_exit(const_tree fndecl)
+{
+	const char *section_name;
+
+#if BUILDING_GCC_VERSION < 5000
+	const_tree section_tree = DECL_SECTION_NAME(fndecl);
+
+	if (section_tree == NULL_TREE)
+		return true;
+
+	section_name = TREE_STRING_POINTER(section_tree);
+#else
+	section_name = DECL_SECTION_NAME(fndecl);
+	if (!section_name)
+		return true;
+#endif
+
+	if (!strcmp(section_name, ".ref.text\000"))
+		return true;
+
+	if (!strcmp(section_name, ".meminit.text\000"))
+		return false;
+
+	inform(DECL_SOURCE_LOCATION(fndecl), "Section of %qE: %s\n",
+						fndecl, section_name);
+	gcc_unreachable();
+}
+
+static void move_function_to_init_exit_text(struct cgraph_node *node)
+{
+	const char *section_name;
+	tree id, attr;
+	tree section_str, attr_args, fndecl = NODE_DECL(node);
+
+	if (NODE_SYMBOL(node)->aux == (void *)NONE)
+		return;
+
+	if (!can_move_to_init_exit(fndecl))
+		return;
+
+	if (verbose) {
+		const char *attr_name;
+		location_t loc = DECL_SOURCE_LOCATION(fndecl);
+
+		attr_name = NODE_SYMBOL(node)->aux ==
+					(void *)INIT ? "__init" : "__exit";
+
+		if (in_lto_p && TREE_PUBLIC(fndecl))
+			inform(loc, "%s attribute is missing from the %qE function (public)",
+							attr_name, fndecl);
+
+		if (!in_lto_p && !TREE_PUBLIC(fndecl))
+			inform(loc, "%s attribute is missing from the %qE function (static)",
+							attr_name, fndecl);
+	}
+
+	if (in_lto_p)
+		return;
+
+	/* Add the init/exit section attribute to the function declaration. */
+	DECL_ATTRIBUTES(fndecl) = copy_list(DECL_ATTRIBUTES(fndecl));
+
+	section_name = NODE_SYMBOL(node)->aux ==
+				(void *)INIT ? ".init.text" : ".exit.text";
+	section_str = build_string(strlen(section_name) + 1, section_name);
+	TREE_READONLY(section_str) = 1;
+	TREE_STATIC(section_str) = 1;
+	attr_args = build_tree_list(NULL_TREE, section_str);
+
+	id = get_identifier("__section__");
+	attr = DECL_ATTRIBUTES(fndecl);
+	DECL_ATTRIBUTES(fndecl) = tree_cons(id, attr_args, attr);
+
+#if BUILDING_GCC_VERSION < 5000
+	DECL_SECTION_NAME(fndecl) = section_str;
+#endif
+	set_decl_section_name(fndecl, section_name);
+}
+
+/* Find all functions that can become __init/__exit functions */
+static unsigned int search_init_functions_execute(void)
+{
+	struct cgraph_node *node;
+
+	if (flag_lto && !in_lto_p)
+		return 0;
+
+	FOR_EACH_FUNCTION(node)
+		NODE_SYMBOL(node)->aux = (void *)NONE;
+
+	while (search_init_exit_callers()) {};
+
+	FOR_EACH_FUNCTION(node) {
+		move_function_to_init_exit_text(node);
+
+		NODE_SYMBOL(node)->aux = NULL;
+	}
+
+	return 0;
+}
+
+/* Find the specified argument in the clone */
+static unsigned int orig_argnum_on_clone(struct cgraph_node *new_node,
+						unsigned int orig_argnum)
+{
+	bitmap args_to_skip;
+	unsigned int i, new_argnum = orig_argnum;
+
+	gcc_assert(new_node->clone_of && new_node->clone.tree_map);
+	args_to_skip = new_node->clone.args_to_skip;
+	if (bitmap_bit_p(args_to_skip, orig_argnum - 1))
+		return 0;
+
+	for (i = 0; i < orig_argnum; i++) {
+		if (bitmap_bit_p(args_to_skip, i))
+			new_argnum--;
+	}
+	return new_argnum + 1;
+}
+
+/* Determine if a cloned function has all the original arguments */
+static bool unchanged_arglist(struct cgraph_node *new_node,
+				struct cgraph_node *old_node)
+{
+	const_tree new_decl_list, old_decl_list;
+
+	if (new_node->clone_of && new_node->clone.tree_map)
+		return !new_node->clone.args_to_skip;
+
+	new_decl_list = DECL_ARGUMENTS(NODE_DECL(new_node));
+	old_decl_list = DECL_ARGUMENTS(NODE_DECL(old_node));
+	if (new_decl_list != NULL_TREE && old_decl_list != NULL_TREE)
+		gcc_assert(list_length(new_decl_list) ==
+						list_length(old_decl_list));
+
+	return true;
+}
+
+static void initify_node_duplication_hook(struct cgraph_node *src,
+						struct cgraph_node *dst,
+						void *data __unused)
+{
+	const_tree orig_fndecl, orig_decl_lst, arg;
+	unsigned int orig_argnum = 0;
+
+	if (unchanged_arglist(dst, src))
+		return;
+
+	orig_fndecl = NODE_DECL(src);
+	if (!has_nocapture_param(orig_fndecl))
+		return;
+
+	orig_decl_lst = DECL_ARGUMENTS(orig_fndecl);
+	gcc_assert(orig_decl_lst != NULL_TREE);
+
+	for (arg = orig_decl_lst; arg; arg = TREE_CHAIN(arg), orig_argnum++) {
+		if (!is_nocapture_param(orig_fndecl, orig_argnum))
+			continue;
+		if (orig_argnum_on_clone(dst, orig_argnum) == 0)
+			continue;
+
+		debug_cgraph_node(dst);
+		debug_cgraph_node(src);
+		gcc_unreachable();
+	}
+}
+
+static void initify_register_hooks(void)
+{
+	static bool init_p = false;
+
+	if (init_p)
+		return;
+	init_p = true;
+
+	node_duplication_hook_holder =
+		cgraph_add_node_duplication_hook(&initify_node_duplication_hook,
+									NULL);
+}
+
+static void search_init_functions_generate_summary(void)
+{
+	initify_register_hooks();
+}
+
+static void search_init_functions_read_summary(void)
+{
+	initify_register_hooks();
+}
+
+#define PASS_NAME search_init_functions
+#define NO_WRITE_SUMMARY
+#define NO_READ_OPTIMIZATION_SUMMARY
+#define NO_WRITE_OPTIMIZATION_SUMMARY
+#define NO_STMT_FIXUP
+#define NO_FUNCTION_TRANSFORM
+#define NO_VARIABLE_TRANSFORM
+
+#include "gcc-generate-ipa-pass.h"
+
+static unsigned int (*old_section_type_flags)(tree decl, const char *name,
+								int reloc);
+
+static unsigned int initify_section_type_flags(tree decl, const char *name,
+								int reloc)
+{
+	if (!strcmp(name, ".init.rodata.str") ||
+					!strcmp(name, ".exit.rodata.str")) {
+		gcc_assert(TREE_CODE(decl) == VAR_DECL);
+		gcc_assert(DECL_INITIAL(decl));
+		gcc_assert(TREE_CODE(DECL_INITIAL(decl)) == STRING_CST);
+
+		return 1 | SECTION_MERGE | SECTION_STRINGS;
+	}
+
+	return old_section_type_flags(decl, name, reloc);
+}
+
+static void initify_start_unit(void __unused *gcc_data,
+						void __unused *user_data)
+{
+	old_section_type_flags = targetm.section_type_flags;
+	targetm.section_type_flags = initify_section_type_flags;
+}
+
+int plugin_init(struct plugin_name_args *plugin_info,
+					struct plugin_gcc_version *version)
+{
+	struct register_pass_info initify_pass_info, search_init_functions_info;
+	int i;
+	const int argc = plugin_info->argc;
+	bool enabled = true;
+	const struct plugin_argument * const argv = plugin_info->argv;
+	const char * const plugin_name = plugin_info->base_name;
+
+	initify_pass_info.pass				= make_initify_pass();
+	initify_pass_info.reference_pass_name		= "nrv";
+	initify_pass_info.ref_pass_instance_number	= 1;
+	initify_pass_info.pos_op			= PASS_POS_INSERT_AFTER;
+
+	search_init_functions_info.pass = make_search_init_functions_pass();
+	search_init_functions_info.reference_pass_name		= "inline";
+	search_init_functions_info.ref_pass_instance_number	= 1;
+	search_init_functions_info.pos_op = PASS_POS_INSERT_AFTER;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	for (i = 0; i < argc; ++i) {
+		if (!(strcmp(argv[i].key, "disable"))) {
+			enabled = false;
+			continue;
+		}
+		if (!strcmp(argv[i].key, "verbose")) {
+			verbose = true;
+			continue;
+		}
+		if (!strcmp(argv[i].key, "print_missing_attr")) {
+			print_missing_attr = true;
+			continue;
+		}
+		if (!strcmp(argv[i].key, "search_init_exit_functions")) {
+			search_init_exit_functions = true;
+			continue;
+		}
+
+		error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name,
+								argv[i].key);
+	}
+
+	register_callback(plugin_name, PLUGIN_INFO, NULL, &initify_plugin_info);
+	if (enabled) {
+		register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+							&initify_pass_info);
+		register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+						&search_init_functions_info);
+		register_callback(plugin_name, PLUGIN_START_UNIT,
+						initify_start_unit, NULL);
+	}
+	register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
+									NULL);
+
+	return 0;
+}
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
  2016-06-28 11:35 ` [PATCH v1 1/2] Add " Emese Revfy
@ 2016-06-28 11:36 ` Emese Revfy
  2016-06-28 16:43   ` Joe Perches
  2016-06-28 20:50   ` Rasmus Villemoes
  2016-06-28 11:42 ` [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 11:36 UTC (permalink / raw)
  To: kernel-hardening
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

The nocapture gcc attribute can be on functions only.
The attribute takes one or more unsigned integer constants as parameters
that specify the function argument(s) of const char* type to initify.
If the marked argument is a vararg then the plugin initifies
all vararg arguments.

I couldn't test the arm, arm64 and powerpc architectures.

Signed-off-by: Emese Revfy <re.emese@gmail.com>
---
 arch/arm/include/asm/string.h     | 10 +++---
 arch/arm64/include/asm/string.h   | 23 ++++++------
 arch/powerpc/include/asm/string.h | 19 +++++-----
 arch/x86/boot/string.h            |  4 +--
 arch/x86/include/asm/string_32.h  | 21 +++++------
 arch/x86/include/asm/string_64.h  | 18 +++++-----
 arch/x86/kernel/hpet.c            |  2 +-
 include/asm-generic/bug.h         |  6 ++--
 include/linux/compiler-gcc.h      | 10 ++++--
 include/linux/compiler.h          |  4 +++
 include/linux/fs.h                |  5 +--
 include/linux/printk.h            |  2 +-
 include/linux/string.h            | 73 ++++++++++++++++++++-------------------
 13 files changed, 107 insertions(+), 90 deletions(-)

diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h
index cf4f3aa..3f68273 100644
--- a/arch/arm/include/asm/string.h
+++ b/arch/arm/include/asm/string.h
@@ -7,19 +7,19 @@
  */
 
 #define __HAVE_ARCH_STRRCHR
-extern char * strrchr(const char * s, int c);
+extern char * strrchr(const char * s, int c) __nocapture(1);
 
 #define __HAVE_ARCH_STRCHR
-extern char * strchr(const char * s, int c);
+extern char * strchr(const char * s, int c) __nocapture(1);
 
 #define __HAVE_ARCH_MEMCPY
-extern void * memcpy(void *, const void *, __kernel_size_t);
+extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
 
 #define __HAVE_ARCH_MEMMOVE
-extern void * memmove(void *, const void *, __kernel_size_t);
+extern void * memmove(void *, const void *, __kernel_size_t) __nocapture(2);
 
 #define __HAVE_ARCH_MEMCHR
-extern void * memchr(const void *, int, __kernel_size_t);
+extern void * memchr(const void *, int, __kernel_size_t) __nocapture(1);
 
 #define __HAVE_ARCH_MEMSET
 extern void * memset(void *, int, __kernel_size_t);
diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
index 2eb714c..0b3662b 100644
--- a/arch/arm64/include/asm/string.h
+++ b/arch/arm64/include/asm/string.h
@@ -17,40 +17,41 @@
 #define __ASM_STRING_H
 
 #define __HAVE_ARCH_STRRCHR
-extern char *strrchr(const char *, int c);
+extern char *strrchr(const char *, int c) __nocapture(1);
 
 #define __HAVE_ARCH_STRCHR
-extern char *strchr(const char *, int c);
+extern char *strchr(const char *, int c) __nocapture(1);
 
 #define __HAVE_ARCH_STRCMP
-extern int strcmp(const char *, const char *);
+extern int strcmp(const char *, const char *) __nocapture(1, 2);
 
 #define __HAVE_ARCH_STRNCMP
-extern int strncmp(const char *, const char *, __kernel_size_t);
+extern int
+strncmp(const char *, const char *, __kernel_size_t) __nocapture(1, 2);
 
 #define __HAVE_ARCH_STRLEN
 extern __kernel_size_t strlen(const char *);
 
 #define __HAVE_ARCH_STRNLEN
-extern __kernel_size_t strnlen(const char *, __kernel_size_t);
+extern __kernel_size_t strnlen(const char *, __kernel_size_t) __nocapture(1);
 
 #define __HAVE_ARCH_MEMCPY
-extern void *memcpy(void *, const void *, __kernel_size_t);
-extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
+extern void *__memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
 
 #define __HAVE_ARCH_MEMMOVE
-extern void *memmove(void *, const void *, __kernel_size_t);
-extern void *__memmove(void *, const void *, __kernel_size_t);
+extern void *memmove(void *, const void *, __kernel_size_t) __nocapture(2);
+extern void *__memmove(void *, const void *, __kernel_size_t) __nocapture(2);
 
 #define __HAVE_ARCH_MEMCHR
-extern void *memchr(const void *, int, __kernel_size_t);
+extern void *memchr(const void *, int, __kernel_size_t) __nocapture(1);
 
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, __kernel_size_t);
 extern void *__memset(void *, int, __kernel_size_t);
 
 #define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, size_t);
+extern int memcmp(const void *, const void *, size_t) __nocapture(1, 2);
 
 
 #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h
index e40010a..b29fc74 100644
--- a/arch/powerpc/include/asm/string.h
+++ b/arch/powerpc/include/asm/string.h
@@ -15,17 +15,18 @@
 #define __HAVE_ARCH_MEMCMP
 #define __HAVE_ARCH_MEMCHR
 
-extern char * strcpy(char *,const char *);
-extern char * strncpy(char *,const char *, __kernel_size_t);
+extern char * strcpy(char *,const char *) __nocapture(2);
+extern char * strncpy(char *,const char *, __kernel_size_t) __nocapture(2);
 extern __kernel_size_t strlen(const char *);
-extern int strcmp(const char *,const char *);
-extern int strncmp(const char *, const char *, __kernel_size_t);
-extern char * strcat(char *, const char *);
+extern int strcmp(const char *,const char *) __nocapture(1, 2);
+extern int
+strncmp(const char *, const char *, __kernel_size_t) __nocapture(1, 2);
+extern char * strcat(char *, const char *) __nocapture(2);
 extern void * memset(void *,int,__kernel_size_t);
-extern void * memcpy(void *,const void *,__kernel_size_t);
-extern void * memmove(void *,const void *,__kernel_size_t);
-extern int memcmp(const void *,const void *,__kernel_size_t);
-extern void * memchr(const void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t) __nocapture(2);
+extern void * memmove(void *,const void *,__kernel_size_t) __nocapture(2);
+extern int memcmp(const void *,const void *,__kernel_size_t) __nocapture(1, 2);
+extern void * memchr(const void *,int,__kernel_size_t) __nocapture(1);
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h
index 725e820..d7ea2759 100644
--- a/arch/x86/boot/string.h
+++ b/arch/x86/boot/string.h
@@ -6,9 +6,9 @@
 #undef memset
 #undef memcmp
 
-void *memcpy(void *dst, const void *src, size_t len);
+void *memcpy(void *dst, const void *src, size_t len) __nocapture(2);
 void *memset(void *dst, int c, size_t len);
-int memcmp(const void *s1, const void *s2, size_t len);
+int memcmp(const void *s1, const void *s2, size_t len) __nocapture(1, 2);
 
 /*
  * Access builtin version by default. If one needs to use optimized version,
diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h
index 3d3e835..b94699b 100644
--- a/arch/x86/include/asm/string_32.h
+++ b/arch/x86/include/asm/string_32.h
@@ -6,25 +6,26 @@
 /* Let gcc decide whether to inline or use the out of line functions */
 
 #define __HAVE_ARCH_STRCPY
-extern char *strcpy(char *dest, const char *src);
+extern char *strcpy(char *dest, const char *src) __nocapture(2);
 
 #define __HAVE_ARCH_STRNCPY
-extern char *strncpy(char *dest, const char *src, size_t count);
+extern char *strncpy(char *dest, const char *src, size_t count) __nocapture(2);
 
 #define __HAVE_ARCH_STRCAT
-extern char *strcat(char *dest, const char *src);
+extern char *strcat(char *dest, const char *src) __nocapture(2);
 
 #define __HAVE_ARCH_STRNCAT
-extern char *strncat(char *dest, const char *src, size_t count);
+extern char *strncat(char *dest, const char *src, size_t count) __nocapture(2);
 
 #define __HAVE_ARCH_STRCMP
-extern int strcmp(const char *cs, const char *ct);
+extern int strcmp(const char *cs, const char *ct) __nocapture(1, 2);
 
 #define __HAVE_ARCH_STRNCMP
-extern int strncmp(const char *cs, const char *ct, size_t count);
+extern int
+strncmp(const char *cs, const char *ct, size_t count) __nocapture(1, 2);
 
 #define __HAVE_ARCH_STRCHR
-extern char *strchr(const char *s, int c);
+extern char *strchr(const char *s, int c) __nocapture(1);
 
 #define __HAVE_ARCH_STRLEN
 extern size_t strlen(const char *s);
@@ -197,12 +198,12 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len)
 #endif
 
 #define __HAVE_ARCH_MEMMOVE
-void *memmove(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n) __nocapture(2);
 
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-extern void *memchr(const void *cs, int c, size_t count);
+extern void *memchr(const void *cs, int c, size_t count) __nocapture(1);
 
 static inline void *__memset_generic(void *s, char c, size_t count)
 {
@@ -247,7 +248,7 @@ extern size_t strnlen(const char *s, size_t count);
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-extern char *strstr(const char *cs, const char *ct);
+extern char *strstr(const char *cs, const char *ct) __nocapture(1, 2);
 
 /*
  * This looks horribly ugly, but the compiler can optimize it totally,
diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h
index 90dbbd9..aff2c28 100644
--- a/arch/x86/include/asm/string_64.h
+++ b/arch/x86/include/asm/string_64.h
@@ -27,8 +27,8 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
-extern void *memcpy(void *to, const void *from, size_t len);
-extern void *__memcpy(void *to, const void *from, size_t len);
+extern void *memcpy(void *to, const void *from, size_t len) __nocapture(2);
+extern void *__memcpy(void *to, const void *from, size_t len) __nocapture(2);
 
 #ifndef CONFIG_KMEMCHECK
 #if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || __GNUC__ < 4
@@ -56,14 +56,14 @@ void *memset(void *s, int c, size_t n);
 void *__memset(void *s, int c, size_t n);
 
 #define __HAVE_ARCH_MEMMOVE
-void *memmove(void *dest, const void *src, size_t count);
-void *__memmove(void *dest, const void *src, size_t count);
+void *memmove(void *dest, const void *src, size_t count) __nocapture(2);
+void *__memmove(void *dest, const void *src, size_t count) __nocapture(2);
 
-int memcmp(const void *cs, const void *ct, size_t count);
+int memcmp(const void *cs, const void *ct, size_t count) __nocapture(1, 2);
 size_t strlen(const char *s);
-char *strcpy(char *dest, const char *src);
-char *strcat(char *dest, const char *src);
-int strcmp(const char *cs, const char *ct);
+char *strcpy(char *dest, const char *src) __nocapture(2);
+char *strcat(char *dest, const char *src) __nocapture(2);
+int strcmp(const char *cs, const char *ct) __nocapture(1, 2);
 
 #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
 
@@ -89,7 +89,7 @@ int strcmp(const char *cs, const char *ct);
  *
  * Return 0 for success, -EFAULT for fail
  */
-int memcpy_mcsafe(void *dst, const void *src, size_t cnt);
+int memcpy_mcsafe(void *dst, const void *src, size_t cnt) __nocapture(2);
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index f112af7..acf9e16 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -136,7 +136,7 @@ int is_hpet_enabled(void)
 }
 EXPORT_SYMBOL_GPL(is_hpet_enabled);
 
-static void _hpet_print_config(const char *function, int line)
+static void __nocapture(1) _hpet_print_config(const char *function, int line)
 {
 	u32 i, timers, l, h;
 	printk(KERN_INFO "hpet: %s(%d):\n", function, line);
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 6f96247..4cdf266 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -62,13 +62,13 @@ struct bug_entry {
  * to provide better diagnostics.
  */
 #ifndef __WARN_TAINT
-extern __printf(3, 4)
+extern __printf(3, 4) __nocapture(1, 3, 4)
 void warn_slowpath_fmt(const char *file, const int line,
 		       const char *fmt, ...);
-extern __printf(4, 5)
+extern __printf(4, 5) __nocapture(1, 4, 5)
 void warn_slowpath_fmt_taint(const char *file, const int line, unsigned taint,
 			     const char *fmt, ...);
-extern void warn_slowpath_null(const char *file, const int line);
+extern __nocapture(1) void warn_slowpath_null(const char *file, const int line);
 #define WANT_WARN_ON_SLOWPATH
 #define __WARN()		warn_slowpath_null(__FILE__, __LINE__)
 #define __WARN_printf(arg...)	warn_slowpath_fmt(__FILE__, __LINE__, arg)
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index df88c0a..192cea4 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -116,8 +116,10 @@
  */
 #define __pure			__attribute__((pure))
 #define __aligned(x)		__attribute__((aligned(x)))
-#define __printf(a, b)		__attribute__((format(printf, a, b)))
-#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
+#define __printf(a, b)		__attribute__((format(printf, a, b))) \
+				__nocapture(a, b)
+#define __scanf(a, b)		__attribute__((format(scanf, a, b))) \
+				__nocapture(a, b)
 #define __attribute_const__	__attribute__((__const__))
 #define __maybe_unused		__attribute__((unused))
 #define __always_unused		__attribute__((unused))
@@ -193,6 +195,10 @@
 # define __latent_entropy	__attribute__((latent_entropy))
 #endif
 
+#ifdef INITIFY_PLUGIN
+#define __nocapture(...) __attribute__((nocapture(__VA_ARGS__)))
+#endif
+
 /*
  * Mark a position in code as unreachable.  This can be used to
  * suppress control flow warnings after asm blocks that transfer
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index c65327b..8a02dae 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -429,6 +429,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 # define __latent_entropy
 #endif
 
+#ifndef __nocapture
+# define __nocapture(...)
+#endif
+
 /*
  * Tell gcc if a function is cold. The compiler will assume any path
  * directly leading to the call is unlikely.
diff --git a/include/linux/fs.h b/include/linux/fs.h
index dd28814..e3c7191 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2426,8 +2426,9 @@ extern int register_chrdev_region(dev_t, unsigned, const char *);
 extern int __register_chrdev(unsigned int major, unsigned int baseminor,
 			     unsigned int count, const char *name,
 			     const struct file_operations *fops);
-extern void __unregister_chrdev(unsigned int major, unsigned int baseminor,
-				unsigned int count, const char *name);
+extern __nocapture(4) void __unregister_chrdev(unsigned int major,
+				unsigned int baseminor, unsigned int count,
+				const char *name);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern void chrdev_show(struct seq_file *,off_t);
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f4da695..b504798 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -163,7 +163,7 @@ __printf(1, 2) __cold int printk_deferred(const char *fmt, ...);
  * with all other unrelated printk_ratelimit() callsites.  Instead use
  * printk_ratelimited() or plain old __ratelimit().
  */
-extern int __printk_ratelimit(const char *func);
+extern int __printk_ratelimit(const char *func) __nocapture(1);
 #define printk_ratelimit() __printk_ratelimit(__func__)
 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 				   unsigned int interval_msec);
diff --git a/include/linux/string.h b/include/linux/string.h
index 26b6f6a..536e733 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -18,51 +18,52 @@ extern void *memdup_user_nul(const void __user *, size_t);
 #include <asm/string.h>
 
 #ifndef __HAVE_ARCH_STRCPY
-extern char * strcpy(char *,const char *);
+extern char * strcpy(char *,const char *) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRNCPY
-extern char * strncpy(char *,const char *, __kernel_size_t);
+extern char * strncpy(char *,const char *, __kernel_size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRLCPY
-size_t strlcpy(char *, const char *, size_t);
+size_t strlcpy(char *, const char *, size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRSCPY
-ssize_t __must_check strscpy(char *, const char *, size_t);
+ssize_t __must_check strscpy(char *, const char *, size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRCAT
-extern char * strcat(char *, const char *);
+extern char * strcat(char *, const char *) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRNCAT
-extern char * strncat(char *, const char *, __kernel_size_t);
+extern char * strncat(char *, const char *, __kernel_size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRLCAT
-extern size_t strlcat(char *, const char *, __kernel_size_t);
+extern size_t strlcat(char *, const char *, __kernel_size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRCMP
-extern int strcmp(const char *,const char *);
+extern int strcmp(const char *,const char *) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRNCMP
-extern int strncmp(const char *,const char *,__kernel_size_t);
+extern int strncmp(const char *,const char *,__kernel_size_t) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRCASECMP
-extern int strcasecmp(const char *s1, const char *s2);
+extern int strcasecmp(const char *s1, const char *s2) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRNCASECMP
-extern int strncasecmp(const char *s1, const char *s2, size_t n);
+extern int
+strncasecmp(const char *s1, const char *s2, size_t n) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRCHR
-extern char * strchr(const char *,int);
+extern char * strchr(const char *,int) __nocapture(1);
 #endif
 #ifndef __HAVE_ARCH_STRCHRNUL
-extern char * strchrnul(const char *,int);
+extern char * strchrnul(const char *,int) __nocapture(1);
 #endif
 #ifndef __HAVE_ARCH_STRNCHR
-extern char * strnchr(const char *, size_t, int);
+extern char * strnchr(const char *, size_t, int) __nocapture(1);
 #endif
 #ifndef __HAVE_ARCH_STRRCHR
-extern char * strrchr(const char *,int);
+extern char * strrchr(const char *,int) __nocapture(1);
 #endif
-extern char * __must_check skip_spaces(const char *);
+extern char * __must_check skip_spaces(const char *) __nocapture(1);
 
 extern char *strim(char *);
 
@@ -72,10 +73,10 @@ static inline __must_check char *strstrip(char *str)
 }
 
 #ifndef __HAVE_ARCH_STRSTR
-extern char * strstr(const char *, const char *);
+extern char * strstr(const char *, const char *) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRNSTR
-extern char * strnstr(const char *, const char *, size_t);
+extern char * strnstr(const char *, const char *, size_t) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRLEN
 extern __kernel_size_t strlen(const char *);
@@ -84,51 +85,51 @@ extern __kernel_size_t strlen(const char *);
 extern __kernel_size_t strnlen(const char *,__kernel_size_t);
 #endif
 #ifndef __HAVE_ARCH_STRPBRK
-extern char * strpbrk(const char *,const char *);
+extern char * strpbrk(const char *,const char *) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRSEP
-extern char * strsep(char **,const char *);
+extern char * strsep(char **,const char *) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_STRSPN
-extern __kernel_size_t strspn(const char *,const char *);
+extern __kernel_size_t strspn(const char *,const char *) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_STRCSPN
-extern __kernel_size_t strcspn(const char *,const char *);
+extern __kernel_size_t strcspn(const char *,const char *) __nocapture(1, 2);
 #endif
 
 #ifndef __HAVE_ARCH_MEMSET
 extern void * memset(void *,int,__kernel_size_t);
 #endif
 #ifndef __HAVE_ARCH_MEMCPY
-extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_MEMMOVE
-extern void * memmove(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t) __nocapture(2);
 #endif
 #ifndef __HAVE_ARCH_MEMSCAN
 extern void * memscan(void *,int,__kernel_size_t);
 #endif
 #ifndef __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *,const void *,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t) __nocapture(1, 2);
 #endif
 #ifndef __HAVE_ARCH_MEMCHR
-extern void * memchr(const void *,int,__kernel_size_t);
+extern void * memchr(const void *,int,__kernel_size_t) __nocapture(1);
 #endif
-void *memchr_inv(const void *s, int c, size_t n);
+void *memchr_inv(const void *s, int c, size_t n) __nocapture(1);
 char *strreplace(char *s, char old, char new);
 
 extern void kfree_const(const void *x);
 
-extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
-extern const char *kstrdup_const(const char *s, gfp_t gfp);
-extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
-extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kstrdup(const char *s, gfp_t gfp) __malloc __nocapture(1);
+extern const char *kstrdup_const(const char *s, gfp_t gfp) __nocapture(1);
+extern char *kstrndup(const char *s, size_t len, gfp_t gfp) __nocapture(1);
+extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __nocapture(1);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
-extern bool sysfs_streq(const char *s1, const char *s2);
-extern int kstrtobool(const char *s, bool *res);
+extern bool sysfs_streq(const char *s1, const char *s2) __nocapture(1, 2);
+extern int kstrtobool(const char *s, bool *res) __nocapture(1);
 static inline int strtobool(const char *s, bool *res)
 {
 	return kstrtobool(s, res);
@@ -137,8 +138,10 @@ static inline int strtobool(const char *s, bool *res)
 int match_string(const char * const *array, size_t n, const char *string);
 
 #ifdef CONFIG_BINARY_PRINTF
-int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
-int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf);
+int vbin_printf(u32 *bin_buf, size_t size, const char *fmt,
+		va_list args) __nocapture(3);
+int bstr_printf(char *buf, size_t size, const char *fmt,
+		const u32 *bin_buf) __nocapture(3);
 int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4);
 #endif
 
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
  2016-06-28 11:35 ` [PATCH v1 1/2] Add " Emese Revfy
  2016-06-28 11:36 ` [PATCH v1 2/2] Mark functions with the __nocapture attribute Emese Revfy
@ 2016-06-28 11:42 ` Emese Revfy
  2016-06-28 12:57 ` [kernel-hardening] " Mark Rutland
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 11:42 UTC (permalink / raw)
  To: kernel-hardening
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 28 Jun 2016 13:34:07 +0200
Emese Revfy <re.emese@gmail.com> wrote:

>  * automatically discover init/exit functions and apply the __init or
>    __exit attributes on them

Hi,

I have a question about this. If a function is called by __init and __exit functions as well then
I move it to the __exit section. I think this is correct because such a function is available to
both __init and __exit functions as well at runtime.
However this generates a section mismatch (from scripts/mod/modpost.c) e.g.,

   WARNING: vmlinux.o(.init.text+0x196849): Section mismatch in reference from the function sctp_init() to the function .exit.text:sctp_v4_del_protocol()
   The function __init sctp_init() references
   a function __exit sctp_v4_del_protocol().
   This is often seen when error handling in the init function
   uses functionality in the exit path.
   The fix is often to remove the __exit annotation of
   sctp_v4_del_protocol() so it may be used outside an exit section.

This check was introduced by this commit (588ccd732ba2d):
kbuild: add verbose option to Section mismatch reporting in modpost

If this move doesn't cause a problem then I would like to keep it because there are a lot of functions that can become __exit and I would like to remove this warning.

Thanks
-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
                   ` (2 preceding siblings ...)
  2016-06-28 11:42 ` [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
@ 2016-06-28 12:57 ` Mark Rutland
  2016-06-28 16:14   ` Emese Revfy
  2016-06-28 16:35 ` Joe Perches
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: Mark Rutland @ 2016-06-28 12:57 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> I would like to introduce the initify gcc plugin. The kernel already has
> a mechanism to free up code and data memory that is only used during kernel
> or module initialization.
> This plugin will teach the compiler to find more such code and data that
> can be freed after initialization. It reduces memory usage.
> The initify gcc plugin can be useful for embedded systems.
> 
> It is a CII project supported by the Linux Foundation.
> 
> This plugin is the part of grsecurity/PaX.
> 
> The plugin supports all gcc versions from 4.5 to 6.0.
> 
> I made some changes on top of the PaX version (since March 6.). These are
> the important ones:
>  * move all local strings to init.rodata.str and exit.rodata.str
>    (not just __func__)
>  * report all initified strings and functions
>    (GCC_PLUGIN_INITIFY_VERBOSE config option)
>  * automatically discover init/exit functions and apply the __init or
>    __exit attributes on them
> 
> You can find more about the changes here:
> https://github.com/ephox-gcc-plugins/initify
> 
> This patch set is based on the "Add support for complex gcc plugins that
> don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> e5d4798b284cd192c8b).

I was hoping to give this a spin on arm/arm64, but I couldn't find the
prerequisite branch/tag/commit in that tree:

https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b

Where should I be looking?

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 12:57 ` [kernel-hardening] " Mark Rutland
@ 2016-06-28 16:14   ` Emese Revfy
  2016-06-28 20:46     ` Kees Cook
  0 siblings, 1 reply; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 16:14 UTC (permalink / raw)
  To: Mark Rutland
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 28 Jun 2016 13:57:49 +0100
Mark Rutland <mark.rutland@arm.com> wrote:

> On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> > This patch set is based on the "Add support for complex gcc plugins that
> > don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> > e5d4798b284cd192c8b).
> 
> I was hoping to give this a spin on arm/arm64, but I couldn't find the
> prerequisite branch/tag/commit in that tree:
> 
> https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b
> 
> Where should I be looking?

Sorry, this commit was disappear. You can apply these patches to this tree:
https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next.git (initify branch)

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
                   ` (3 preceding siblings ...)
  2016-06-28 12:57 ` [kernel-hardening] " Mark Rutland
@ 2016-06-28 16:35 ` Joe Perches
  2016-06-28 18:48   ` Joe Perches
  2016-06-28 17:00 ` Mathias Krause
  2016-06-28 21:49 ` Joe Perches
  6 siblings, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-28 16:35 UTC (permalink / raw)
  To: Emese Revfy, kernel-hardening, Mathias Krause
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

(adding Mathias Krause who did something similar via macros in 2014)

https://lkml.org/lkml/2014/6/22/149

On Tue, 2016-06-28 at 13:34 +0200, Emese Revfy wrote:
> I would like to introduce the initify gcc plugin. The kernel already has
> a mechanism to free up code and data memory that is only used during kernel
> or module initialization.
> This plugin will teach the compiler to find more such code and data that
> can be freed after initialization. It reduces memory usage.
> The initify gcc plugin can be useful for embedded systems.

What happens to string deduplication when one string
is in an init function and the same string is also used
in a non-init function in the same compilation unit?

foo.c

__init void initfunc(void)
{
	pr_info("%s: I'm here\n", __func__);
}

void runtimefunc(void)
{
	pr_info("I'm here: %s\n", __func__);
}

In what section does the string "I'm here: %s\n" get placed
or does it get placed into multiple sections?

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 11:36 ` [PATCH v1 2/2] Mark functions with the __nocapture attribute Emese Revfy
@ 2016-06-28 16:43   ` Joe Perches
  2016-06-28 20:40     ` Emese Revfy
  2016-06-28 20:50   ` Rasmus Villemoes
  1 sibling, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-28 16:43 UTC (permalink / raw)
  To: Emese Revfy, kernel-hardening
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> The nocapture gcc attribute can be on functions only.
> The attribute takes one or more unsigned integer constants as parameters
> that specify the function argument(s) of const char* type to initify.

Perhaps this should be const <type>*
> diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h
[]
> @@ -7,19 +7,19 @@
[]
>  #define __HAVE_ARCH_MEMCPY
> -extern void * memcpy(void *, const void *, __kernel_size_t);
> +extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
                   ` (4 preceding siblings ...)
  2016-06-28 16:35 ` Joe Perches
@ 2016-06-28 17:00 ` Mathias Krause
  2016-06-28 20:29   ` Emese Revfy
  2016-06-28 21:49 ` Joe Perches
  6 siblings, 1 reply; 32+ messages in thread
From: Mathias Krause @ 2016-06-28 17:00 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

Hi Emese,

On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> I would like to introduce the initify gcc plugin. The kernel already has
> a mechanism to free up code and data memory that is only used during kernel
> or module initialization.
> This plugin will teach the compiler to find more such code and data that
> can be freed after initialization. It reduces memory usage.
> The initify gcc plugin can be useful for embedded systems.
> 
> It is a CII project supported by the Linux Foundation.
> 
> This plugin is the part of grsecurity/PaX.
> 
> The plugin supports all gcc versions from 4.5 to 6.0.
> 
> I made some changes on top of the PaX version (since March 6.). These are
> the important ones:
>  * move all local strings to init.rodata.str and exit.rodata.str
>    (not just __func__)
>  * report all initified strings and functions
>    (GCC_PLUGIN_INITIFY_VERBOSE config option)
>  * automatically discover init/exit functions and apply the __init or
>    __exit attributes on them
> 
> You can find more about the changes here:
> https://github.com/ephox-gcc-plugins/initify
> 
> This patch set is based on the "Add support for complex gcc plugins that
> don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> e5d4798b284cd192c8b).
> 
> Some statistics about the plugin:
> 
> On allyes config (amd64, gcc-6):
> * 7731 initified strings
> *  231 initified functions
> 
> On allmod config (i386, gcc-6):
> * 8846 initified strings
> *  252 initified functions
> 
> On allyes config (amd64, gcc-6):
> 
> section         vanilla                 vanilla + initify        change
> -----------------------------------------------------------------------
> .rodata         39059688 (0x25400e8)    38527210 (0x24be0ea)    -532478
> .data           45744128 (0x2ba0000)    45404160 (0x2b4d000)    -339968
> .init.data       1361144  (0x14c4f8)     1674200  (0x198bd8)    +313056
> .text           77615128 (0x4a05018)    77576664 (0x49fb9d8)     -38464
> .init.text       1108455  (0x10e9e7)     1137618  (0x115bd2)     +29163

You should probably provide numbers for .init.rodata.str, .exit.rodata.str
and .exit.text as well. Otherwise this delta calculation suggests a rather
gigantic image size reduction which is probably not the case ;)

Also a comparison of the final kernel image size would be nice to see if
the string duplication issue mentioned in [1] is actually an issue.

  [1] http://marc.info/?l=linux-kernel&m=140364632417795&w=2


Thanks,
Mathias

> 
> 
> Emese Revfy (2):
>  Add the initify gcc plugin
>  Mark functions with the __nocapture attribute
> 
> ---
>  arch/Kconfig                         |   23 +
>  arch/arm/include/asm/string.h        |   10 +-
>  arch/arm64/include/asm/string.h      |   23 +-
>  arch/powerpc/include/asm/string.h    |   19 +-
>  arch/x86/boot/string.h               |    4 +-
>  arch/x86/include/asm/string_32.h     |   21 +-
>  arch/x86/include/asm/string_64.h     |   18 +-
>  arch/x86/kernel/hpet.c               |    2 +-
>  include/asm-generic/bug.h            |    6 +-
>  include/asm-generic/vmlinux.lds.h    |    2 +
>  include/linux/compiler-gcc.h         |   10 +-
>  include/linux/compiler.h             |    4 +
>  include/linux/fs.h                   |    5 +-
>  include/linux/printk.h               |    2 +-
>  include/linux/string.h               |   73 +--
>  scripts/Makefile.gcc-plugins         |    4 +
>  scripts/gcc-plugins/initify_plugin.c | 1147 ++++++++++++++++++++++++++++++++++
>  17 files changed, 1283 insertions(+), 90 deletions(-)

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 16:35 ` Joe Perches
@ 2016-06-28 18:48   ` Joe Perches
  2016-06-28 19:02     ` Rasmus Villemoes
  0 siblings, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-28 18:48 UTC (permalink / raw)
  To: Emese Revfy, kernel-hardening, Mathias Krause
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 2016-06-28 at 09:35 -0700, Joe Perches wrote:
> (adding Mathias Krause who did something similar via macros in 2014)
> 
> https://lkml.org/lkml/2014/6/22/149
> 
> On Tue, 2016-06-28 at 13:34 +0200, Emese Revfy wrote:
> > 
> > I would like to introduce the initify gcc plugin. The kernel already
> > has
> > a mechanism to free up code and data memory that is only used during
> > kernel
> > or module initialization.
> > This plugin will teach the compiler to find more such code and data
> > that
> > can be freed after initialization. It reduces memory usage.
> > The initify gcc plugin can be useful for embedded systems.
> What happens to string deduplication when one string
> is in an init function and the same string is also used
> in a non-init function in the same compilation unit?
> 
> foo.c
> 
> __init void initfunc(void)
> {
> 	pr_info("%s: I'm here\n", __func__);
> }
> 
> void runtimefunc(void)
> {
> 	pr_info("I'm here: %s\n", __func__);
> }
> 
> In what section does the string "I'm here: %s\n" get placed
> or does it get placed into multiple sections?

Sorry, Joe can't type.
That was meant to be the identical string in both functions.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 18:48   ` Joe Perches
@ 2016-06-28 19:02     ` Rasmus Villemoes
  2016-06-28 20:29       ` Emese Revfy
  0 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2016-06-28 19:02 UTC (permalink / raw)
  To: Joe Perches
  Cc: Emese Revfy, kernel-hardening, Mathias Krause, pageexec, spender,
	mmarek, keescook, linux-kernel, yamada.masahiro, linux-kbuild,
	minipli, linux, catalin.marinas, david.brown, benh, tglx, akpm,
	jlayton, arnd

On Tue, Jun 28 2016, Joe Perches <joe@perches.com> wrote:

>> What happens to string deduplication when one string
>> is in an init function and the same string is also used
>> in a non-init function in the same compilation unit?
>> 
>> foo.c
>> 
>> __init void initfunc(void)
>> {
>> 	pr_info("%s: I'm here\n", __func__);
>> }
>> 
>> void runtimefunc(void)
>> {
>> 	pr_info("I'm here: %s\n", __func__);
>> }
>> 
>> In what section does the string "I'm here: %s\n" get placed
>> or does it get placed into multiple sections?

It'll get placed in multiple sections by the compiler, and nothing bad
happens. String deduplication is something the linker does to sections
equipped with appropriate flags. So in this case that of course means
that the kernel image itself would be slightly bigger, while the used
data after init would be the same. But I don't think there's a lot of
these cases. (Also, "initfunc" would at least vanish).

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 17:00 ` Mathias Krause
@ 2016-06-28 20:29   ` Emese Revfy
  0 siblings, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 20:29 UTC (permalink / raw)
  To: Mathias Krause
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 28 Jun 2016 19:00:22 +0200
Mathias Krause <minipli@ld-linux.so> wrote:

> > section         vanilla                 vanilla + initify        change
> > -----------------------------------------------------------------------
> > .rodata         39059688 (0x25400e8)    38527210 (0x24be0ea)    -532478
> > .data           45744128 (0x2ba0000)    45404160 (0x2b4d000)    -339968
> > .init.data       1361144  (0x14c4f8)     1674200  (0x198bd8)    +313056
> > .text           77615128 (0x4a05018)    77576664 (0x49fb9d8)     -38464
> > .init.text       1108455  (0x10e9e7)     1137618  (0x115bd2)     +29163
> 
> You should probably provide numbers for .init.rodata.str, .exit.rodata.str
> and .exit.text as well. Otherwise this delta calculation suggests a rather
> gigantic image size reduction which is probably not the case ;)

init.rodata.str is an input section that merges into the INIT_DATA output section.
I didn't make statistics for exit* yet because I have a problem with that (I asked
for help in a previous e-mail).
 
> Also a comparison of the final kernel image size would be nice to see if

I no longer have the vmlinux images but I saved away the readelf outputs,
here's the PT_LOAD size data:

        FileSiz (vanilla)       FileSiz (vanilla+initify)       change
-----------------------------------------------------------------------
00      119189504 (0x71ab000)   118657024 (0x7129000)           -532480
01       45838336 (0x2bb7000)    45498368 (0x2b64000)           -339968
03        2830336  (0x2b3000)     3198976  (0x30d000)           +368640


00     .text .text.exit .text.startup .notes __ex_table .rodata __bug_table .pci_fixup
       .builtin_fw .tracedata __ksymtab __ksymtab_gpl __ksymtab_strings __init_rodata __param __modver
01     .data .fini_array .vvar
03     .init.text .altinstr_aux .init.data .x86_cpu_dev.init .parainstructions .altinstructions
       .altinstr_replacement .iommu_table .apicdrivers .exit.text .exit.data .smp_locks .bss .brk

I think the smaller .data section is wrong, so I'll look into it.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 19:02     ` Rasmus Villemoes
@ 2016-06-28 20:29       ` Emese Revfy
  0 siblings, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 20:29 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: Joe Perches, kernel-hardening, Mathias Krause, pageexec, spender,
	mmarek, keescook, linux-kernel, yamada.masahiro, linux-kbuild,
	minipli, linux, catalin.marinas, david.brown, benh, tglx, akpm,
	jlayton, arnd

On Tue, 28 Jun 2016 21:02:54 +0200
Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:

> It'll get placed in multiple sections by the compiler, and nothing bad
> happens. String deduplication is something the linker does to sections
> equipped with appropriate flags. So in this case that of course means

Note that I didn't add such flags to my sections yet, but I have it on my todo list.

> that the kernel image itself would be slightly bigger, while the used
> data after init would be the same. But I don't think there's a lot of
> these cases. (Also, "initfunc" would at least vanish).

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 16:43   ` Joe Perches
@ 2016-06-28 20:40     ` Emese Revfy
  2016-06-28 21:00       ` Joe Perches
  0 siblings, 1 reply; 32+ messages in thread
From: Emese Revfy @ 2016-06-28 20:40 UTC (permalink / raw)
  To: Joe Perches
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 28 Jun 2016 09:43:31 -0700
Joe Perches <joe@perches.com> wrote:

> On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> > The nocapture gcc attribute can be on functions only.
> > The attribute takes one or more unsigned integer constants as parameters
> > that specify the function argument(s) of const char* type to initify.
> 
> Perhaps this should be const <type>*

For me function arguments are the values passed to a function call so
the const char* type is good because this is the only one that the plugin handles
(for now at least).

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 16:14   ` Emese Revfy
@ 2016-06-28 20:46     ` Kees Cook
  2016-06-29  8:21       ` Mark Rutland
  0 siblings, 1 reply; 32+ messages in thread
From: Kees Cook @ 2016-06-28 20:46 UTC (permalink / raw)
  To: Emese Revfy
  Cc: Mark Rutland, kernel-hardening, PaX Team, Brad Spengler,
	Michal Marek, LKML, Masahiro Yamada, linux-kbuild, minipli,
	Russell King, Catalin Marinas, Rasmus Villemoes, David Brown,
	benh, Thomas Gleixner, Andrew Morton, jlayton, Arnd Bergmann

On Tue, Jun 28, 2016 at 9:14 AM, Emese Revfy <re.emese@gmail.com> wrote:
> On Tue, 28 Jun 2016 13:57:49 +0100
> Mark Rutland <mark.rutland@arm.com> wrote:
>
>> On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
>> > This patch set is based on the "Add support for complex gcc plugins that
>> > don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
>> > e5d4798b284cd192c8b).
>>
>> I was hoping to give this a spin on arm/arm64, but I couldn't find the
>> prerequisite branch/tag/commit in that tree:
>>
>> https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b
>>
>> Where should I be looking?
>
> Sorry, this commit was disappear. You can apply these patches to this tree:
> https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next.git (initify branch)

The linux-next tree should have what you need for the plugin support.
This is merging from my KSPP tree:

https://git.kernel.org/linux/kernel/git/kees/linux.git for-next/kspp

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 11:36 ` [PATCH v1 2/2] Mark functions with the __nocapture attribute Emese Revfy
  2016-06-28 16:43   ` Joe Perches
@ 2016-06-28 20:50   ` Rasmus Villemoes
  2016-06-28 21:38     ` PaX Team
  2016-06-29 18:39     ` Emese Revfy
  1 sibling, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2016-06-28 20:50 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, Jun 28 2016, Emese Revfy <re.emese@gmail.com> wrote:

> The nocapture gcc attribute can be on functions only.
> The attribute takes one or more unsigned integer constants as parameters
> that specify the function argument(s) of const char* type to initify.
> If the marked argument is a vararg then the plugin initifies
> all vararg arguments.
>
> I couldn't test the arm, arm64 and powerpc architectures.
>
> Signed-off-by: Emese Revfy <re.emese@gmail.com>
> ---
>  arch/arm/include/asm/string.h     | 10 +++---
>  arch/arm64/include/asm/string.h   | 23 ++++++------
>  arch/powerpc/include/asm/string.h | 19 +++++-----
>  arch/x86/boot/string.h            |  4 +--
>  arch/x86/include/asm/string_32.h  | 21 +++++------
>  arch/x86/include/asm/string_64.h  | 18 +++++-----
>  arch/x86/kernel/hpet.c            |  2 +-
>  include/asm-generic/bug.h         |  6 ++--
>  include/linux/compiler-gcc.h      | 10 ++++--
>  include/linux/compiler.h          |  4 +++
>  include/linux/fs.h                |  5 +--
>  include/linux/printk.h            |  2 +-
>  include/linux/string.h            | 73 ++++++++++++++++++++-------------------
>  13 files changed, 107 insertions(+), 90 deletions(-)
>
> diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h
> index cf4f3aa..3f68273 100644
> --- a/arch/arm/include/asm/string.h
> +++ b/arch/arm/include/asm/string.h
> @@ -7,19 +7,19 @@
>   */
>  
>  #define __HAVE_ARCH_STRRCHR
> -extern char * strrchr(const char * s, int c);
> +extern char * strrchr(const char * s, int c) __nocapture(1);
>  
>  #define __HAVE_ARCH_STRCHR
> -extern char * strchr(const char * s, int c);
> +extern char * strchr(const char * s, int c) __nocapture(1);
>  
>  #define __HAVE_ARCH_MEMCPY
> -extern void * memcpy(void *, const void *, __kernel_size_t);
> +extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
>  

Why not also mark he dest argument of the various strcpy/memcpy/memset
functions as nocapture? It's no use for the initify plugin, but a static
analysis tool could for example use it to (better) diagnose resource leaks
(e.g., a buffer is kmalloc'ed and initialized with some *cpy, but then
something goes wrong, and the buffer isn't freed on the error path).
>  
>  #define __HAVE_ARCH_STRLEN
>  extern __kernel_size_t strlen(const char *);

Why not also mark strlen? I know that gcc optimizes strlen("literal")
away, but, again, there might be other uses even when the argument is
not a literal. One example is the plugin itself, which could deduce (or
suggest) __nocapture for a given function parameter if the parameter is
only passed on as __nocapture arguments.

> diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
> index 6f96247..4cdf266 100644
> --- a/include/asm-generic/bug.h
> +++ b/include/asm-generic/bug.h
> @@ -62,13 +62,13 @@ struct bug_entry {
>   * to provide better diagnostics.
>   */
>  #ifndef __WARN_TAINT
> -extern __printf(3, 4)
> +extern __printf(3, 4) __nocapture(1, 3, 4)
>  void warn_slowpath_fmt(const char *file, const int line,
>  		       const char *fmt, ...);
> -extern __printf(4, 5)
> +extern __printf(4, 5) __nocapture(1, 4, 5)
>  void warn_slowpath_fmt_taint(const char *file, const int line, unsigned taint,
>  			     const char *fmt, ...);

The 3,4 and 4,5 parts seem redundant when __printf automatically supplies those.

> -extern void warn_slowpath_null(const char *file, const int line);
> +extern __nocapture(1) void warn_slowpath_null(const char *file, const int line);
>  #define WANT_WARN_ON_SLOWPATH
>  #define __WARN()		warn_slowpath_null(__FILE__, __LINE__)
>  #define __WARN_printf(arg...)	warn_slowpath_fmt(__FILE__, __LINE__, arg)
> diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
> index df88c0a..192cea4 100644
> --- a/include/linux/compiler-gcc.h
> +++ b/include/linux/compiler-gcc.h
> @@ -116,8 +116,10 @@
>   */
>  #define __pure			__attribute__((pure))
>  #define __aligned(x)		__attribute__((aligned(x)))
> -#define __printf(a, b)		__attribute__((format(printf, a, b)))
> -#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
> +#define __printf(a, b)		__attribute__((format(printf, a, b))) \
> +				__nocapture(a, b)
> +#define __scanf(a, b)		__attribute__((format(scanf, a, b))) \
> +				__nocapture(a, b)

So obviously the output parameters for scanf are never going to be
string literals, but I've already argued that one might as well put the
__nocapture on all relevant pointer arguments while we're churning the
headers, so keep this.

>  
> -extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
> -extern const char *kstrdup_const(const char *s, gfp_t gfp);
> -extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
> -extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
> +extern char *kstrdup(const char *s, gfp_t gfp) __malloc __nocapture(1);
> +extern const char *kstrdup_const(const char *s, gfp_t gfp) __nocapture(1);

OK, so this one is pretty dangerous, and probably wrong. If one does

  foo->bar = kstrdup_const(a-macro-that-might-be-a-string-literal)

in an .init function, foo->bar will very likely become dangling. Come to
think of it, I guess this means that __nocapture arguments must not only
not be stashed anywhere, the return value cannot point (in)to the same
object, which in turn then also disqualifies at least strchr(), memchr()
and the haystack parameter of strstr(). And bummer, that kills my
suggestion to add __nocapture to the dst parameters of *cpy, since they
return that argument.

Rasmus

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 20:40     ` Emese Revfy
@ 2016-06-28 21:00       ` Joe Perches
  2016-06-29 18:42         ` Emese Revfy
  0 siblings, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-28 21:00 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 2016-06-28 at 22:40 +0200, Emese Revfy wrote:
> On Tue, 28 Jun 2016 09:43:31 -0700 Joe Perches <joe@perches.com> wrote:
> > On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> > > The nocapture gcc attribute can be on functions only.
> > > The attribute takes one or more unsigned integer constants as parameters
> > > that specify the function argument(s) of const char* type to initify.
> > Perhaps this should be const *
> For me function arguments are the values passed to a function call so
> the const char* type is good because this is the only one that the plugin handles
> (for now at least).

OK, but this function prototype specified takes a const void *

+extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 1/2] Add the initify gcc plugin
  2016-06-28 11:35 ` [PATCH v1 1/2] Add " Emese Revfy
@ 2016-06-28 21:05   ` Rasmus Villemoes
  2016-06-29 14:50     ` Kees Cook
  2016-06-29 19:03     ` Emese Revfy
  0 siblings, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2016-06-28 21:05 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, Jun 28 2016, Emese Revfy <re.emese@gmail.com> wrote:

> The kernel already has a mechanism to free up code and data memory that
> is only used during kernel or module initialization.
> This plugin will teach the compiler to find more such code and data that
> can be freed after initialization.
> It has two passes. The first one tries to find all functions that
> can be become __init/__exit. The second one moves string constants
> (local variables and function string arguments marked by
> the nocapture attribute) only referenced in __init/__exit functions
> to the __initconst/__exitconst sections.
> It reduces memory usage. This plugin can be useful for embedded systems.

May I suggest, as a followup patch, a debug option/plugin parameter to
put the strings in a section which will not be reaped after init, but
just marked inaccessible, with graceful handling of bad accesses (print
a big fat warning, make the page(s) readable, continue)?

Rasmus

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 20:50   ` Rasmus Villemoes
@ 2016-06-28 21:38     ` PaX Team
  2016-06-28 22:41       ` Rasmus Villemoes
  2016-06-29 18:39     ` Emese Revfy
  1 sibling, 1 reply; 32+ messages in thread
From: PaX Team @ 2016-06-28 21:38 UTC (permalink / raw)
  To: Emese Revfy, Rasmus Villemoes
  Cc: kernel-hardening, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	david.brown, benh, tglx, akpm, jlayton, arnd

On 28 Jun 2016 at 22:50, Rasmus Villemoes wrote:

> > +extern const char *kstrdup_const(const char *s, gfp_t gfp) __nocapture(1);
> 
> OK, so this one is pretty dangerous, and probably wrong. If one does
> 
>   foo->bar = kstrdup_const(a-macro-that-might-be-a-string-literal)
> 
> in an .init function, foo->bar will very likely become dangling.

doesn't kstrdup_const omit the copy only for arguments that are stored in
.rodata (which doesn't include .init.rodata* and other init sections)?

cheers,
 PaX Team

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
                   ` (5 preceding siblings ...)
  2016-06-28 17:00 ` Mathias Krause
@ 2016-06-28 21:49 ` Joe Perches
  2016-06-28 22:07   ` [kernel-hardening] " Valdis.Kletnieks
  6 siblings, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-28 21:49 UTC (permalink / raw)
  To: Emese Revfy, kernel-hardening, Matt Davis
  Cc: pageexec, spender, mmarek, keescook, linux-kernel,
	yamada.masahiro, linux-kbuild, minipli, linux, catalin.marinas,
	linux, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 2016-06-28 at 13:34 +0200, Emese Revfy wrote:
> I would like to introduce the initify gcc plugin. The kernel already has
> a mechanism to free up code and data memory that is only used during kernel
> or module initialization.
> This plugin will teach the compiler to find more such code and data that
> can be freed after initialization. It reduces memory usage.
> The initify gcc plugin can be useful for embedded systems.

Another potentially useful plugin, especially for embedded systems,
would be to compress any string literal marked with

	 __attribute__((format(printf, string-index,)))

and decompress the compressed format on the stack in lib/vsprintf.c
vsnprintf just before use.

I've started to experiment with that.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 21:49 ` Joe Perches
@ 2016-06-28 22:07   ` Valdis.Kletnieks
  2016-06-28 23:54     ` Joe Perches
  0 siblings, 1 reply; 32+ messages in thread
From: Valdis.Kletnieks @ 2016-06-28 22:07 UTC (permalink / raw)
  To: kernel-hardening
  Cc: Emese Revfy, Matt Davis, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

[-- Attachment #1: Type: text/plain, Size: 939 bytes --]

On Tue, 28 Jun 2016 14:49:15 -0700, Joe Perches said:

> Another potentially useful plugin, especially for embedded systems,
> would be to compress any string literal marked with
>
> 	 __attribute__((format(printf, string-index,)))
>
> and decompress the compressed format on the stack in lib/vsprintf.c
> vsnprintf just before use.

Are there enough such strings in the kernel to make it worth the effort?
I'm assuming that the string literals in printk("some string here") are
automatically so marked?

Is there a minimum length under which the compression overhead actually
makes it larger?  For instance, "a" can't be compressed, because you need
to indicate there's 1 "a" and 1 \0, while "aaaaaa" can, because you can
express it as '6*"a" 1 \0 in only 4 bytes not 7.  But exactly where the
cutoff is, I have no idea (and is probably *very* text-dependent, as
"aaaaaa" and "abcdef" will compress differently....)


[-- Attachment #2: Type: application/pgp-signature, Size: 848 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 21:38     ` PaX Team
@ 2016-06-28 22:41       ` Rasmus Villemoes
  0 siblings, 0 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2016-06-28 22:41 UTC (permalink / raw)
  To: pageexec
  Cc: Emese Revfy, kernel-hardening, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, Jun 28 2016, "PaX Team" <pageexec@freemail.hu> wrote:

> On 28 Jun 2016 at 22:50, Rasmus Villemoes wrote:
>
>> > +extern const char *kstrdup_const(const char *s, gfp_t gfp) __nocapture(1);
>> 
>> OK, so this one is pretty dangerous, and probably wrong. If one does
>> 
>>   foo->bar = kstrdup_const(a-macro-that-might-be-a-string-literal)
>> 
>> in an .init function, foo->bar will very likely become dangling.
>
> doesn't kstrdup_const omit the copy only for arguments that are stored in
> .rodata (which doesn't include .init.rodata* and other init sections)?
>

Ah, right. But that's a little subtle. Also, it kind of defeats the
purpose of kstrdup_const - but it's probably not actually called with a
string literal all that often.

In any case, I think there's still a problem with strchr() and friends.

Rasmus

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] Re: [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 22:07   ` [kernel-hardening] " Valdis.Kletnieks
@ 2016-06-28 23:54     ` Joe Perches
  0 siblings, 0 replies; 32+ messages in thread
From: Joe Perches @ 2016-06-28 23:54 UTC (permalink / raw)
  To: Valdis.Kletnieks, kernel-hardening
  Cc: Emese Revfy, Matt Davis, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 2016-06-28 at 18:07 -0400, Valdis.Kletnieks@vt.edu wrote:
> On Tue, 28 Jun 2016 14:49:15 -0700, Joe Perches said:
> 
> > 
> > Another potentially useful plugin, especially for embedded systems,
> > would be to compress any string literal marked with
> > 
> > 	 __attribute__((format(printf, string-index,)))
> > 
> > and decompress the compressed format on the stack in lib/vsprintf.c
> > vsnprintf just before use.
> Are there enough such strings in the kernel to make it worth the effort?
> I'm assuming that the string literals in printk("some string here") are
> automatically so marked?

Yes, that's the concept.

> Is there a minimum length under which the compression overhead actually
> makes it larger?

No, compression would have to be possible, otherwise it'd
be stored directly.  Compression would use a special
"compressed string" header with a 2 byte overhead and
then stored with no trailing \0.

Something like struct compressed_format_header {
	u8	flag;	/* Must be ASCII STX or "\b" */
	u8	length;
}

Depends on the config of course, but it could reduce total
image size ~50k on an x86-32 defconfig

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-28 20:46     ` Kees Cook
@ 2016-06-29  8:21       ` Mark Rutland
  2016-06-29 17:52         ` Mark Rutland
  0 siblings, 1 reply; 32+ messages in thread
From: Mark Rutland @ 2016-06-29  8:21 UTC (permalink / raw)
  To: Kees Cook
  Cc: Emese Revfy, kernel-hardening, PaX Team, Brad Spengler,
	Michal Marek, LKML, Masahiro Yamada, linux-kbuild, minipli,
	Russell King, Catalin Marinas, Rasmus Villemoes, David Brown,
	benh, Thomas Gleixner, Andrew Morton, jlayton, Arnd Bergmann

On Tue, Jun 28, 2016 at 01:46:04PM -0700, Kees Cook wrote:
> On Tue, Jun 28, 2016 at 9:14 AM, Emese Revfy <re.emese@gmail.com> wrote:
> > On Tue, 28 Jun 2016 13:57:49 +0100
> > Mark Rutland <mark.rutland@arm.com> wrote:
> >
> >> On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> >> > This patch set is based on the "Add support for complex gcc plugins that
> >> > don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> >> > e5d4798b284cd192c8b).
> >>
> >> I was hoping to give this a spin on arm/arm64, but I couldn't find the
> >> prerequisite branch/tag/commit in that tree:
> >>
> >> https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b
> >>
> >> Where should I be looking?
> >
> > Sorry, this commit was disappear. You can apply these patches to this tree:
> > https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next.git (initify branch)
> 
> The linux-next tree should have what you need for the plugin support.
> This is merging from my KSPP tree:
> 
> https://git.kernel.org/linux/kernel/git/kees/linux.git for-next/kspp

I didn't see the complex gcc plugins patch in that branch or linux-next,
so I take it you mean a a base for applying the complex plugin patch and
initify patches.

I'll try to give that a go shortly.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 1/2] Add the initify gcc plugin
  2016-06-28 21:05   ` Rasmus Villemoes
@ 2016-06-29 14:50     ` Kees Cook
  2016-06-29 19:03     ` Emese Revfy
  1 sibling, 0 replies; 32+ messages in thread
From: Kees Cook @ 2016-06-29 14:50 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: Emese Revfy, kernel-hardening, PaX Team, Brad Spengler,
	Michal Marek, LKML, Masahiro Yamada, linux-kbuild, minipli,
	Russell King, Catalin Marinas, David Brown, benh,
	Thomas Gleixner, Andrew Morton, jlayton, Arnd Bergmann

On Tue, Jun 28, 2016 at 2:05 PM, Rasmus Villemoes
<linux@rasmusvillemoes.dk> wrote:
> On Tue, Jun 28 2016, Emese Revfy <re.emese@gmail.com> wrote:
>
>> The kernel already has a mechanism to free up code and data memory that
>> is only used during kernel or module initialization.
>> This plugin will teach the compiler to find more such code and data that
>> can be freed after initialization.
>> It has two passes. The first one tries to find all functions that
>> can be become __init/__exit. The second one moves string constants
>> (local variables and function string arguments marked by
>> the nocapture attribute) only referenced in __init/__exit functions
>> to the __initconst/__exitconst sections.
>> It reduces memory usage. This plugin can be useful for embedded systems.
>
> May I suggest, as a followup patch, a debug option/plugin parameter to
> put the strings in a section which will not be reaped after init, but
> just marked inaccessible, with graceful handling of bad accesses (print
> a big fat warning, make the page(s) readable, continue)?

Is there a clean way to do this that isn't arch-specific?

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-29  8:21       ` Mark Rutland
@ 2016-06-29 17:52         ` Mark Rutland
  2016-06-29 18:28           ` Emese Revfy
  0 siblings, 1 reply; 32+ messages in thread
From: Mark Rutland @ 2016-06-29 17:52 UTC (permalink / raw)
  To: Kees Cook
  Cc: Emese Revfy, kernel-hardening, PaX Team, Brad Spengler,
	Michal Marek, LKML, Masahiro Yamada, linux-kbuild, minipli,
	Russell King, Catalin Marinas, Rasmus Villemoes, David Brown,
	benh, Thomas Gleixner, Andrew Morton, jlayton, Arnd Bergmann

On Wed, Jun 29, 2016 at 09:21:37AM +0100, Mark Rutland wrote:
> On Tue, Jun 28, 2016 at 01:46:04PM -0700, Kees Cook wrote:
> > On Tue, Jun 28, 2016 at 9:14 AM, Emese Revfy <re.emese@gmail.com> wrote:
> > > On Tue, 28 Jun 2016 13:57:49 +0100
> > > Mark Rutland <mark.rutland@arm.com> wrote:
> > >
> > >> On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> > >> > This patch set is based on the "Add support for complex gcc plugins that
> > >> > don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> > >> > e5d4798b284cd192c8b).
> > >>
> > >> I was hoping to give this a spin on arm/arm64, but I couldn't find the
> > >> prerequisite branch/tag/commit in that tree:
> > >>
> > >> https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b
> > >>
> > >> Where should I be looking?
> > >
> > > Sorry, this commit was disappear. You can apply these patches to this tree:
> > > https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next.git (initify branch)
> > 
> > The linux-next tree should have what you need for the plugin support.
> > This is merging from my KSPP tree:
> > 
> > https://git.kernel.org/linux/kernel/git/kees/linux.git for-next/kspp
> 
> I didn't see the complex gcc plugins patch in that branch or linux-next,
> so I take it you mean a a base for applying the complex plugin patch and
> initify patches.
> 
> I'll try to give that a go shortly.

I tried to give this a go atop of kees's for-next/kspp branch, but this
doesn't seem to build. With the Linaro 15.08 AArch64 toolchain, I see:

[mark@leverpostej:~/src/linux]% uselinaro 15.08 make V=1 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 
set -e; : '  CHK     include/config/kernel.release'; mkdir -p include/config/;  echo "4.7.0-rc1$(/bin/bash ./scripts/setlocalversion .)" < include/config/auto.conf > include/config/kernel.release.tmp; if [ -r include/config/kernel.release ] && cmp -s include/config/kernel.release include/config/kernel.release.tmp; then rm -f include/config/kernel.release.tmp; else : '  UPD     include/config/kernel.release'; mv -f include/config/kernel.release.tmp include/config/kernel.release; fi
make -f ./scripts/Makefile.asm-generic \
                    src=asm obj=arch/arm64/include/generated/asm
make -f ./scripts/Makefile.asm-generic \
                    src=uapi/asm obj=arch/arm64/include/generated/uapi/asm
set -e; : '  CHK     include/generated/uapi/linux/version.h'; mkdir -p include/generated/uapi/linux/;   (echo \#define LINUX_VERSION_CODE 263936; echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';) < Makefile > include/generated/uapi/linux/version.h.tmp; if [ -r include/generated/uapi/linux/version.h ] && cmp -s include/generated/uapi/linux/version.h include/generated/uapi/linux/version.h.tmp; then rm -f include/generated/uapi/linux/version.h.tmp; else : '  UPD     include/generated/uapi/linux/version.h'; mv -f include/generated/uapi/linux/version.h.tmp include/generated/uapi/linux/version.h; fi
rm -f include/linux/version.h
set -e; : '  CHK     include/generated/utsrelease.h'; mkdir -p include/generated/;      if [ `echo -n "4.7.0-rc1+" | wc -c ` -gt 64 ]; then echo '"4.7.0-rc1+" exceeds 64 characters' >&2; exit 1; fi; (echo \#define UTS_RELEASE \"4.7.0-rc1+\";) < include/config/kernel.release > include/generated/utsrelease.h.tmp; if [ -r include/generated/utsrelease.h ] && cmp -s include/generated/utsrelease.h include/generated/utsrelease.h.tmp; then rm -f include/generated/utsrelease.h.tmp; else : '  UPD     include/generated/utsrelease.h'; mv -f include/generated/utsrelease.h.tmp include/generated/utsrelease.h; fi
mkdir -p .tmp_versions ; rm -f .tmp_versions/*
test -e include/generated/autoksyms.h || \
            touch   include/generated/autoksyms.h
make -f ./scripts/Makefile.build obj=scripts/basic
(cat /dev/null; ) > scripts/basic/modules.order
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/gcc-plugins
(cat /dev/null; ) > scripts/gcc-plugins/modules.order
  g++  -shared -o scripts/gcc-plugins/initify_plugin.so   
g++: fatal error: no input files
compilation terminated.
make[1]: *** [scripts/gcc-plugins/initify_plugin.so] Error 4
make: *** [gcc-plugins] Error 2

Any ideas?

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [kernel-hardening] [PATCH v1 0/2] Introduce the initify gcc plugin
  2016-06-29 17:52         ` Mark Rutland
@ 2016-06-29 18:28           ` Emese Revfy
  0 siblings, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-29 18:28 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Kees Cook, kernel-hardening, PaX Team, Brad Spengler,
	Michal Marek, LKML, Masahiro Yamada, linux-kbuild, minipli,
	Russell King, Catalin Marinas, Rasmus Villemoes, David Brown,
	benh, Thomas Gleixner, Andrew Morton, jlayton, Arnd Bergmann

On Wed, 29 Jun 2016 18:52:27 +0100
Mark Rutland <mark.rutland@arm.com> wrote:

> On Wed, Jun 29, 2016 at 09:21:37AM +0100, Mark Rutland wrote:
> > On Tue, Jun 28, 2016 at 01:46:04PM -0700, Kees Cook wrote:
> > > On Tue, Jun 28, 2016 at 9:14 AM, Emese Revfy <re.emese@gmail.com> wrote:
> > > > On Tue, 28 Jun 2016 13:57:49 +0100
> > > > Mark Rutland <mark.rutland@arm.com> wrote:
> > > >
> > > >> On Tue, Jun 28, 2016 at 01:34:07PM +0200, Emese Revfy wrote:
> > > >> > This patch set is based on the "Add support for complex gcc plugins that
> > > >> > don't fit in a single file" patch set (git/kees/linux.git#kspp HEAD:
> > > >> > e5d4798b284cd192c8b).
> > > >>
> > > >> I was hoping to give this a spin on arm/arm64, but I couldn't find the
> > > >> prerequisite branch/tag/commit in that tree:
> > > >>
> > > >> https://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/commit/?id=e5d4798b284cd192c8b
> > > >>
> > > >> Where should I be looking?
> > > >
> > > > Sorry, this commit was disappear. You can apply these patches to this tree:
> > > > https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next.git (initify branch)
>
> g++: fatal error: no input files
> compilation terminated.
> make[1]: *** [scripts/gcc-plugins/initify_plugin.so] Error 4
> make: *** [gcc-plugins] Error 2

Hi,

There are some missing patches from Kees tree that's why I suggested my tree above.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 20:50   ` Rasmus Villemoes
  2016-06-28 21:38     ` PaX Team
@ 2016-06-29 18:39     ` Emese Revfy
  1 sibling, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-29 18:39 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 28 Jun 2016 22:50:55 +0200
Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:

> On Tue, Jun 28 2016, Emese Revfy <re.emese@gmail.com> wrote: 
> > diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
> > index 6f96247..4cdf266 100644
> > --- a/include/asm-generic/bug.h
> > +++ b/include/asm-generic/bug.h
> > @@ -62,13 +62,13 @@ struct bug_entry {
> >   * to provide better diagnostics.
> >   */
> >  #ifndef __WARN_TAINT
> > -extern __printf(3, 4)
> > +extern __printf(3, 4) __nocapture(1, 3, 4)
> >  void warn_slowpath_fmt(const char *file, const int line,
> >  		       const char *fmt, ...);
> > -extern __printf(4, 5)
> > +extern __printf(4, 5) __nocapture(1, 4, 5)
> >  void warn_slowpath_fmt_taint(const char *file, const int line, unsigned taint,
> >  			     const char *fmt, ...);
> 
> The 3,4 and 4,5 parts seem redundant when __printf automatically supplies those.

Thanks, I'll fix them in the next patch set.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-28 21:00       ` Joe Perches
@ 2016-06-29 18:42         ` Emese Revfy
  2016-06-30  0:12           ` Joe Perches
  0 siblings, 1 reply; 32+ messages in thread
From: Emese Revfy @ 2016-06-29 18:42 UTC (permalink / raw)
  To: Joe Perches
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Tue, 28 Jun 2016 14:00:57 -0700
Joe Perches <joe@perches.com> wrote:

> On Tue, 2016-06-28 at 22:40 +0200, Emese Revfy wrote:
> > On Tue, 28 Jun 2016 09:43:31 -0700 Joe Perches <joe@perches.com> wrote:
> > > On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> > > > The nocapture gcc attribute can be on functions only.
> > > > The attribute takes one or more unsigned integer constants as parameters
> > > > that specify the function argument(s) of const char* type to initify.
> > > Perhaps this should be const *
> > For me function arguments are the values passed to a function call so
> > the const char* type is good because this is the only one that the plugin handles
> > (for now at least).
> 
> OK, but this function prototype specified takes a const void *
> 
> +extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);

What matters for the plugin is the type of the passed arguments (which can be const char*
in the current implementation), not that of the parameters.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 1/2] Add the initify gcc plugin
  2016-06-28 21:05   ` Rasmus Villemoes
  2016-06-29 14:50     ` Kees Cook
@ 2016-06-29 19:03     ` Emese Revfy
  1 sibling, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-06-29 19:03 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, david.brown, benh, tglx, akpm, jlayton, arnd

On Tue, 28 Jun 2016 23:05:56 +0200
Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:

> On Tue, Jun 28 2016, Emese Revfy <re.emese@gmail.com> wrote:
> 
> > The kernel already has a mechanism to free up code and data memory that
> > is only used during kernel or module initialization.
> > This plugin will teach the compiler to find more such code and data that
> > can be freed after initialization.
> > It has two passes. The first one tries to find all functions that
> > can be become __init/__exit. The second one moves string constants
> > (local variables and function string arguments marked by
> > the nocapture attribute) only referenced in __init/__exit functions
> > to the __initconst/__exitconst sections.
> > It reduces memory usage. This plugin can be useful for embedded systems.
> 
> May I suggest, as a followup patch, a debug option/plugin parameter to
> put the strings in a section which will not be reaped after init, but
> just marked inaccessible, with graceful handling of bad accesses (print
> a big fat warning, make the page(s) readable, continue)?

I think even better would be to verify the whole init section.
Unfortunately, I won't implement it anytime soon because my project ends this week.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-29 18:42         ` Emese Revfy
@ 2016-06-30  0:12           ` Joe Perches
  2016-07-01 14:03             ` Emese Revfy
  0 siblings, 1 reply; 32+ messages in thread
From: Joe Perches @ 2016-06-30  0:12 UTC (permalink / raw)
  To: Emese Revfy
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Wed, 2016-06-29 at 20:42 +0200, Emese Revfy wrote:
> On Tue, 28 Jun 2016 14:00:57 -0700 Joe Perches <joe@perches.com> wrote:
> > On Tue, 2016-06-28 at 22:40 +0200, Emese Revfy wrote:
> > > On Tue, 28 Jun 2016 09:43:31 -0700 Joe Perches <joe@perches.com> wrote:
> > > > On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> > > > > The nocapture gcc attribute can be on functions only.
> > > > > The attribute takes one or more unsigned integer constants as parameters
> > > > > that specify the function argument(s) of const char* type to initify.
> > > > Perhaps this should be const <void>*
> > > For me function arguments are the values passed to a function call so
> > > the const char* type is good because this is the only one that the plugin handles
> > > (for now at least).
> > OK, but this function prototype specified takes a const void *
> > 
> > +extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
> What matters for the plugin is the type of the passed arguments (which can be const char*
> in the current implementation), not that of the parameters.

And how does this work when the prototype requires the compiler to
implicit cast to const void * before calling the function?

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v1 2/2] Mark functions with the __nocapture attribute
  2016-06-30  0:12           ` Joe Perches
@ 2016-07-01 14:03             ` Emese Revfy
  0 siblings, 0 replies; 32+ messages in thread
From: Emese Revfy @ 2016-07-01 14:03 UTC (permalink / raw)
  To: Joe Perches
  Cc: kernel-hardening, pageexec, spender, mmarek, keescook,
	linux-kernel, yamada.masahiro, linux-kbuild, minipli, linux,
	catalin.marinas, linux, david.brown, benh, tglx, akpm, jlayton,
	arnd

On Wed, 29 Jun 2016 17:12:45 -0700
Joe Perches <joe@perches.com> wrote:

> On Wed, 2016-06-29 at 20:42 +0200, Emese Revfy wrote:
> > On Tue, 28 Jun 2016 14:00:57 -0700 Joe Perches <joe@perches.com> wrote:
> > > On Tue, 2016-06-28 at 22:40 +0200, Emese Revfy wrote:
> > > > On Tue, 28 Jun 2016 09:43:31 -0700 Joe Perches <joe@perches.com> wrote:
> > > > > On Tue, 2016-06-28 at 13:36 +0200, Emese Revfy wrote:
> > > > > > The nocapture gcc attribute can be on functions only.
> > > > > > The attribute takes one or more unsigned integer constants as parameters
> > > > > > that specify the function argument(s) of const char* type to initify.
> > > > > Perhaps this should be const <void>*
> > > > For me function arguments are the values passed to a function call so
> > > > the const char* type is good because this is the only one that the plugin handles
> > > > (for now at least).
> > > OK, but this function prototype specified takes a const void *
> > > 
> > > +extern void * memcpy(void *, const void *, __kernel_size_t) __nocapture(2);
> > What matters for the plugin is the type of the passed arguments (which can be const char*
> > in the current implementation), not that of the parameters.
> 
> And how does this work when the prototype requires the compiler to
> implicit cast to const void * before calling the function?


The plugin searches for the nocapture attribute that does not depend on the type.
If the function argument is not a string constant just a pointer then
the plugin walks the data flow (use-def chain) and tries to find a string constant.
If there is a cast to void * then the use-def chain will walk across it.

-- 
Emese

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2016-07-01 13:57 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-28 11:34 [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
2016-06-28 11:35 ` [PATCH v1 1/2] Add " Emese Revfy
2016-06-28 21:05   ` Rasmus Villemoes
2016-06-29 14:50     ` Kees Cook
2016-06-29 19:03     ` Emese Revfy
2016-06-28 11:36 ` [PATCH v1 2/2] Mark functions with the __nocapture attribute Emese Revfy
2016-06-28 16:43   ` Joe Perches
2016-06-28 20:40     ` Emese Revfy
2016-06-28 21:00       ` Joe Perches
2016-06-29 18:42         ` Emese Revfy
2016-06-30  0:12           ` Joe Perches
2016-07-01 14:03             ` Emese Revfy
2016-06-28 20:50   ` Rasmus Villemoes
2016-06-28 21:38     ` PaX Team
2016-06-28 22:41       ` Rasmus Villemoes
2016-06-29 18:39     ` Emese Revfy
2016-06-28 11:42 ` [PATCH v1 0/2] Introduce the initify gcc plugin Emese Revfy
2016-06-28 12:57 ` [kernel-hardening] " Mark Rutland
2016-06-28 16:14   ` Emese Revfy
2016-06-28 20:46     ` Kees Cook
2016-06-29  8:21       ` Mark Rutland
2016-06-29 17:52         ` Mark Rutland
2016-06-29 18:28           ` Emese Revfy
2016-06-28 16:35 ` Joe Perches
2016-06-28 18:48   ` Joe Perches
2016-06-28 19:02     ` Rasmus Villemoes
2016-06-28 20:29       ` Emese Revfy
2016-06-28 17:00 ` Mathias Krause
2016-06-28 20:29   ` Emese Revfy
2016-06-28 21:49 ` Joe Perches
2016-06-28 22:07   ` [kernel-hardening] " Valdis.Kletnieks
2016-06-28 23:54     ` Joe Perches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).