Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Stange <nstange@suse.de>2018-08-08 15:08:00 +0200
committerMiroslav Benes <mbenes@suse.cz>2018-08-09 15:29:29 +0200
commitbd113d8b6ae8a9d5bb463256923026051ee2697a (patch)
tree346b04db86c93ad6dcaa252069c2be14684ff8ef
parentd8d2d5918d37d2d48a4ae8cd8142988888f9abf5 (diff)
Provide common kallsyms wrapper API
With bsc#1103203, the need for disambiguating between a multiply defined symbol arose. This is something the kallsyms_lookup_name() based code snippet we used to copy&paste to every individual CVE fix can't handle. Implement a proper wrapper API for doing the kallsyms lookups. Signed-off-by: Nicolai Stange <nstange@suse.de> Signed-off-by: Miroslav Benes <mbenes@suse.cz>
-rw-r--r--kallsyms_relocs.c125
-rw-r--r--kallsyms_relocs.h15
-rw-r--r--rpm/kernel-livepatch.spec4
-rwxr-xr-xscripts/register-patches.sh4
-rwxr-xr-xscripts/tar-up.sh2
5 files changed, 148 insertions, 2 deletions
diff --git a/kallsyms_relocs.c b/kallsyms_relocs.c
new file mode 100644
index 0000000..5347af0
--- /dev/null
+++ b/kallsyms_relocs.c
@@ -0,0 +1,125 @@
+/*
+ * kallsyms_relocs.c - resolve non-exported symbols
+ *
+ * Copyright (C) 2018 SUSE
+ * Author: Nicolai Stange <nstange@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include "kallsyms_relocs.h"
+
+struct find_args
+{
+ struct klp_kallsyms_reloc reloc;
+ unsigned long match_count;
+};
+
+static int __find_callback(void *data, const char *name,
+ struct module *mod, unsigned long addr)
+{
+ struct find_args *args = data;
+
+ if ((mod && !args->reloc.objname) || (!mod && args->reloc.objname))
+ return 0;
+
+ if (strcmp(args->reloc.symname, name))
+ return 0;
+
+ if (args->reloc.objname && strcmp(args->reloc.objname, mod->name))
+ return 0;
+
+ args->match_count++;
+
+ /*
+ * Finish the search when the symbol is found for the desired
+ * position or the position is not defined.
+ */
+ if (!args->reloc.sympos || args->match_count == args->reloc.sympos) {
+ *args->reloc.addr = (void *)addr;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int (*klp_module_kallsyms_on_each_symbol)(int (*fn)(void *, const char *,
+ struct module *,
+ unsigned long),
+ void *data);
+
+/* Bootstrap: resolve non-exported module_kallsyms_on_each_symbol() */
+static int __kallsyms_relocs_init(void)
+{
+ const char symname[] = "module_kallsyms_on_each_symbol";
+
+ if (klp_module_kallsyms_on_each_symbol)
+ return 0;
+
+ klp_module_kallsyms_on_each_symbol =
+ (void *)kallsyms_lookup_name(symname);
+
+ if (!klp_module_kallsyms_on_each_symbol) {
+ pr_err("livepatch: symbol %s not resolved\n", symname);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+/*
+ * Must be called with module_mutex held if any of the relocs'
+ * ->objname can be non-NULL.
+ */
+int __klp_resolve_kallsyms_relocs(struct klp_kallsyms_reloc *relocs,
+ unsigned long count)
+{
+ int ret;
+ unsigned long i;
+ struct find_args args;
+
+ ret = __kallsyms_relocs_init();
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; ++i) {
+ *relocs[i].addr = NULL;
+ args.reloc = relocs[i];
+ args.match_count = 0;
+
+ if (args.reloc.objname) {
+ klp_module_kallsyms_on_each_symbol(__find_callback,
+ &args);
+ } else {
+ kallsyms_on_each_symbol(__find_callback, &args);
+ }
+
+ if (!*relocs[i].addr) {
+ if (relocs[i].objname) {
+ pr_err("livepatch: symbol %s:%s not resolved\n",
+ relocs[i].objname, relocs[i].symname);
+ } else {
+ pr_err("livepatch: symbol %s not resolved\n",
+ relocs[i].symname);
+ }
+
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
diff --git a/kallsyms_relocs.h b/kallsyms_relocs.h
new file mode 100644
index 0000000..87ae4f5
--- /dev/null
+++ b/kallsyms_relocs.h
@@ -0,0 +1,15 @@
+#ifndef _KLP_KALLSYMS_RELOCS
+#define _KLP_KALLSYMS_RELOCS
+
+struct klp_kallsyms_reloc
+{
+ const char *symname;
+ void **addr;
+ const char *objname;
+ unsigned long sympos;
+};
+
+int __klp_resolve_kallsyms_relocs(struct klp_kallsyms_reloc *relocs,
+ unsigned long count);
+
+#endif /* _KLP_KALLSYMS_RELOCS */
diff --git a/rpm/kernel-livepatch.spec b/rpm/kernel-livepatch.spec
index 5638494..11efeb9 100644
--- a/rpm/kernel-livepatch.spec
+++ b/rpm/kernel-livepatch.spec
@@ -30,6 +30,8 @@ Source2: livepatch_main.c
Source3: config.sh
Source4: source-timestamp
Source5: shadow.h
+Source6: kallsyms_relocs.h
+Source7: kallsyms_relocs.c
@@KLP_PATCHES_SOURCES@@
BuildRequires: kernel-syms kernel-livepatch-tools-devel libelf-devel
ExclusiveArch: ppc64le x86_64
@@ -45,6 +47,8 @@ This is a live patch for SUSE Linux Enterprise Server kernel.
@@KLP_PATCHES_SETUP_SOURCES@@
cp %_sourcedir/livepatch_main.c .
cp %_sourcedir/shadow.h .
+cp %_sourcedir/kallsyms_relocs.h .
+cp %_sourcedir/kallsyms_relocs.c .
cp %_sourcedir/Makefile .
%build
diff --git a/scripts/register-patches.sh b/scripts/register-patches.sh
index 42b56d7..1a53baa 100755
--- a/scripts/register-patches.sh
+++ b/scripts/register-patches.sh
@@ -264,8 +264,8 @@ EOF
# Finish kernel-livepatch.spec:
## Enumerate the per subpatch source *.tar.bz2.
-## Note: Start with Source5
-S=6
+## Note: Start with Source8
+S=8
## First check that none of the to be occupied Source<n> slots has
## been used already.
for i in "${!livepatches[@]}"; do
diff --git a/scripts/tar-up.sh b/scripts/tar-up.sh
index e5d3762..92fe7b4 100755
--- a/scripts/tar-up.sh
+++ b/scripts/tar-up.sh
@@ -74,6 +74,8 @@ source $(dirname $0)/release-version.sh
install -m 644 livepatch_main.c $build_dir
install -m 644 shadow.h $build_dir
+install -m 644 kallsyms_relocs.h $build_dir
+install -m 644 kallsyms_relocs.c $build_dir
install -m 644 rpm/kernel-livepatch.spec $build_dir/kernel-livepatch-"$RELEASE".spec
scripts/register-patches.sh $build_dir/livepatch_main.c $build_dir/kernel-livepatch-"$RELEASE".spec
install -m 644 rpm/config.sh $build_dir/config.sh