| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | Generic support for BUG() |
| 4 | |
| 5 | This respects the following config options: |
| 6 | |
| 7 | CONFIG_BUG - emit BUG traps. Nothing happens without this. |
| 8 | CONFIG_GENERIC_BUG - enable this code. |
| 9 | CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit relative pointers for bug_addr and file |
| 10 | CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG |
| 11 | |
| 12 | CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable |
| 13 | (though they're generally always on). |
| 14 | |
| 15 | CONFIG_GENERIC_BUG is set by each architecture using this code. |
| 16 | |
| 17 | To use this, your architecture must: |
| 18 | |
| 19 | 1. Set up the config options: |
| 20 | - Enable CONFIG_GENERIC_BUG if CONFIG_BUG |
| 21 | |
| 22 | 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON) |
| 23 | - Define HAVE_ARCH_BUG |
| 24 | - Implement BUG() to generate a faulting instruction |
| 25 | - NOTE: struct bug_entry does not have "file" or "line" entries |
| 26 | when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate |
| 27 | the values accordingly. |
| 28 | |
| 29 | 3. Implement the trap |
| 30 | - In the illegal instruction trap handler (typically), verify |
| 31 | that the fault was in kernel mode, and call report_bug() |
| 32 | - report_bug() will return whether it was a false alarm, a warning, |
| 33 | or an actual bug. |
| 34 | - You must implement the is_valid_bugaddr(bugaddr) callback which |
| 35 | returns true if the eip is a real kernel address, and it points |
| 36 | to the expected BUG trap instruction. |
| 37 | |
| 38 | Jeremy Fitzhardinge <jeremy@goop.org> 2006 |
| 39 | */ |
| 40 | |
| 41 | #define pr_fmt(fmt) fmt |
| 42 | |
| 43 | #include <linux/list.h> |
| 44 | #include <linux/module.h> |
| 45 | #include <linux/kernel.h> |
| 46 | #include <linux/bug.h> |
| 47 | #include <linux/sched.h> |
| 48 | #include <linux/rculist.h> |
| 49 | #include <linux/ftrace.h> |
| 50 | #include <linux/context_tracking.h> |
| 51 | |
| 52 | extern struct bug_entry __start___bug_table[], __stop___bug_table[]; |
| 53 | |
| 54 | static inline unsigned long bug_addr(const struct bug_entry *bug) |
| 55 | { |
| 56 | #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS |
| 57 | return (unsigned long)&bug->bug_addr_disp + bug->bug_addr_disp; |
| 58 | #else |
| 59 | return bug->bug_addr; |
| 60 | #endif |
| 61 | } |
| 62 | |
| 63 | #ifdef CONFIG_MODULES |
| 64 | /* Updates are protected by module mutex */ |
| 65 | static LIST_HEAD(module_bug_list); |
| 66 | |
| 67 | static struct bug_entry *module_find_bug(unsigned long bugaddr) |
| 68 | { |
| 69 | struct bug_entry *bug; |
| 70 | struct module *mod; |
| 71 | |
| 72 | guard(rcu)(); |
| 73 | list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { |
| 74 | unsigned i; |
| 75 | |
| 76 | bug = mod->bug_table; |
| 77 | for (i = 0; i < mod->num_bugs; ++i, ++bug) |
| 78 | if (bugaddr == bug_addr(bug)) |
| 79 | return bug; |
| 80 | } |
| 81 | return NULL; |
| 82 | } |
| 83 | |
| 84 | void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, |
| 85 | struct module *mod) |
| 86 | { |
| 87 | char *secstrings; |
| 88 | unsigned int i; |
| 89 | |
| 90 | mod->bug_table = NULL; |
| 91 | mod->num_bugs = 0; |
| 92 | |
| 93 | /* Find the __bug_table section, if present */ |
| 94 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
| 95 | for (i = 1; i < hdr->e_shnum; i++) { |
| 96 | if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table" )) |
| 97 | continue; |
| 98 | mod->bug_table = (void *) sechdrs[i].sh_addr; |
| 99 | mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); |
| 100 | break; |
| 101 | } |
| 102 | |
| 103 | /* |
| 104 | * Strictly speaking this should have a spinlock to protect against |
| 105 | * traversals, but since we only traverse on BUG()s, a spinlock |
| 106 | * could potentially lead to deadlock and thus be counter-productive. |
| 107 | * Thus, this uses RCU to safely manipulate the bug list, since BUG |
| 108 | * must run in non-interruptive state. |
| 109 | */ |
| 110 | list_add_rcu(new: &mod->bug_list, head: &module_bug_list); |
| 111 | } |
| 112 | |
| 113 | void module_bug_cleanup(struct module *mod) |
| 114 | { |
| 115 | list_del_rcu(entry: &mod->bug_list); |
| 116 | } |
| 117 | |
| 118 | #else |
| 119 | |
| 120 | static inline struct bug_entry *module_find_bug(unsigned long bugaddr) |
| 121 | { |
| 122 | return NULL; |
| 123 | } |
| 124 | #endif |
| 125 | |
| 126 | void bug_get_file_line(struct bug_entry *bug, const char **file, |
| 127 | unsigned int *line) |
| 128 | { |
| 129 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
| 130 | #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS |
| 131 | *file = (const char *)&bug->file_disp + bug->file_disp; |
| 132 | #else |
| 133 | *file = bug->file; |
| 134 | #endif |
| 135 | *line = bug->line; |
| 136 | #else |
| 137 | *file = NULL; |
| 138 | *line = 0; |
| 139 | #endif |
| 140 | } |
| 141 | |
| 142 | static const char *bug_get_format(struct bug_entry *bug) |
| 143 | { |
| 144 | const char *format = NULL; |
| 145 | #ifdef HAVE_ARCH_BUG_FORMAT |
| 146 | #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS |
| 147 | /* |
| 148 | * Allow an architecture to: |
| 149 | * - relative encode NULL (difficult vs KASLR); |
| 150 | * - use a literal 0 (there are no valid objects inside |
| 151 | * the __bug_table itself to refer to after all); |
| 152 | * - use an empty string. |
| 153 | */ |
| 154 | if (bug->format_disp) |
| 155 | format = (const char *)&bug->format_disp + bug->format_disp; |
| 156 | if (format && format[0] == '\0') |
| 157 | format = NULL; |
| 158 | #else |
| 159 | format = bug->format; |
| 160 | #endif |
| 161 | #endif |
| 162 | return format; |
| 163 | } |
| 164 | |
| 165 | struct bug_entry *find_bug(unsigned long bugaddr) |
| 166 | { |
| 167 | struct bug_entry *bug; |
| 168 | |
| 169 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) |
| 170 | if (bugaddr == bug_addr(bug)) |
| 171 | return bug; |
| 172 | |
| 173 | return module_find_bug(bugaddr); |
| 174 | } |
| 175 | |
| 176 | __diag_push(); |
| 177 | __diag_ignore(GCC, all, "-Wsuggest-attribute=format" , |
| 178 | "Not a valid __printf() conversion candidate." ); |
| 179 | static void __warn_printf(const char *fmt, struct pt_regs *regs) |
| 180 | { |
| 181 | if (!fmt) |
| 182 | return; |
| 183 | |
| 184 | #ifdef HAVE_ARCH_BUG_FORMAT_ARGS |
| 185 | if (regs) { |
| 186 | struct arch_va_list _args; |
| 187 | va_list *args = __warn_args(args: &_args, regs); |
| 188 | |
| 189 | if (args) { |
| 190 | vprintk(fmt, args: *args); |
| 191 | return; |
| 192 | } |
| 193 | } |
| 194 | #endif |
| 195 | |
| 196 | printk("%s" , fmt); |
| 197 | } |
| 198 | __diag_pop(); |
| 199 | |
| 200 | static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long bugaddr, struct pt_regs *regs) |
| 201 | { |
| 202 | bool warning, once, done, no_cut, has_args; |
| 203 | const char *file, *fmt; |
| 204 | unsigned line; |
| 205 | |
| 206 | if (!bug) { |
| 207 | if (!is_valid_bugaddr(addr: bugaddr)) |
| 208 | return BUG_TRAP_TYPE_NONE; |
| 209 | |
| 210 | bug = find_bug(bugaddr); |
| 211 | if (!bug) |
| 212 | return BUG_TRAP_TYPE_NONE; |
| 213 | } |
| 214 | |
| 215 | disable_trace_on_warning(); |
| 216 | |
| 217 | bug_get_file_line(bug, file: &file, line: &line); |
| 218 | fmt = bug_get_format(bug); |
| 219 | |
| 220 | warning = bug->flags & BUGFLAG_WARNING; |
| 221 | once = bug->flags & BUGFLAG_ONCE; |
| 222 | done = bug->flags & BUGFLAG_DONE; |
| 223 | no_cut = bug->flags & BUGFLAG_NO_CUT_HERE; |
| 224 | has_args = bug->flags & BUGFLAG_ARGS; |
| 225 | |
| 226 | if (warning && once) { |
| 227 | if (done) |
| 228 | return BUG_TRAP_TYPE_WARN; |
| 229 | |
| 230 | /* |
| 231 | * Since this is the only store, concurrency is not an issue. |
| 232 | */ |
| 233 | bug->flags |= BUGFLAG_DONE; |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | * BUG() and WARN_ON() families don't print a custom debug message |
| 238 | * before triggering the exception handler, so we must add the |
| 239 | * "cut here" line now. WARN() issues its own "cut here" before the |
| 240 | * extra debugging message it writes before triggering the handler. |
| 241 | */ |
| 242 | if (!no_cut) { |
| 243 | printk(KERN_DEFAULT CUT_HERE); |
| 244 | __warn_printf(fmt, regs: has_args ? regs : NULL); |
| 245 | } |
| 246 | |
| 247 | if (warning) { |
| 248 | /* this is a WARN_ON rather than BUG/BUG_ON */ |
| 249 | __warn(file, line, caller: (void *)bugaddr, BUG_GET_TAINT(bug), regs, |
| 250 | NULL); |
| 251 | return BUG_TRAP_TYPE_WARN; |
| 252 | } |
| 253 | |
| 254 | if (file) |
| 255 | pr_crit("kernel BUG at %s:%u!\n" , file, line); |
| 256 | else |
| 257 | pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n" , |
| 258 | (void *)bugaddr); |
| 259 | |
| 260 | return BUG_TRAP_TYPE_BUG; |
| 261 | } |
| 262 | |
| 263 | enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs) |
| 264 | { |
| 265 | enum bug_trap_type ret; |
| 266 | bool rcu = false; |
| 267 | |
| 268 | rcu = warn_rcu_enter(); |
| 269 | ret = __report_bug(bug, bugaddr: bug_addr(bug), regs); |
| 270 | warn_rcu_exit(rcu); |
| 271 | |
| 272 | return ret; |
| 273 | } |
| 274 | |
| 275 | enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) |
| 276 | { |
| 277 | enum bug_trap_type ret; |
| 278 | bool rcu = false; |
| 279 | |
| 280 | rcu = warn_rcu_enter(); |
| 281 | ret = __report_bug(NULL, bugaddr, regs); |
| 282 | warn_rcu_exit(rcu); |
| 283 | |
| 284 | return ret; |
| 285 | } |
| 286 | |
| 287 | static void clear_once_table(struct bug_entry *start, struct bug_entry *end) |
| 288 | { |
| 289 | struct bug_entry *bug; |
| 290 | |
| 291 | for (bug = start; bug < end; bug++) |
| 292 | bug->flags &= ~BUGFLAG_DONE; |
| 293 | } |
| 294 | |
| 295 | void generic_bug_clear_once(void) |
| 296 | { |
| 297 | #ifdef CONFIG_MODULES |
| 298 | struct module *mod; |
| 299 | |
| 300 | scoped_guard(rcu) { |
| 301 | list_for_each_entry_rcu(mod, &module_bug_list, bug_list) |
| 302 | clear_once_table(start: mod->bug_table, |
| 303 | end: mod->bug_table + mod->num_bugs); |
| 304 | } |
| 305 | #endif |
| 306 | |
| 307 | clear_once_table(start: __start___bug_table, end: __stop___bug_table); |
| 308 | } |
| 309 | |