All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: Mike Galbraith <efault@gmx.de>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>,
	linux-kernel@vger.kernel.org
Subject: [PATCH][DEBUG] x86/refcount: split up refcount saturation handling
Date: Thu, 31 Aug 2017 12:27:28 -0700	[thread overview]
Message-ID: <20170831192728.GA135568@beast> (raw)

In support of debugging the problems Mike Galbraith has seen with
x86-refcount vs gcc vs network refcounts...

This minimizes the differences between unchecked-refcount and x86-refcount
by changing the refcount_dec() failure case to not saturate. The reporting
of negative values is reduced to pr_warn from WARN to avoid spamming dmesg
(which may impact race conditions). Ratelimiting is disabled just to be
sure no reports are being dropped.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/mm/extable.c | 51 ++++++++++++++++++++++++++++++++++-----------------
 kernel/panic.c        |  2 +-
 2 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index c076f710de4c..dcb498668370 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -1,6 +1,7 @@
 #include <linux/extable.h>
 #include <linux/uaccess.h>
 #include <linux/sched/debug.h>
+#include <linux/ratelimit.h>
 
 #include <asm/traps.h>
 #include <asm/kdebug.h>
@@ -43,19 +44,7 @@ EXPORT_SYMBOL_GPL(ex_handler_fault);
 bool ex_handler_refcount(const struct exception_table_entry *fixup,
 			 struct pt_regs *regs, int trapnr)
 {
-	/* First unconditionally saturate the refcount. */
-	*(int *)regs->cx = INT_MIN / 2;
-
-	/*
-	 * Strictly speaking, this reports the fixup destination, not
-	 * the fault location, and not the actually overflowing
-	 * instruction, which is the instruction before the "js", but
-	 * since that instruction could be a variety of lengths, just
-	 * report the location after the overflow, which should be close
-	 * enough for finding the overflow, as it's at least back in
-	 * the function, having returned from .text.unlikely.
-	 */
-	regs->ip = ex_fixup_addr(fixup);
+	const char *msg;
 
 	/*
 	 * This function has been called because either a negative refcount
@@ -68,12 +57,40 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup,
 	 * these cases we want a report, since it's a boundary condition.
 	 *
 	 */
-	if (regs->flags & (X86_EFLAGS_OF | X86_EFLAGS_ZF)) {
-		bool zero = regs->flags & X86_EFLAGS_ZF;
-
-		refcount_error_report(regs, zero ? "hit zero" : "overflow");
+	if (regs->flags & X86_EFLAGS_OF) {
+		/* Always saturate on overflow detection. */
+		*(int *)regs->cx = INT_MIN / 2;
+		msg = "saturated due to overflow";
+	} else if (regs->flags & X86_EFLAGS_SF) {
+		/* Do not generate traceback on re-saturation. */
+		*(int *)regs->cx = INT_MIN / 2;
+		regs->ip = ex_fixup_addr(fixup);
+		pr_warn("refcount_t saturated due to negative result at %pB in %s[%d]\n",
+				(void *)instruction_pointer(regs),
+				current->comm, task_pid_nr(current));
+		return true;
+	} else if (regs->flags & X86_EFLAGS_ZF) {
+		/* An unchecked dec-to-zero happened. WARN only. */
+		msg = "hit zero without test";
+	} else {
+		/* Impossible state. */
+		*(int *)regs->cx = INT_MIN / 2;
+		msg = "saturated due to unknown state";
 	}
 
+	/*
+	 * Strictly speaking, this reports the fixup destination, not
+	 * the fault location, and not the actually overflowing
+	 * instruction, which is the instruction before the "js", but
+	 * since that instruction could be a variety of lengths, just
+	 * report the location after the overflow, which should be close
+	 * enough for finding the overflow, as it's at least back in
+	 * the function, having returned from .text.unlikely.
+	 */
+	regs->ip = ex_fixup_addr(fixup);
+
+	refcount_error_report(regs, msg);
+
 	return true;
 }
 EXPORT_SYMBOL_GPL(ex_handler_refcount);
diff --git a/kernel/panic.c b/kernel/panic.c
index bdd18afa19a4..966ade491543 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -605,7 +605,7 @@ EXPORT_SYMBOL(__stack_chk_fail);
 #ifdef CONFIG_ARCH_HAS_REFCOUNT
 void refcount_error_report(struct pt_regs *regs, const char *err)
 {
-	WARN_RATELIMIT(1, "refcount_t %s at %pB in %s[%d], uid/euid: %u/%u\n",
+	WARN(1, "refcount_t %s at %pB in %s[%d], uid/euid: %u/%u\n",
 		err, (void *)instruction_pointer(regs),
 		current->comm, task_pid_nr(current),
 		from_kuid_munged(&init_user_ns, current_uid()),
-- 
2.7.4


-- 
Kees Cook
Pixel Security

             reply	other threads:[~2017-08-31 19:27 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-31 19:27 Kees Cook [this message]
2017-09-02 10:35 ` [PATCH][DEBUG] x86/refcount: split up refcount saturation handling Ingo Molnar
2017-09-02 19:51   ` Kees Cook

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170831192728.GA135568@beast \
    --to=keescook@chromium.org \
    --cc=efault@gmx.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.