diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 7a8a1222c7b1..6137fe32b4b8 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -1313,67 +1313,80 @@ static inline int check_kprobe_rereg(struct kprobe *p) | |||
1313 | return ret; | 1313 | return ret; |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | int __kprobes register_kprobe(struct kprobe *p) | 1316 | static __kprobes int check_kprobe_address_safe(struct kprobe *p, |
1317 | struct module **probed_mod) | ||
1317 | { | 1318 | { |
1318 | int ret = 0; | 1319 | int ret = 0; |
1319 | struct kprobe *old_p; | ||
1320 | struct module *probed_mod; | ||
1321 | kprobe_opcode_t *addr; | ||
1322 | |||
1323 | addr = kprobe_addr(p); | ||
1324 | if (IS_ERR(addr)) | ||
1325 | return PTR_ERR(addr); | ||
1326 | p->addr = addr; | ||
1327 | |||
1328 | ret = check_kprobe_rereg(p); | ||
1329 | if (ret) | ||
1330 | return ret; | ||
1331 | 1320 | ||
1332 | jump_label_lock(); | 1321 | jump_label_lock(); |
1333 | preempt_disable(); | 1322 | preempt_disable(); |
1323 | |||
1324 | /* Ensure it is not in reserved area nor out of text */ | ||
1334 | if (!kernel_text_address((unsigned long) p->addr) || | 1325 | if (!kernel_text_address((unsigned long) p->addr) || |
1335 | in_kprobes_functions((unsigned long) p->addr) || | 1326 | in_kprobes_functions((unsigned long) p->addr) || |
1336 | ftrace_text_reserved(p->addr, p->addr) || | 1327 | ftrace_text_reserved(p->addr, p->addr) || |
1337 | jump_label_text_reserved(p->addr, p->addr)) { | 1328 | jump_label_text_reserved(p->addr, p->addr)) { |
1338 | ret = -EINVAL; | 1329 | ret = -EINVAL; |
1339 | goto cannot_probe; | 1330 | goto out; |
1340 | } | 1331 | } |
1341 | 1332 | ||
1342 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ | 1333 | /* Check if are we probing a module */ |
1343 | p->flags &= KPROBE_FLAG_DISABLED; | 1334 | *probed_mod = __module_text_address((unsigned long) p->addr); |
1344 | 1335 | if (*probed_mod) { | |
1345 | /* | ||
1346 | * Check if are we probing a module. | ||
1347 | */ | ||
1348 | probed_mod = __module_text_address((unsigned long) p->addr); | ||
1349 | if (probed_mod) { | ||
1350 | /* Return -ENOENT if fail. */ | ||
1351 | ret = -ENOENT; | ||
1352 | /* | 1336 | /* |
1353 | * We must hold a refcount of the probed module while updating | 1337 | * We must hold a refcount of the probed module while updating |
1354 | * its code to prohibit unexpected unloading. | 1338 | * its code to prohibit unexpected unloading. |
1355 | */ | 1339 | */ |
1356 | if (unlikely(!try_module_get(probed_mod))) | 1340 | if (unlikely(!try_module_get(*probed_mod))) { |
1357 | goto cannot_probe; | 1341 | ret = -ENOENT; |
1342 | goto out; | ||
1343 | } | ||
1358 | 1344 | ||
1359 | /* | 1345 | /* |
1360 | * If the module freed .init.text, we couldn't insert | 1346 | * If the module freed .init.text, we couldn't insert |
1361 | * kprobes in there. | 1347 | * kprobes in there. |
1362 | */ | 1348 | */ |
1363 | if (within_module_init((unsigned long)p->addr, probed_mod) && | 1349 | if (within_module_init((unsigned long)p->addr, *probed_mod) && |
1364 | probed_mod->state != MODULE_STATE_COMING) { | 1350 | (*probed_mod)->state != MODULE_STATE_COMING) { |
1365 | module_put(probed_mod); | 1351 | module_put(*probed_mod); |
1366 | goto cannot_probe; | 1352 | *probed_mod = NULL; |
1353 | ret = -ENOENT; | ||
1367 | } | 1354 | } |
1368 | /* ret will be updated by following code */ | ||
1369 | } | 1355 | } |
1356 | out: | ||
1370 | preempt_enable(); | 1357 | preempt_enable(); |
1371 | jump_label_unlock(); | 1358 | jump_label_unlock(); |
1372 | 1359 | ||
1360 | return ret; | ||
1361 | } | ||
1362 | |||
1363 | int __kprobes register_kprobe(struct kprobe *p) | ||
1364 | { | ||
1365 | int ret; | ||
1366 | struct kprobe *old_p; | ||
1367 | struct module *probed_mod; | ||
1368 | kprobe_opcode_t *addr; | ||
1369 | |||
1370 | /* Adjust probe address from symbol */ | ||
1371 | addr = kprobe_addr(p); | ||
1372 | if (IS_ERR(addr)) | ||
1373 | return PTR_ERR(addr); | ||
1374 | p->addr = addr; | ||
1375 | |||
1376 | ret = check_kprobe_rereg(p); | ||
1377 | if (ret) | ||
1378 | return ret; | ||
1379 | |||
1380 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ | ||
1381 | p->flags &= KPROBE_FLAG_DISABLED; | ||
1373 | p->nmissed = 0; | 1382 | p->nmissed = 0; |
1374 | INIT_LIST_HEAD(&p->list); | 1383 | INIT_LIST_HEAD(&p->list); |
1375 | mutex_lock(&kprobe_mutex); | ||
1376 | 1384 | ||
1385 | ret = check_kprobe_address_safe(p, &probed_mod); | ||
1386 | if (ret) | ||
1387 | return ret; | ||
1388 | |||
1389 | mutex_lock(&kprobe_mutex); | ||
1377 | jump_label_lock(); /* needed to call jump_label_text_reserved() */ | 1390 | jump_label_lock(); /* needed to call jump_label_text_reserved() */ |
1378 | 1391 | ||
1379 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ | 1392 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ |
@@ -1410,11 +1423,6 @@ out: | |||
1410 | module_put(probed_mod); | 1423 | module_put(probed_mod); |
1411 | 1424 | ||
1412 | return ret; | 1425 | return ret; |
1413 | |||
1414 | cannot_probe: | ||
1415 | preempt_enable(); | ||
1416 | jump_label_unlock(); | ||
1417 | return ret; | ||
1418 | } | 1426 | } |
1419 | EXPORT_SYMBOL_GPL(register_kprobe); | 1427 | EXPORT_SYMBOL_GPL(register_kprobe); |
1420 | 1428 | ||