Hi,
This builds on Jann's v1 patch[1]. Changes in v2:
- move sysctl into kernel/exit.c (where it belongs)
- expand Documentation slightly
New stuff in v2:
- expose oops_count to sysfs
- consolidate panic_on_warn usage
- introduce warn_limit
- expose warn_count to sysfs
[1] https://lore.kernel.org/lkml/[email protected]
Jann Horn (1):
exit: Put an upper limit on how often we can oops
Kees Cook (5):
panic: Separate sysctl logic from CONFIG_SMP
exit: Expose "oops_count" to sysfs
panic: Consolidate open-coded panic_on_warn checks
panic: Introduce warn_limit
panic: Expose "warn_count" to sysfs
.../ABI/testing/sysfs-kernel-oops_count | 6 ++
.../ABI/testing/sysfs-kernel-warn_count | 6 ++
Documentation/admin-guide/sysctl/kernel.rst | 17 ++++++
MAINTAINERS | 2 +
include/linux/panic.h | 1 +
kernel/exit.c | 60 +++++++++++++++++++
kernel/kcsan/report.c | 3 +-
kernel/panic.c | 44 +++++++++++++-
kernel/sched/core.c | 3 +-
lib/ubsan.c | 3 +-
mm/kasan/report.c | 4 +-
mm/kfence/report.c | 3 +-
12 files changed, 139 insertions(+), 13 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-kernel-oops_count
create mode 100644 Documentation/ABI/testing/sysfs-kernel-warn_count
--
2.34.1
Since Warn count is now tracked and is a fairly interesting signal, add
the entry /sys/kernel/warn_count to expose it to userspace.
Cc: Petr Mladek <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: tangmeng <[email protected]>
Cc: "Guilherme G. Piccoli" <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Tiezhu Yang <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
.../ABI/testing/sysfs-kernel-warn_count | 6 +++++
MAINTAINERS | 1 +
kernel/panic.c | 22 +++++++++++++++++--
3 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-kernel-warn_count
diff --git a/Documentation/ABI/testing/sysfs-kernel-warn_count b/Documentation/ABI/testing/sysfs-kernel-warn_count
new file mode 100644
index 000000000000..08f083d2fd51
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-warn_count
@@ -0,0 +1,6 @@
+What: /sys/kernel/oops_count
+Date: November 2022
+KernelVersion: 6.2.0
+Contact: Linux Kernel Hardening List <[email protected]>
+Description:
+ Shows how many times the system has Warned since last boot.
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1e95a58e54..282cd8a513fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11107,6 +11107,7 @@ L: [email protected]
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
F: Documentation/ABI/testing/sysfs-kernel-oops_count
+F: Documentation/ABI/testing/sysfs-kernel-warn_count
F: include/linux/overflow.h
F: include/linux/randomize_kstack.h
F: mm/usercopy.c
diff --git a/kernel/panic.c b/kernel/panic.c
index b235fa4a6fc8..ddf0f8956d6e 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -32,6 +32,7 @@
#include <linux/bug.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
+#include <linux/sysfs.h>
#include <trace/events/error_report.h>
#include <asm/sections.h>
@@ -107,6 +108,25 @@ static __init int kernel_panic_sysctls_init(void)
late_initcall(kernel_panic_sysctls_init);
#endif
+static atomic_t warn_count = ATOMIC_INIT(0);
+
+#ifdef CONFIG_SYSFS
+static ssize_t warn_count_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *page)
+{
+ return sysfs_emit(page, "%d\n", atomic_read(&warn_count));
+}
+
+static struct kobj_attribute warn_count_attr = __ATTR_RO(warn_count);
+
+static __init int kernel_panic_sysfs_init(void)
+{
+ sysfs_add_file_to_group(kernel_kobj, &warn_count_attr.attr, NULL);
+ return 0;
+}
+late_initcall(kernel_panic_sysfs_init);
+#endif
+
static long no_blink(int state)
{
return 0;
@@ -211,8 +231,6 @@ static void panic_print_sys_info(bool console_flush)
void check_panic_on_warn(const char *reason)
{
- static atomic_t warn_count = ATOMIC_INIT(0);
-
if (panic_on_warn)
panic("%s: panic_on_warn set ...\n", reason);
--
2.34.1
Since Oops count is now tracked and is a fairly interesting signal, add
the entry /sys/kernel/oops_count to expose it to userspace.
Cc: "Eric W. Biederman" <[email protected]>
Cc: Jann Horn <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
.../ABI/testing/sysfs-kernel-oops_count | 6 +++++
MAINTAINERS | 1 +
kernel/exit.c | 22 +++++++++++++++++--
3 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-kernel-oops_count
diff --git a/Documentation/ABI/testing/sysfs-kernel-oops_count b/Documentation/ABI/testing/sysfs-kernel-oops_count
new file mode 100644
index 000000000000..156cca9dbc96
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-oops_count
@@ -0,0 +1,6 @@
+What: /sys/kernel/oops_count
+Date: November 2022
+KernelVersion: 6.2.0
+Contact: Linux Kernel Hardening List <[email protected]>
+Description:
+ Shows how many times the system has Oopsed since last boot.
diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd80c113721..0a1e95a58e54 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11106,6 +11106,7 @@ M: Kees Cook <[email protected]>
L: [email protected]
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
+F: Documentation/ABI/testing/sysfs-kernel-oops_count
F: include/linux/overflow.h
F: include/linux/randomize_kstack.h
F: mm/usercopy.c
diff --git a/kernel/exit.c b/kernel/exit.c
index 892f38aeb0a4..4bffef9f3f46 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -67,6 +67,7 @@
#include <linux/io_uring.h>
#include <linux/kprobes.h>
#include <linux/rethook.h>
+#include <linux/sysfs.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
@@ -99,6 +100,25 @@ static __init int kernel_exit_sysctls_init(void)
late_initcall(kernel_exit_sysctls_init);
#endif
+static atomic_t oops_count = ATOMIC_INIT(0);
+
+#ifdef CONFIG_SYSFS
+static ssize_t oops_count_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *page)
+{
+ return sysfs_emit(page, "%d\n", atomic_read(&oops_count));
+}
+
+static struct kobj_attribute oops_count_attr = __ATTR_RO(oops_count);
+
+static __init int kernel_exit_sysfs_init(void)
+{
+ sysfs_add_file_to_group(kernel_kobj, &oops_count_attr.attr, NULL);
+ return 0;
+}
+late_initcall(kernel_exit_sysfs_init);
+#endif
+
static void __unhash_process(struct task_struct *p, bool group_dead)
{
nr_threads--;
@@ -901,8 +921,6 @@ void __noreturn do_exit(long code)
void __noreturn make_task_dead(int signr)
{
- static atomic_t oops_count = ATOMIC_INIT(0);
-
/*
* Take the task off the cpu after something catastrophic has
* happened.
--
2.34.1
Like oops_limit, add warn_limit for limiting the number of warnings when
panic_on_warn is not set.
Cc: Jonathan Corbet <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: "Jason A. Donenfeld" <[email protected]>
Cc: Eric Biggers <[email protected]>
Cc: Huang Ying <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: tangmeng <[email protected]>
Cc: "Guilherme G. Piccoli" <[email protected]>
Cc: Tiezhu Yang <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
Documentation/admin-guide/sysctl/kernel.rst | 9 +++++++++
kernel/panic.c | 13 +++++++++++++
2 files changed, 22 insertions(+)
diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index 09f3fb2f8585..c385d5319cdf 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -1508,6 +1508,15 @@ entry will default to 2 instead of 0.
2 Unprivileged calls to ``bpf()`` are disabled
= =============================================================
+
+warn_limit
+==========
+
+Number of kernel warnings after which the kernel should panic when
+``panic_on_warn`` is not set. Setting this to 0 or 1 has the same effect
+as setting ``panic_on_warn=1``.
+
+
watchdog
========
diff --git a/kernel/panic.c b/kernel/panic.c
index 3afd234767bc..b235fa4a6fc8 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -58,6 +58,7 @@ bool crash_kexec_post_notifiers;
int panic_on_warn __read_mostly;
unsigned long panic_on_taint;
bool panic_on_taint_nousertaint = false;
+static unsigned int warn_limit __read_mostly = 10000;
int panic_timeout = CONFIG_PANIC_TIMEOUT;
EXPORT_SYMBOL_GPL(panic_timeout);
@@ -88,6 +89,13 @@ static struct ctl_table kern_panic_table[] = {
.extra2 = SYSCTL_ONE,
},
#endif
+ {
+ .procname = "warn_limit",
+ .data = &warn_limit,
+ .maxlen = sizeof(warn_limit),
+ .mode = 0644,
+ .proc_handler = proc_douintvec,
+ },
{ }
};
@@ -203,8 +211,13 @@ static void panic_print_sys_info(bool console_flush)
void check_panic_on_warn(const char *reason)
{
+ static atomic_t warn_count = ATOMIC_INIT(0);
+
if (panic_on_warn)
panic("%s: panic_on_warn set ...\n", reason);
+
+ if (atomic_inc_return(&warn_count) >= READ_ONCE(warn_limit))
+ panic("Warned too often (warn_limit is %d)", warn_limit);
}
/**
--
2.34.1
On Wed, Nov 09, 2022 at 12:00:43PM -0800, Kees Cook wrote:
> Hi,
>
> This builds on Jann's v1 patch[1]. Changes in v2:
> - move sysctl into kernel/exit.c (where it belongs)
> - expand Documentation slightly
>
> New stuff in v2:
> - expose oops_count to sysfs
> - consolidate panic_on_warn usage
> - introduce warn_limit
> - expose warn_count to sysfs
>
> [1] https://lore.kernel.org/lkml/[email protected]
>
> Jann Horn (1):
> exit: Put an upper limit on how often we can oops
>
> Kees Cook (5):
> panic: Separate sysctl logic from CONFIG_SMP
> exit: Expose "oops_count" to sysfs
> panic: Consolidate open-coded panic_on_warn checks
> panic: Introduce warn_limit
> panic: Expose "warn_count" to sysfs
For all:
Reviewed-by: Luis Chamberlain <[email protected]>
Luis
On Wed, 9 Nov 2022 at 21:00, Kees Cook <[email protected]> wrote:
>
> Like oops_limit, add warn_limit for limiting the number of warnings when
> panic_on_warn is not set.
>
> Cc: Jonathan Corbet <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: Baolin Wang <[email protected]>
> Cc: "Jason A. Donenfeld" <[email protected]>
> Cc: Eric Biggers <[email protected]>
> Cc: Huang Ying <[email protected]>
> Cc: Petr Mladek <[email protected]>
> Cc: tangmeng <[email protected]>
> Cc: "Guilherme G. Piccoli" <[email protected]>
> Cc: Tiezhu Yang <[email protected]>
> Cc: Sebastian Andrzej Siewior <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> Documentation/admin-guide/sysctl/kernel.rst | 9 +++++++++
> kernel/panic.c | 13 +++++++++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
> index 09f3fb2f8585..c385d5319cdf 100644
> --- a/Documentation/admin-guide/sysctl/kernel.rst
> +++ b/Documentation/admin-guide/sysctl/kernel.rst
> @@ -1508,6 +1508,15 @@ entry will default to 2 instead of 0.
> 2 Unprivileged calls to ``bpf()`` are disabled
> = =============================================================
>
> +
> +warn_limit
> +==========
> +
> +Number of kernel warnings after which the kernel should panic when
> +``panic_on_warn`` is not set. Setting this to 0 or 1 has the same effect
> +as setting ``panic_on_warn=1``.
> +
> +
> watchdog
> ========
>
> diff --git a/kernel/panic.c b/kernel/panic.c
> index 3afd234767bc..b235fa4a6fc8 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -58,6 +58,7 @@ bool crash_kexec_post_notifiers;
> int panic_on_warn __read_mostly;
> unsigned long panic_on_taint;
> bool panic_on_taint_nousertaint = false;
> +static unsigned int warn_limit __read_mostly = 10000;
>
> int panic_timeout = CONFIG_PANIC_TIMEOUT;
> EXPORT_SYMBOL_GPL(panic_timeout);
> @@ -88,6 +89,13 @@ static struct ctl_table kern_panic_table[] = {
> .extra2 = SYSCTL_ONE,
> },
> #endif
> + {
> + .procname = "warn_limit",
> + .data = &warn_limit,
> + .maxlen = sizeof(warn_limit),
> + .mode = 0644,
> + .proc_handler = proc_douintvec,
> + },
> { }
> };
>
> @@ -203,8 +211,13 @@ static void panic_print_sys_info(bool console_flush)
>
> void check_panic_on_warn(const char *reason)
> {
> + static atomic_t warn_count = ATOMIC_INIT(0);
> +
> if (panic_on_warn)
> panic("%s: panic_on_warn set ...\n", reason);
> +
> + if (atomic_inc_return(&warn_count) >= READ_ONCE(warn_limit))
> + panic("Warned too often (warn_limit is %d)", warn_limit);
Shouldn't this also include the "reason", like above? (Presumably a
warning had just been generated to console so the reason is easy
enough to infer from the log, although in that case "reason" also
seems redundant above.)
On Mon, Nov 14, 2022 at 10:48:38AM +0100, Marco Elver wrote:
> On Wed, 9 Nov 2022 at 21:00, Kees Cook <[email protected]> wrote:
> >
> > Like oops_limit, add warn_limit for limiting the number of warnings when
> > panic_on_warn is not set.
> >
> > Cc: Jonathan Corbet <[email protected]>
> > Cc: Andrew Morton <[email protected]>
> > Cc: Baolin Wang <[email protected]>
> > Cc: "Jason A. Donenfeld" <[email protected]>
> > Cc: Eric Biggers <[email protected]>
> > Cc: Huang Ying <[email protected]>
> > Cc: Petr Mladek <[email protected]>
> > Cc: tangmeng <[email protected]>
> > Cc: "Guilherme G. Piccoli" <[email protected]>
> > Cc: Tiezhu Yang <[email protected]>
> > Cc: Sebastian Andrzej Siewior <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > Documentation/admin-guide/sysctl/kernel.rst | 9 +++++++++
> > kernel/panic.c | 13 +++++++++++++
> > 2 files changed, 22 insertions(+)
> >
> > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
> > index 09f3fb2f8585..c385d5319cdf 100644
> > --- a/Documentation/admin-guide/sysctl/kernel.rst
> > +++ b/Documentation/admin-guide/sysctl/kernel.rst
> > @@ -1508,6 +1508,15 @@ entry will default to 2 instead of 0.
> > 2 Unprivileged calls to ``bpf()`` are disabled
> > = =============================================================
> >
> > +
> > +warn_limit
> > +==========
> > +
> > +Number of kernel warnings after which the kernel should panic when
> > +``panic_on_warn`` is not set. Setting this to 0 or 1 has the same effect
> > +as setting ``panic_on_warn=1``.
> > +
> > +
> > watchdog
> > ========
> >
> > diff --git a/kernel/panic.c b/kernel/panic.c
> > index 3afd234767bc..b235fa4a6fc8 100644
> > --- a/kernel/panic.c
> > +++ b/kernel/panic.c
> > @@ -58,6 +58,7 @@ bool crash_kexec_post_notifiers;
> > int panic_on_warn __read_mostly;
> > unsigned long panic_on_taint;
> > bool panic_on_taint_nousertaint = false;
> > +static unsigned int warn_limit __read_mostly = 10000;
> >
> > int panic_timeout = CONFIG_PANIC_TIMEOUT;
> > EXPORT_SYMBOL_GPL(panic_timeout);
> > @@ -88,6 +89,13 @@ static struct ctl_table kern_panic_table[] = {
> > .extra2 = SYSCTL_ONE,
> > },
> > #endif
> > + {
> > + .procname = "warn_limit",
> > + .data = &warn_limit,
> > + .maxlen = sizeof(warn_limit),
> > + .mode = 0644,
> > + .proc_handler = proc_douintvec,
> > + },
> > { }
> > };
> >
> > @@ -203,8 +211,13 @@ static void panic_print_sys_info(bool console_flush)
> >
> > void check_panic_on_warn(const char *reason)
> > {
> > + static atomic_t warn_count = ATOMIC_INIT(0);
> > +
> > if (panic_on_warn)
> > panic("%s: panic_on_warn set ...\n", reason);
> > +
> > + if (atomic_inc_return(&warn_count) >= READ_ONCE(warn_limit))
> > + panic("Warned too often (warn_limit is %d)", warn_limit);
>
> Shouldn't this also include the "reason", like above? (Presumably a
> warning had just been generated to console so the reason is easy
> enough to infer from the log, although in that case "reason" also
> seems redundant above.)
Yeah, that makes sense. I had been thinking that since it was an action
due to repeated prior actions, the current "reason" didn't matter here.
But thinking about it more, I see what you mean. :)
--
Kees Cook