diff options
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r-- | kernel/livepatch/core.c | 84 |
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 | ||
206 | struct klp_verify_args { | ||
207 | const char *name; | ||
208 | const unsigned long addr; | ||
209 | }; | ||
210 | |||
211 | static 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 | |||
224 | static 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 | } |