Fix: Disable IBT around indirect function calls
[lttng-modules.git] / src / wrapper / kallsyms.c
CommitLineData
a6576540
MD
1/* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only)
2 *
3 * wrapper/kallsyms.c
4 *
5 * Wrapper around kallsyms. Using kprobes to get its address when available.
6 *
7 * Can we mainline LTTng already so we don't have to waste our time doing this
8 * kind of hack ?
9 *
10 * Copyright (C) 2020 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
11 */
12
13#include <linux/kprobes.h>
14#include <linux/module.h>
15#include <wrapper/kallsyms.h>
16
5f4c791e 17#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,7,0))
a6576540
MD
18
19#ifndef CONFIG_KPROBES
20# error "LTTng-modules requires CONFIG_KPROBES on kernels >= 5.7.0"
21#endif
22
23static
24unsigned long (*kallsyms_lookup_name_sym)(const char *name);
25
26static
27int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs)
28{
29 return 0;
30}
31
b4a626cb 32#ifdef LTTNG_CONFIG_PPC64_ELF_ABI_V2
a6576540 33static
b4a626cb 34void kallsyms_pre_arch_adjust(struct kprobe *probe)
a6576540 35{
67c5ffca
HZ
36 /*
37 * With powerpc64 ABIv2, we need the global entry point of
38 * kallsyms_lookup_name to call it later, while kprobe_register would
39 * automatically adjust the global entry point to the local entry point,
40 * when a kprobe was registered at a function entry. So we add 4 bytes
41 * which is the length of one instruction to kallsyms_lookup_name to
42 * avoid the adjustment.
43 */
b4a626cb
MD
44 probe->offset = 4;
45}
46#else
47static
48void kallsyms_pre_arch_adjust(struct kprobe *probe)
49{
50}
67c5ffca 51#endif
b4a626cb 52
47af6022 53#ifdef LTTNG_CONFIG_PPC64_ELF_ABI_V2
b4a626cb
MD
54static
55unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe)
56{
67c5ffca 57 /* Substract 4 bytes to get what we originally want */
b4a626cb
MD
58 return (unsigned long)(((char *)probe->addr) - 4);
59}
60
a1f1ecf4 61#elif defined(LTTNG_CONFIG_PPC64_ELF_ABI_V1)
b4a626cb
MD
62# if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,18,0))
63# include <asm/elf.h>
64# define LTTNG_FUNC_DESC_TYPE struct func_desc
65# define LTTNG_FUNC_DESC_ADDR_NAME addr
66# else
67# include <asm/types.h>
68# define LTTNG_FUNC_DESC_TYPE func_descr_t
69# define LTTNG_FUNC_DESC_ADDR_NAME entry
70
71static
72LTTNG_FUNC_DESC_TYPE kallsyms_lookup_name_func_desc;
73# endif
74
75static
76unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe)
77{
a1f1ecf4
MJ
78 /*
79 * Build a function descriptor from the address of
80 * 'kallsyms_lookup_name' returned by kprobe and the toc of
81 * 'sprint_symbol' which is in the same compile unit and exported. I
82 * hate this on so many levels but it works.
83 */
84 kallsyms_lookup_name_func_desc.LTTNG_FUNC_DESC_ADDR_NAME = (unsigned long) probe.addr;
85 kallsyms_lookup_name_func_desc.toc = ((LTTNG_FUNC_DESC_TYPE *) &sprint_symbol)->toc;
b4a626cb
MD
86 return (unsigned long) &kallsyms_lookup_name_func_desc;
87}
88#elif defined(CONFIG_ARM) && defined(CONFIG_THUMB2_KERNEL)
89static
90unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe)
91{
92 unsigned long addr = (unsigned long)probe->addr;
93
a6576540
MD
94 if (addr)
95 addr |= 1; /* set bit 0 in address for thumb mode */
b4a626cb
MD
96 return addr;
97}
98#else
99static
100unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe)
101{
102 return (unsigned long)probe->addr;
103}
a6576540 104#endif
b4a626cb
MD
105
106static
107unsigned long do_get_kallsyms(void)
108{
109 struct kprobe probe;
110 int ret;
111 unsigned long addr;
112
113 memset(&probe, 0, sizeof(probe));
114 probe.pre_handler = dummy_kprobe_handler;
115 probe.symbol_name = "kallsyms_lookup_name";
116 kallsyms_pre_arch_adjust(&probe);
117 ret = register_kprobe(&probe);
118 if (ret)
119 return 0;
120 addr = kallsyms_get_arch_call_addr(&probe);
a6576540
MD
121 unregister_kprobe(&probe);
122 return addr;
123}
124
125unsigned long wrapper_kallsyms_lookup_name(const char *name)
126{
127 if (!kallsyms_lookup_name_sym) {
128 kallsyms_lookup_name_sym = (void *)do_get_kallsyms();
129 }
92e2c5fe
MD
130 if (kallsyms_lookup_name_sym) {
131 struct irq_ibt_state irq_ibt_state;
132 unsigned long ret;
133
134 irq_ibt_state = wrapper_irq_ibt_save();
135 ret = kallsyms_lookup_name_sym(name);
136 wrapper_irq_ibt_restore(irq_ibt_state);
137 return ret;
138 } else {
5a15f70c 139 printk_once(KERN_WARNING "LTTng: requires kallsyms_lookup_name\n");
a6576540
MD
140 return 0;
141 }
142}
143EXPORT_SYMBOL_GPL(wrapper_kallsyms_lookup_name);
144
145#endif
612ddfa1 146
95b4bc7d 147#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,4,0) && defined(CONFIG_ANDROID))
612ddfa1
L
148MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
149#endif
This page took 0.05469 seconds and 4 git commands to generate.