aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r--kernel/livepatch/core.c84
1 files changed, 19 insertions, 65 deletions
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 }