diff options
Diffstat (limited to 'kernel/kprobes.c')
| -rw-r--r-- | kernel/kprobes.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 77981813a1e7..b30fd54eb985 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -1255,19 +1255,29 @@ static int __kprobes in_kprobes_functions(unsigned long addr) | |||
| 1255 | /* | 1255 | /* |
| 1256 | * If we have a symbol_name argument, look it up and add the offset field | 1256 | * If we have a symbol_name argument, look it up and add the offset field |
| 1257 | * to it. This way, we can specify a relative address to a symbol. | 1257 | * to it. This way, we can specify a relative address to a symbol. |
| 1258 | * This returns encoded errors if it fails to look up symbol or invalid | ||
| 1259 | * combination of parameters. | ||
| 1258 | */ | 1260 | */ |
| 1259 | static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) | 1261 | static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) |
| 1260 | { | 1262 | { |
| 1261 | kprobe_opcode_t *addr = p->addr; | 1263 | kprobe_opcode_t *addr = p->addr; |
| 1264 | |||
| 1265 | if ((p->symbol_name && p->addr) || | ||
| 1266 | (!p->symbol_name && !p->addr)) | ||
| 1267 | goto invalid; | ||
| 1268 | |||
| 1262 | if (p->symbol_name) { | 1269 | if (p->symbol_name) { |
| 1263 | if (addr) | ||
| 1264 | return NULL; | ||
| 1265 | kprobe_lookup_name(p->symbol_name, addr); | 1270 | kprobe_lookup_name(p->symbol_name, addr); |
| 1271 | if (!addr) | ||
| 1272 | return ERR_PTR(-ENOENT); | ||
| 1266 | } | 1273 | } |
| 1267 | 1274 | ||
| 1268 | if (!addr) | 1275 | addr = (kprobe_opcode_t *)(((char *)addr) + p->offset); |
| 1269 | return NULL; | 1276 | if (addr) |
| 1270 | return (kprobe_opcode_t *)(((char *)addr) + p->offset); | 1277 | return addr; |
| 1278 | |||
| 1279 | invalid: | ||
| 1280 | return ERR_PTR(-EINVAL); | ||
| 1271 | } | 1281 | } |
| 1272 | 1282 | ||
| 1273 | /* Check passed kprobe is valid and return kprobe in kprobe_table. */ | 1283 | /* Check passed kprobe is valid and return kprobe in kprobe_table. */ |
| @@ -1311,8 +1321,8 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1311 | kprobe_opcode_t *addr; | 1321 | kprobe_opcode_t *addr; |
| 1312 | 1322 | ||
| 1313 | addr = kprobe_addr(p); | 1323 | addr = kprobe_addr(p); |
| 1314 | if (!addr) | 1324 | if (IS_ERR(addr)) |
| 1315 | return -EINVAL; | 1325 | return PTR_ERR(addr); |
| 1316 | p->addr = addr; | 1326 | p->addr = addr; |
| 1317 | 1327 | ||
| 1318 | ret = check_kprobe_rereg(p); | 1328 | ret = check_kprobe_rereg(p); |
| @@ -1335,6 +1345,8 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1335 | */ | 1345 | */ |
| 1336 | probed_mod = __module_text_address((unsigned long) p->addr); | 1346 | probed_mod = __module_text_address((unsigned long) p->addr); |
| 1337 | if (probed_mod) { | 1347 | if (probed_mod) { |
| 1348 | /* Return -ENOENT if fail. */ | ||
| 1349 | ret = -ENOENT; | ||
| 1338 | /* | 1350 | /* |
| 1339 | * We must hold a refcount of the probed module while updating | 1351 | * We must hold a refcount of the probed module while updating |
| 1340 | * its code to prohibit unexpected unloading. | 1352 | * its code to prohibit unexpected unloading. |
| @@ -1351,6 +1363,7 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1351 | module_put(probed_mod); | 1363 | module_put(probed_mod); |
| 1352 | goto fail_with_jump_label; | 1364 | goto fail_with_jump_label; |
| 1353 | } | 1365 | } |
| 1366 | /* ret will be updated by following code */ | ||
| 1354 | } | 1367 | } |
| 1355 | preempt_enable(); | 1368 | preempt_enable(); |
| 1356 | jump_label_unlock(); | 1369 | jump_label_unlock(); |
| @@ -1399,7 +1412,7 @@ out: | |||
| 1399 | fail_with_jump_label: | 1412 | fail_with_jump_label: |
| 1400 | preempt_enable(); | 1413 | preempt_enable(); |
| 1401 | jump_label_unlock(); | 1414 | jump_label_unlock(); |
| 1402 | return -EINVAL; | 1415 | return ret; |
| 1403 | } | 1416 | } |
| 1404 | EXPORT_SYMBOL_GPL(register_kprobe); | 1417 | EXPORT_SYMBOL_GPL(register_kprobe); |
| 1405 | 1418 | ||
| @@ -1686,8 +1699,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
| 1686 | 1699 | ||
| 1687 | if (kretprobe_blacklist_size) { | 1700 | if (kretprobe_blacklist_size) { |
| 1688 | addr = kprobe_addr(&rp->kp); | 1701 | addr = kprobe_addr(&rp->kp); |
| 1689 | if (!addr) | 1702 | if (IS_ERR(addr)) |
| 1690 | return -EINVAL; | 1703 | return PTR_ERR(addr); |
| 1691 | 1704 | ||
| 1692 | for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { | 1705 | for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { |
| 1693 | if (kretprobe_blacklist[i].addr == addr) | 1706 | if (kretprobe_blacklist[i].addr == addr) |
