diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 100 |
1 files changed, 52 insertions, 48 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5b5ac76671e7..5ffc6875d2a7 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -86,18 +86,8 @@ static raw_spinlock_t *kretprobe_table_lock_ptr(unsigned long hash) | |||
86 | return &(kretprobe_table_locks[hash].lock); | 86 | return &(kretprobe_table_locks[hash].lock); |
87 | } | 87 | } |
88 | 88 | ||
89 | /* | 89 | /* Blacklist -- list of struct kprobe_blacklist_entry */ |
90 | * Normally, functions that we'd want to prohibit kprobes in, are marked | 90 | static LIST_HEAD(kprobe_blacklist); |
91 | * __kprobes. But, there are cases where such functions already belong to | ||
92 | * a different section (__sched for preempt_schedule) | ||
93 | * | ||
94 | * For such cases, we now have a blacklist | ||
95 | */ | ||
96 | static struct kprobe_blackpoint kprobe_blacklist[] = { | ||
97 | {"preempt_schedule",}, | ||
98 | {"native_get_debugreg",}, | ||
99 | {NULL} /* Terminator */ | ||
100 | }; | ||
101 | 91 | ||
102 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT | 92 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT |
103 | /* | 93 | /* |
@@ -1328,24 +1318,22 @@ bool __weak arch_within_kprobe_blacklist(unsigned long addr) | |||
1328 | addr < (unsigned long)__kprobes_text_end; | 1318 | addr < (unsigned long)__kprobes_text_end; |
1329 | } | 1319 | } |
1330 | 1320 | ||
1331 | static int __kprobes in_kprobes_functions(unsigned long addr) | 1321 | static bool __kprobes within_kprobe_blacklist(unsigned long addr) |
1332 | { | 1322 | { |
1333 | struct kprobe_blackpoint *kb; | 1323 | struct kprobe_blacklist_entry *ent; |
1334 | 1324 | ||
1335 | if (arch_within_kprobe_blacklist(addr)) | 1325 | if (arch_within_kprobe_blacklist(addr)) |
1336 | return -EINVAL; | 1326 | return true; |
1337 | /* | 1327 | /* |
1338 | * If there exists a kprobe_blacklist, verify and | 1328 | * If there exists a kprobe_blacklist, verify and |
1339 | * fail any probe registration in the prohibited area | 1329 | * fail any probe registration in the prohibited area |
1340 | */ | 1330 | */ |
1341 | for (kb = kprobe_blacklist; kb->name != NULL; kb++) { | 1331 | list_for_each_entry(ent, &kprobe_blacklist, list) { |
1342 | if (kb->start_addr) { | 1332 | if (addr >= ent->start_addr && addr < ent->end_addr) |
1343 | if (addr >= kb->start_addr && | 1333 | return true; |
1344 | addr < (kb->start_addr + kb->range)) | ||
1345 | return -EINVAL; | ||
1346 | } | ||
1347 | } | 1334 | } |
1348 | return 0; | 1335 | |
1336 | return false; | ||
1349 | } | 1337 | } |
1350 | 1338 | ||
1351 | /* | 1339 | /* |
@@ -1436,7 +1424,7 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p, | |||
1436 | 1424 | ||
1437 | /* Ensure it is not in reserved area nor out of text */ | 1425 | /* Ensure it is not in reserved area nor out of text */ |
1438 | if (!kernel_text_address((unsigned long) p->addr) || | 1426 | if (!kernel_text_address((unsigned long) p->addr) || |
1439 | in_kprobes_functions((unsigned long) p->addr) || | 1427 | within_kprobe_blacklist((unsigned long) p->addr) || |
1440 | jump_label_text_reserved(p->addr, p->addr)) { | 1428 | jump_label_text_reserved(p->addr, p->addr)) { |
1441 | ret = -EINVAL; | 1429 | ret = -EINVAL; |
1442 | goto out; | 1430 | goto out; |
@@ -2022,6 +2010,38 @@ void __kprobes dump_kprobe(struct kprobe *kp) | |||
2022 | kp->symbol_name, kp->addr, kp->offset); | 2010 | kp->symbol_name, kp->addr, kp->offset); |
2023 | } | 2011 | } |
2024 | 2012 | ||
2013 | /* | ||
2014 | * Lookup and populate the kprobe_blacklist. | ||
2015 | * | ||
2016 | * Unlike the kretprobe blacklist, we'll need to determine | ||
2017 | * the range of addresses that belong to the said functions, | ||
2018 | * since a kprobe need not necessarily be at the beginning | ||
2019 | * of a function. | ||
2020 | */ | ||
2021 | static int __init populate_kprobe_blacklist(unsigned long *start, | ||
2022 | unsigned long *end) | ||
2023 | { | ||
2024 | unsigned long *iter; | ||
2025 | struct kprobe_blacklist_entry *ent; | ||
2026 | unsigned long offset = 0, size = 0; | ||
2027 | |||
2028 | for (iter = start; iter < end; iter++) { | ||
2029 | if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) { | ||
2030 | pr_err("Failed to find blacklist %p\n", (void *)*iter); | ||
2031 | continue; | ||
2032 | } | ||
2033 | |||
2034 | ent = kmalloc(sizeof(*ent), GFP_KERNEL); | ||
2035 | if (!ent) | ||
2036 | return -ENOMEM; | ||
2037 | ent->start_addr = *iter; | ||
2038 | ent->end_addr = *iter + size; | ||
2039 | INIT_LIST_HEAD(&ent->list); | ||
2040 | list_add_tail(&ent->list, &kprobe_blacklist); | ||
2041 | } | ||
2042 | return 0; | ||
2043 | } | ||
2044 | |||
2025 | /* Module notifier call back, checking kprobes on the module */ | 2045 | /* Module notifier call back, checking kprobes on the module */ |
2026 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, | 2046 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, |
2027 | unsigned long val, void *data) | 2047 | unsigned long val, void *data) |
@@ -2065,14 +2085,13 @@ static struct notifier_block kprobe_module_nb = { | |||
2065 | .priority = 0 | 2085 | .priority = 0 |
2066 | }; | 2086 | }; |
2067 | 2087 | ||
2088 | /* Markers of _kprobe_blacklist section */ | ||
2089 | extern unsigned long __start_kprobe_blacklist[]; | ||
2090 | extern unsigned long __stop_kprobe_blacklist[]; | ||
2091 | |||
2068 | static int __init init_kprobes(void) | 2092 | static int __init init_kprobes(void) |
2069 | { | 2093 | { |
2070 | int i, err = 0; | 2094 | int i, err = 0; |
2071 | unsigned long offset = 0, size = 0; | ||
2072 | char *modname, namebuf[KSYM_NAME_LEN]; | ||
2073 | const char *symbol_name; | ||
2074 | void *addr; | ||
2075 | struct kprobe_blackpoint *kb; | ||
2076 | 2095 | ||
2077 | /* FIXME allocate the probe table, currently defined statically */ | 2096 | /* FIXME allocate the probe table, currently defined statically */ |
2078 | /* initialize all list heads */ | 2097 | /* initialize all list heads */ |
@@ -2082,26 +2101,11 @@ static int __init init_kprobes(void) | |||
2082 | raw_spin_lock_init(&(kretprobe_table_locks[i].lock)); | 2101 | raw_spin_lock_init(&(kretprobe_table_locks[i].lock)); |
2083 | } | 2102 | } |
2084 | 2103 | ||
2085 | /* | 2104 | err = populate_kprobe_blacklist(__start_kprobe_blacklist, |
2086 | * Lookup and populate the kprobe_blacklist. | 2105 | __stop_kprobe_blacklist); |
2087 | * | 2106 | if (err) { |
2088 | * Unlike the kretprobe blacklist, we'll need to determine | 2107 | pr_err("kprobes: failed to populate blacklist: %d\n", err); |
2089 | * the range of addresses that belong to the said functions, | 2108 | pr_err("Please take care of using kprobes.\n"); |
2090 | * since a kprobe need not necessarily be at the beginning | ||
2091 | * of a function. | ||
2092 | */ | ||
2093 | for (kb = kprobe_blacklist; kb->name != NULL; kb++) { | ||
2094 | kprobe_lookup_name(kb->name, addr); | ||
2095 | if (!addr) | ||
2096 | continue; | ||
2097 | |||
2098 | kb->start_addr = (unsigned long)addr; | ||
2099 | symbol_name = kallsyms_lookup(kb->start_addr, | ||
2100 | &size, &offset, &modname, namebuf); | ||
2101 | if (!symbol_name) | ||
2102 | kb->range = 0; | ||
2103 | else | ||
2104 | kb->range = size; | ||
2105 | } | 2109 | } |
2106 | 2110 | ||
2107 | if (kretprobe_blacklist_size) { | 2111 | if (kretprobe_blacklist_size) { |