aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris J Arges <chris.j.arges@canonical.com>2015-12-01 21:40:55 -0500
committerJiri Kosina <jkosina@suse.cz>2015-12-03 17:01:27 -0500
commit064c89df6247cd829a7880cc8a87b7ed2cdfccd8 (patch)
tree6122ff8685f8ec44fea809709293d9f27e1f4f0d
parentb2b018ef48675a9a524fa9791ea7d67fdac405f7 (diff)
livepatch: add sympos as disambiguator field to klp_reloc
In cases of duplicate symbols, sympos will be used to disambiguate instead of val. By default sympos will be 0, and patching will only succeed if the symbol is unique. Specifying a positive value will ensure that occurrence of the symbol in kallsyms for the patched object will be used for patching if it is valid. For external relocations sympos is not supported. Remove klp_verify_callback, klp_verify_args and klp_verify_vmlinux_symbol as they are no longer used. From the klp_reloc structure remove val, as it can be refactored as a local variable in klp_write_object_relocations. Signed-off-by: Chris J Arges <chris.j.arges@canonical.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--include/linux/livepatch.h5
-rw-r--r--kernel/livepatch/core.c84
2 files changed, 21 insertions, 68 deletions
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index b60e8abab0ab..a8828652f794 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -67,8 +67,7 @@ struct klp_func {
67/** 67/**
68 * struct klp_reloc - relocation structure for live patching 68 * struct klp_reloc - relocation structure for live patching
69 * @loc: address where the relocation will be written 69 * @loc: address where the relocation will be written
70 * @val: address of the referenced symbol (optional, 70 * @sympos: position in kallsyms to disambiguate symbols (optional)
71 * vmlinux patches only)
72 * @type: ELF relocation type 71 * @type: ELF relocation type
73 * @name: name of the referenced symbol (for lookup/verification) 72 * @name: name of the referenced symbol (for lookup/verification)
74 * @addend: offset from the referenced symbol 73 * @addend: offset from the referenced symbol
@@ -76,7 +75,7 @@ struct klp_func {
76 */ 75 */
77struct klp_reloc { 76struct klp_reloc {
78 unsigned long loc; 77 unsigned long loc;
79 unsigned long val; 78 unsigned long sympos;
80 unsigned long type; 79 unsigned long type;
81 const char *name; 80 const char *name;
82 int addend; 81 int addend;
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index e416f96e938d..e842534d3493 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -203,45 +203,6 @@ static int klp_find_object_symbol(const char *objname, const char *name,
203 return -EINVAL; 203 return -EINVAL;
204} 204}
205 205
206struct klp_verify_args {
207 const char *name;
208 const unsigned long addr;
209};
210
211static int klp_verify_callback(void *data, const char *name,
212 struct module *mod, unsigned long addr)
213{
214 struct klp_verify_args *args = data;
215
216 if (!mod &&
217 !strcmp(args->name, name) &&
218 args->addr == addr)
219 return 1;
220
221 return 0;
222}
223
224static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr)
225{
226 struct klp_verify_args args = {
227 .name = name,
228 .addr = addr,
229 };
230 int ret;
231
232 mutex_lock(&module_mutex);
233 ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
234 mutex_unlock(&module_mutex);
235
236 if (!ret) {
237 pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
238 name, addr);
239 return -EINVAL;
240 }
241
242 return 0;
243}
244
245/* 206/*
246 * external symbols are located outside the parent object (where the parent 207 * external symbols are located outside the parent object (where the parent
247 * object is either vmlinux or the kmod being patched). 208 * object is either vmlinux or the kmod being patched).
@@ -272,6 +233,7 @@ static int klp_write_object_relocations(struct module *pmod,
272 struct klp_object *obj) 233 struct klp_object *obj)
273{ 234{
274 int ret; 235 int ret;
236 unsigned long val;
275 struct klp_reloc *reloc; 237 struct klp_reloc *reloc;
276 238
277 if (WARN_ON(!klp_is_object_loaded(obj))) 239 if (WARN_ON(!klp_is_object_loaded(obj)))
@@ -281,35 +243,27 @@ static int klp_write_object_relocations(struct module *pmod,
281 return -EINVAL; 243 return -EINVAL;
282 244
283 for (reloc = obj->relocs; reloc->name; reloc++) { 245 for (reloc = obj->relocs; reloc->name; reloc++) {
284 if (!klp_is_module(obj)) { 246 /* discover the address of the referenced symbol */
285 247 if (reloc->external) {
286#if defined(CONFIG_RANDOMIZE_BASE) 248 if (reloc->sympos > 0) {
287 /* If KASLR has been enabled, adjust old value accordingly */ 249 pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n",
288 if (kaslr_enabled()) 250 reloc->name);
289 reloc->val += kaslr_offset(); 251 return -EINVAL;
290#endif 252 }
291 ret = klp_verify_vmlinux_symbol(reloc->name, 253 ret = klp_find_external_symbol(pmod, reloc->name, &val);
292 reloc->val); 254 } else
293 if (ret) 255 ret = klp_find_object_symbol(obj->name,
294 return ret; 256 reloc->name,
295 } else { 257 reloc->sympos,
296 /* module, reloc->val needs to be discovered */ 258 &val);
297 if (reloc->external) 259 if (ret)
298 ret = klp_find_external_symbol(pmod, 260 return ret;
299 reloc->name, 261
300 &reloc->val);
301 else
302 ret = klp_find_object_symbol(obj->mod->name,
303 reloc->name,
304 0, &reloc->val);
305 if (ret)
306 return ret;
307 }
308 ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc, 262 ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc,
309 reloc->val + reloc->addend); 263 val + reloc->addend);
310 if (ret) { 264 if (ret) {
311 pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n", 265 pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n",
312 reloc->name, reloc->val, ret); 266 reloc->name, val, ret);
313 return ret; 267 return ret;
314 } 268 }
315 } 269 }