mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Pull non-MM updates from Andrew Morton:
- "pid: make sub-init creation retryable" (Oleg Nesterov)
Make creation of init in a new namespace more robust by clearing away
some historical cruft which is no longer needed. Also some
documentation fixups
- "selftests/fchmodat2: Error handling and general" (Mark Brown)
Fix and a cleanup for the fchmodat2() syscall selftest
- "lib: polynomial: Move to math/ and clean up" (Andy Shevchenko)
- "hung_task: Provide runtime reset interface for hung task detector"
(Aaron Tomlin)
Give administrators the ability to zero out
/proc/sys/kernel/hung_task_detect_count
- "tools/getdelays: use the static UAPI headers from
tools/include/uapi" (Thomas Weißschuh)
Teach getdelays to use the in-kernel UAPI headers rather than the
system-provided ones
- "watchdog/hardlockup: Improvements to hardlockup" (Mayank Rungta)
Several cleanups and fixups to the hardlockup detector code and its
documentation
- "lib/bch: fix undefined behavior from signed left-shifts" (Josh Law)
A couple of small/theoretical fixes in the bch code
- "ocfs2/dlm: fix two bugs in dlm_match_regions()" (Junrui Luo)
- "cleanup the RAID5 XOR library" (Christoph Hellwig)
A quite far-reaching cleanup to this code. I can't do better than to
quote Christoph:
"The XOR library used for the RAID5 parity is a bit of a mess right
now. The main file sits in crypto/ despite not being cryptography
and not using the crypto API, with the generic implementations
sitting in include/asm-generic and the arch implementations
sitting in an asm/ header in theory. The latter doesn't work for
many cases, so architectures often build the code directly into
the core kernel, or create another module for the architecture
code.
Change this to a single module in lib/ that also contains the
architecture optimizations, similar to the library work Eric
Biggers has done for the CRC and crypto libraries later. After
that it changes to better calling conventions that allow for
smarter architecture implementations (although none is contained
here yet), and uses static_call to avoid indirection function call
overhead"
- "lib/list_sort: Clean up list_sort() scheduling workarounds"
(Kuan-Wei Chiu)
Clean up this library code by removing a hacky thing which was added
for UBIFS, which UBIFS doesn't actually need
- "Fix bugs in extract_iter_to_sg()" (Christian Ehrhardt)
Fix a few bugs in the scatterlist code, add in-kernel tests for the
now-fixed bugs and fix a leak in the test itself
- "kdump: Enable LUKS-encrypted dump target support in ARM64 and
PowerPC" (Coiby Xu)
Enable support of the LUKS-encrypted device dump target on arm64 and
powerpc
- "ocfs2: consolidate extent list validation into block read callbacks"
(Joseph Qi)
Cleanup, simplify, and make more robust ocfs2's validation of extent
list fields (Kernel test robot loves mounting corrupted fs images!)
* tag 'mm-nonmm-stable-2026-04-15-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (127 commits)
ocfs2: validate group add input before caching
ocfs2: validate bg_bits during freefrag scan
ocfs2: fix listxattr handling when the buffer is full
doc: watchdog: fix typos etc
update Sean's email address
ocfs2: use get_random_u32() where appropriate
ocfs2: split transactions in dio completion to avoid credit exhaustion
ocfs2: remove redundant l_next_free_rec check in __ocfs2_find_path()
ocfs2: validate extent block list fields during block read
ocfs2: remove empty extent list check in ocfs2_dx_dir_lookup_rec()
ocfs2: validate dx_root extent list fields during block read
ocfs2: fix use-after-free in ocfs2_fault() when VM_FAULT_RETRY
ocfs2: handle invalid dinode in ocfs2_group_extend
.get_maintainer.ignore: add Askar
ocfs2: validate bg_list extent bounds in discontig groups
checkpatch: exclude forward declarations of const structs
tools/accounting: handle truncated taskstats netlink messages
taskstats: set version in TGID exit notifications
ocfs2/heartbeat: fix slot mapping rollback leaks on error paths
arm64,ppc64le/kdump: pass dm-crypt keys to kdump kernel
...
306 lines
7.3 KiB
C
306 lines
7.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
Generic support for BUG()
|
|
|
|
This respects the following config options:
|
|
|
|
CONFIG_BUG - emit BUG traps. Nothing happens without this.
|
|
CONFIG_GENERIC_BUG - enable this code.
|
|
CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit relative pointers for bug_addr and file
|
|
CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
|
|
|
|
CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
|
|
(though they're generally always on).
|
|
|
|
CONFIG_GENERIC_BUG is set by each architecture using this code.
|
|
|
|
To use this, your architecture must:
|
|
|
|
1. Set up the config options:
|
|
- Enable CONFIG_GENERIC_BUG if CONFIG_BUG
|
|
|
|
2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
|
|
- Define HAVE_ARCH_BUG
|
|
- Implement BUG() to generate a faulting instruction
|
|
- NOTE: struct bug_entry does not have "file" or "line" entries
|
|
when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
|
|
the values accordingly.
|
|
|
|
3. Implement the trap
|
|
- In the illegal instruction trap handler (typically), verify
|
|
that the fault was in kernel mode, and call report_bug()
|
|
- report_bug() will return whether it was a false alarm, a warning,
|
|
or an actual bug.
|
|
- You must implement the is_valid_bugaddr(bugaddr) callback which
|
|
returns true if the eip is a real kernel address, and it points
|
|
to the expected BUG trap instruction.
|
|
|
|
Jeremy Fitzhardinge <jeremy@goop.org> 2006
|
|
*/
|
|
|
|
#define pr_fmt(fmt) fmt
|
|
|
|
#include <linux/list.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/rculist.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/context_tracking.h>
|
|
|
|
extern struct bug_entry __start___bug_table[], __stop___bug_table[];
|
|
|
|
static inline unsigned long bug_addr(const struct bug_entry *bug)
|
|
{
|
|
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
|
return (unsigned long)&bug->bug_addr_disp + bug->bug_addr_disp;
|
|
#else
|
|
return bug->bug_addr;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_MODULES
|
|
/* Updates are protected by module mutex */
|
|
static LIST_HEAD(module_bug_list);
|
|
|
|
static struct bug_entry *module_find_bug(unsigned long bugaddr)
|
|
{
|
|
struct bug_entry *bug;
|
|
struct module *mod;
|
|
|
|
guard(rcu)();
|
|
list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
|
|
unsigned i;
|
|
|
|
bug = mod->bug_table;
|
|
for (i = 0; i < mod->num_bugs; ++i, ++bug)
|
|
if (bugaddr == bug_addr(bug))
|
|
return bug;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
|
struct module *mod)
|
|
{
|
|
char *secstrings;
|
|
unsigned int i;
|
|
|
|
mod->bug_table = NULL;
|
|
mod->num_bugs = 0;
|
|
|
|
/* Find the __bug_table section, if present */
|
|
secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
|
for (i = 1; i < hdr->e_shnum; i++) {
|
|
if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
|
|
continue;
|
|
mod->bug_table = (void *) sechdrs[i].sh_addr;
|
|
mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Strictly speaking this should have a spinlock to protect against
|
|
* traversals, but since we only traverse on BUG()s, a spinlock
|
|
* could potentially lead to deadlock and thus be counter-productive.
|
|
* Thus, this uses RCU to safely manipulate the bug list, since BUG
|
|
* must run in non-interruptive state.
|
|
*/
|
|
list_add_rcu(&mod->bug_list, &module_bug_list);
|
|
}
|
|
|
|
void module_bug_cleanup(struct module *mod)
|
|
{
|
|
list_del_rcu(&mod->bug_list);
|
|
}
|
|
|
|
#else
|
|
|
|
static inline struct bug_entry *module_find_bug(unsigned long bugaddr)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
void bug_get_file_line(struct bug_entry *bug, const char **file,
|
|
unsigned int *line)
|
|
{
|
|
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
|
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
|
*file = (const char *)&bug->file_disp + bug->file_disp;
|
|
#else
|
|
*file = bug->file;
|
|
#endif
|
|
*line = bug->line;
|
|
#else
|
|
*file = NULL;
|
|
*line = 0;
|
|
#endif
|
|
}
|
|
|
|
static const char *bug_get_format(struct bug_entry *bug)
|
|
{
|
|
const char *format = NULL;
|
|
#ifdef HAVE_ARCH_BUG_FORMAT
|
|
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
|
/*
|
|
* Allow an architecture to:
|
|
* - relative encode NULL (difficult vs KASLR);
|
|
* - use a literal 0 (there are no valid objects inside
|
|
* the __bug_table itself to refer to after all);
|
|
* - use an empty string.
|
|
*/
|
|
if (bug->format_disp)
|
|
format = (const char *)&bug->format_disp + bug->format_disp;
|
|
if (format && format[0] == '\0')
|
|
format = NULL;
|
|
#else
|
|
format = bug->format;
|
|
#endif
|
|
#endif
|
|
return format;
|
|
}
|
|
|
|
struct bug_entry *find_bug(unsigned long bugaddr)
|
|
{
|
|
struct bug_entry *bug;
|
|
|
|
for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
|
|
if (bugaddr == bug_addr(bug))
|
|
return bug;
|
|
|
|
return module_find_bug(bugaddr);
|
|
}
|
|
|
|
static __printf(1, 0)
|
|
void __warn_printf(const char *fmt, struct pt_regs *regs)
|
|
{
|
|
if (!fmt)
|
|
return;
|
|
|
|
#ifdef HAVE_ARCH_BUG_FORMAT_ARGS
|
|
if (regs) {
|
|
struct arch_va_list _args;
|
|
va_list *args = __warn_args(&_args, regs);
|
|
|
|
if (args) {
|
|
vprintk(fmt, *args);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
printk("%s", fmt);
|
|
}
|
|
|
|
static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long bugaddr, struct pt_regs *regs)
|
|
{
|
|
bool warning, once, done, no_cut, has_args;
|
|
const char *file, *fmt;
|
|
unsigned line;
|
|
|
|
if (!bug) {
|
|
if (!is_valid_bugaddr(bugaddr))
|
|
return BUG_TRAP_TYPE_NONE;
|
|
|
|
bug = find_bug(bugaddr);
|
|
if (!bug)
|
|
return BUG_TRAP_TYPE_NONE;
|
|
}
|
|
|
|
disable_trace_on_warning();
|
|
|
|
bug_get_file_line(bug, &file, &line);
|
|
fmt = bug_get_format(bug);
|
|
|
|
warning = bug->flags & BUGFLAG_WARNING;
|
|
once = bug->flags & BUGFLAG_ONCE;
|
|
done = bug->flags & BUGFLAG_DONE;
|
|
no_cut = bug->flags & BUGFLAG_NO_CUT_HERE;
|
|
has_args = bug->flags & BUGFLAG_ARGS;
|
|
|
|
if (warning && once) {
|
|
if (done)
|
|
return BUG_TRAP_TYPE_WARN;
|
|
|
|
/*
|
|
* Since this is the only store, concurrency is not an issue.
|
|
*/
|
|
bug->flags |= BUGFLAG_DONE;
|
|
}
|
|
|
|
/*
|
|
* BUG() and WARN_ON() families don't print a custom debug message
|
|
* before triggering the exception handler, so we must add the
|
|
* "cut here" line now. WARN() issues its own "cut here" before the
|
|
* extra debugging message it writes before triggering the handler.
|
|
*/
|
|
if (!no_cut) {
|
|
printk(KERN_DEFAULT CUT_HERE);
|
|
__warn_printf(fmt, has_args ? regs : NULL);
|
|
}
|
|
|
|
if (warning) {
|
|
/* this is a WARN_ON rather than BUG/BUG_ON */
|
|
__warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs,
|
|
NULL);
|
|
return BUG_TRAP_TYPE_WARN;
|
|
}
|
|
|
|
if (file)
|
|
pr_crit("kernel BUG at %s:%u!\n", file, line);
|
|
else
|
|
pr_crit("kernel BUG at %pB [verbose debug info unavailable]\n",
|
|
(void *)bugaddr);
|
|
|
|
return BUG_TRAP_TYPE_BUG;
|
|
}
|
|
|
|
enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs)
|
|
{
|
|
enum bug_trap_type ret;
|
|
bool rcu;
|
|
|
|
rcu = warn_rcu_enter();
|
|
ret = __report_bug(bug, bug_addr(bug), regs);
|
|
warn_rcu_exit(rcu);
|
|
|
|
return ret;
|
|
}
|
|
|
|
enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
|
|
{
|
|
enum bug_trap_type ret;
|
|
bool rcu;
|
|
|
|
rcu = warn_rcu_enter();
|
|
ret = __report_bug(NULL, bugaddr, regs);
|
|
warn_rcu_exit(rcu);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void clear_once_table(struct bug_entry *start, struct bug_entry *end)
|
|
{
|
|
struct bug_entry *bug;
|
|
|
|
for (bug = start; bug < end; bug++)
|
|
bug->flags &= ~BUGFLAG_DONE;
|
|
}
|
|
|
|
void generic_bug_clear_once(void)
|
|
{
|
|
#ifdef CONFIG_MODULES
|
|
struct module *mod;
|
|
|
|
scoped_guard(rcu) {
|
|
list_for_each_entry_rcu(mod, &module_bug_list, bug_list)
|
|
clear_once_table(mod->bug_table,
|
|
mod->bug_table + mod->num_bugs);
|
|
}
|
|
#endif
|
|
|
|
clear_once_table(__start___bug_table, __stop___bug_table);
|
|
}
|