lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20160316212556.GB6872@packer-debian-8-amd64.digitalocean.com>
Date:	Wed, 16 Mar 2016 17:25:56 -0400
From:	Jessica Yu <jeyu@...hat.com>
To:	Rusty Russell <rusty@...tcorp.com.au>,
	Josh Poimboeuf <jpoimboe@...hat.com>,
	Petr Mladek <pmladek@...e.com>, Jiri Kosina <jikos@...nel.org>,
	Jonathan Corbet <corbet@....net>,
	Miroslav Benes <mbenes@...e.cz>
Cc:	linux-api@...r.kernel.org, live-patching@...r.kernel.org,
	x86@...nel.org, linux-kernel@...r.kernel.org,
	linux-s390@...r.kernel.org, linux-doc@...r.kernel.org
Subject: Re: module: preserve Elf information for livepatch modules

+++ Jessica Yu [16/03/16 15:47 -0400]:
>For livepatch modules, copy Elf section, symbol, and string information
>from the load_info struct in the module loader. Persist copies of the
>original symbol table and string table.
>
>Livepatch manages its own relocation sections in order to reuse module
>loader code to write relocations. Livepatch modules must preserve Elf
>information such as section indices in order to apply livepatch relocation
>sections using the module loader's apply_relocate_add() function.
>
>In order to apply livepatch relocation sections, livepatch modules must
>keep a complete copy of their original symbol table in memory. Normally, a
>stripped down copy of a module's symbol table (containing only "core"
>symbols) is made available through module->core_symtab. But for livepatch
>modules, the symbol table copied into memory on module load must be exactly
>the same as the symbol table produced when the patch module was compiled.
>This is because the relocations in each livepatch relocation section refer
>to their respective symbols with their symbol indices, and the original
>symbol indices (and thus the symtab ordering) must be preserved in order
>for apply_relocate_add() to find the right symbol.
>
>Signed-off-by: Jessica Yu <jeyu@...hat.com>
>---
> include/linux/module.h |  25 ++++++++++
> kernel/module.c        | 123 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 146 insertions(+), 2 deletions(-)
>
>diff --git a/include/linux/module.h b/include/linux/module.h
>index 2bb0c30..3daf2b3 100644
>--- a/include/linux/module.h
>+++ b/include/linux/module.h
>@@ -330,6 +330,15 @@ struct mod_kallsyms {
> 	char *strtab;
> };
>
>+#ifdef CONFIG_LIVEPATCH
>+struct klp_modinfo {
>+	Elf_Ehdr hdr;
>+	Elf_Shdr *sechdrs;
>+	char *secstrings;
>+	unsigned int symndx;
>+};
>+#endif
>+
> struct module {
> 	enum module_state state;
>
>@@ -456,7 +465,11 @@ struct module {
> #endif
>
> #ifdef CONFIG_LIVEPATCH
>+	bool klp; /* Is this a livepatch module? */
> 	bool klp_alive;
>+
>+	/* Elf information */
>+	struct klp_modinfo *klp_info;
> #endif
>
> #ifdef CONFIG_MODULE_UNLOAD
>@@ -630,6 +643,18 @@ static inline bool module_requested_async_probing(struct module *module)
> 	return module && module->async_probe_requested;
> }
>
>+#ifdef CONFIG_LIVEPATCH
>+static inline bool is_livepatch_module(struct module *mod)
>+{
>+	return mod->klp;
>+}
>+#else /* !CONFIG_LIVEPATCH */
>+static inline bool is_livepatch_module(struct module *mod)
>+{
>+	return false;
>+}
>+#endif /* CONFIG_LIVEPATCH */
>+
> #else /* !CONFIG_MODULES... */
>
> /* Given an address, look for it in the exception tables. */
>diff --git a/kernel/module.c b/kernel/module.c
>index 87cfeb2..80b7fd9 100644
>--- a/kernel/module.c
>+++ b/kernel/module.c
>@@ -1971,6 +1971,82 @@ static void module_enable_nx(const struct module *mod) { }
> static void module_disable_nx(const struct module *mod) { }
> #endif
>
>+#ifdef CONFIG_LIVEPATCH
>+/*
>+ * Persist Elf information about a module. Copy the Elf header,
>+ * section header table, section string table, and symtab section
>+ * index from info to mod->klp_info.
>+ */
>+static int copy_module_elf(struct module *mod, struct load_info *info)
>+{
>+	unsigned int size, symndx;
>+	int ret;
>+
>+	size = sizeof(*mod->klp_info);
>+	mod->klp_info = kmalloc(size, GFP_KERNEL);
>+	if (mod->klp_info == NULL)
>+		return -ENOMEM;
>+
>+	/* Elf header */
>+	size = sizeof(Elf_Ehdr);
>+	memcpy(&mod->klp_info->hdr, info->hdr, size);
>+
>+	/* Elf section header table */
>+	size = sizeof(Elf_Shdr) * info->hdr->e_shnum;
>+	mod->klp_info->sechdrs = kmalloc(size, GFP_KERNEL);
>+	if (mod->klp_info->sechdrs == NULL) {
>+		ret = -ENOMEM;
>+		goto free_info;
>+	}
>+	memcpy(mod->klp_info->sechdrs, info->sechdrs, size);
>+
>+	/* Elf section name string table */
>+	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
>+	mod->klp_info->secstrings = kmalloc(size, GFP_KERNEL);
>+	if (mod->klp_info->secstrings == NULL) {
>+		ret = -ENOMEM;
>+		goto free_sechdrs;
>+	}
>+	memcpy(mod->klp_info->secstrings, info->secstrings, size);
>+
>+	/* Elf symbol section index */
>+	symndx = info->index.sym;
>+	mod->klp_info->symndx = symndx;
>+
>+	/*
>+	 * For livepatch modules, core_symtab is a complete copy
>+	 * of the original symbol table. Adjust sh_addr to point
>+	 * to core_symtab since the copy of the symtab in module
>+	 * init memory is freed at the end of do_init_module().
>+	 */
>+	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long) mod->core_kallsyms.symtab;
>+
>+	return 0;
>+
>+free_sechdrs:
>+	kfree(mod->klp_info->sechdrs);
>+free_info:
>+	kfree(mod->klp_info);
>+	return ret;
>+}
>+
>+static void free_module_elf(struct module *mod)
>+{
>+	kfree(mod->klp_info->sechdrs);
>+	kfree(mod->klp_info->secstrings);
>+	kfree(mod->klp_info);
>+}
>+#else /* !CONFIG_LIVEPATCH */
>+static int copy_module_elf(struct module *mod, struct load_info *info)
>+{
>+	return 0;
>+}
>+
>+static void free_module_elf(struct module *mod)
>+{
>+}
>+#endif /* CONFIG_LIVEPATCH */
>+
> void __weak module_memfree(void *module_region)
> {
> 	vfree(module_region);
>@@ -2009,6 +2085,9 @@ static void free_module(struct module *mod)
> 	/* Free any allocated parameters. */
> 	destroy_params(mod->kp, mod->num_kp);
>
>+	if (is_livepatch_module(mod))
>+		free_module_elf(mod);
>+
> 	/* Now we can delete it from the lists */
> 	mutex_lock(&module_mutex);
> 	/* Unlink carefully: kallsyms could be walking list. */
>@@ -2124,6 +2203,10 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
> 			       (long)sym[i].st_value);
> 			break;
>
>+		case SHN_LIVEPATCH:
>+			/* Livepatch symbols are resolved by livepatch */
>+			break;
>+
> 		case SHN_UNDEF:
> 			ksym = resolve_symbol_wait(mod, info, name);
> 			/* Ok if resolved.  */
>@@ -2172,6 +2255,10 @@ static int apply_relocations(struct module *mod, const struct load_info *info)
> 		if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
> 			continue;
>
>+		/* Livepatch relocation sections are applied by livepatch */
>+		if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
>+			continue;
>+
> 		if (info->sechdrs[i].sh_type == SHT_REL)
> 			err = apply_relocate(info->sechdrs, info->strtab,
> 					     info->index.sym, i, mod);
>@@ -2467,7 +2554,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
>
> 	/* Compute total space required for the core symbols' strtab. */
> 	for (ndst = i = 0; i < nsrc; i++) {
>-		if (i == 0 ||
>+		if (i == 0 || is_livepatch_module(mod) ||
> 		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> 				   info->index.pcpu)) {
> 			strtab_size += strlen(&info->strtab[src[i].st_name])+1;
>@@ -2526,7 +2613,7 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
> 	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> 	src = mod->kallsyms->symtab;
> 	for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
>-		if (i == 0 ||
>+		if (i == 0 || is_livepatch_module(mod) ||
> 		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> 				   info->index.pcpu)) {
> 			dst[ndst] = src[i];
>@@ -2665,6 +2752,26 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
> 	return 0;
> }
>
>+#ifdef CONFIG_LIVEPATCH
>+static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
>+{
>+	mod->klp = get_modinfo(info, "livepatch") ? true : false;
>+
>+	return 0;
>+}
>+#else /* !CONFIG_LIVEPATCH */
>+static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
>+{
>+	if (get_modinfo(info, "livepatch")) {
>+		pr_err("%s: module is marked as livepatch module, but livepatch support is disabled"
>+		       mod->name);

...And that is why I should have tested the changes with !CONFIG_LIVEPATCH
before sending this out. :-\ The above line should've been (w/ comma and newline):

	pr_err("%s: module is marked as livepatch module, but livepatch support is disabled\n",
		mod->name);

Jessica

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ