All of lore.kernel.org
 help / color / mirror / Atom feed
From: Elena Reshetova <elena.reshetova@intel.com>
To: kernel-hardening@lists.openwall.com
Cc: keescook@chromium.org, arnd@arndb.de, tglx@linutronix.de,
	mingo@redhat.com, h.peter.anvin@intel.com, peterz@infradead.org,
	will.deacon@arm.com, Hans Liljestrand <ishkamiel@gmail.com>,
	David Windsor <dwindsor@gmail.com>,
	Elena Reshetova <elena.reshetova@intel.com>
Subject: [kernel-hardening] [RFC v4 PATCH 02/13] percpu-refcount: leave atomic counter unprotected
Date: Thu, 10 Nov 2016 22:24:37 +0200	[thread overview]
Message-ID: <1478809488-18303-3-git-send-email-elena.reshetova@intel.com> (raw)
In-Reply-To: <1478809488-18303-1-git-send-email-elena.reshetova@intel.com>

From: Hans Liljestrand <ishkamiel@gmail.com>

This is a temporary solution, and a deviation from the PaX/Grsecurity
implementation where the counter in question is protected against
overflows. That however necessitates decreasing the PERCPU_COUNT_BIAS
which is used in lib/percpu-refcount.c. Such a change effectively cuts
the safe counter range down by half, and still allows the counter to,
without warning, prematurely reach zero (which is what the bias aims to
prevent).

A slightly expanded summary follows. Please see percpu-refcount source
for more details, particularly lib/percup-refcount.c where the
aforementioned bias is set and documented.

The atomic counter (defined in include/linux/percpu-refcount.h) needs to
be updated in a non-atomic way.  This means that before all the percpu
refs are added the value could be off in either direction, but no more
than the actual "true" value of the counter. In order to prevent the
counter prematurely reaching zero, a bias is used to offset the range
from [MIN,MAX] to [1,MAX]+[MIN,-1] (with "zero" in the middle, as far
from 0 as possible).

The problem is then that if the atomic is protected it cannot wrap (and
zero is already offset next to the "wrap-barrier", so it is practically
guaranteed to do just that). One solution would be to decrease this
bias, effectively cutting the safe range in half (now [1,MAX]). And
while overflows at MAX would be caught, the counter could still
prematurely reach zero. (Although since the counter can be off at most
by it's true value, presumably an overflow would still trigger at some
point during the percpu ref additions, but not necessarily before zero
had been reached one or more times.)

The immediate solution would be to go with the bias decrease (and
document the repercussions), but we have already seen some objections to
that due to the reasons above. Other solutions would seem to require
more comprehensive changes into how percpu-ref works, which we felt were
not suited for this patch series. We therefore decided to switch the
counter to an atomic_long_wrap_t and just document the issue for now.

Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
---
 include/linux/percpu-refcount.h | 18 ++++++++++++++----
 lib/percpu-refcount.c           | 12 ++++++------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index 1c7eec0..7c6a482 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -81,7 +81,17 @@ enum {
 };
 
 struct percpu_ref {
-	atomic_long_t		count;
+	/*
+	 * This is a temporary solution.
+	 *
+	 * The count should technically not be allowed to wrap, but due to the
+	 * way the counter is used (in lib/percpu-refcount.c) together with the
+	 * PERCPU_COUNT_BIAS it needs to wrap. This leaves the counter open
+	 * to over/underflows. A non-wrapping atomic, together with a bias
+	 * decrease would reduce the safe range in half, and also offer only
+	 * partial protection.
+	 */
+	atomic_long_wrap_t	count;
 	/*
 	 * The low bit of the pointer indicates whether the ref is in percpu
 	 * mode; if set, then get/put will manipulate the atomic_t.
@@ -174,7 +184,7 @@ static inline void percpu_ref_get_many(struct percpu_ref *ref, unsigned long nr)
 	if (__ref_is_percpu(ref, &percpu_count))
 		this_cpu_add(*percpu_count, nr);
 	else
-		atomic_long_add(nr, &ref->count);
+		atomic_long_add_wrap(nr, &ref->count);
 
 	rcu_read_unlock_sched();
 }
@@ -272,7 +282,7 @@ static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)
 
 	if (__ref_is_percpu(ref, &percpu_count))
 		this_cpu_sub(*percpu_count, nr);
-	else if (unlikely(atomic_long_sub_and_test(nr, &ref->count)))
+	else if (unlikely(atomic_long_sub_and_test_wrap(nr, &ref->count)))
 		ref->release(ref);
 
 	rcu_read_unlock_sched();
@@ -320,7 +330,7 @@ static inline bool percpu_ref_is_zero(struct percpu_ref *ref)
 
 	if (__ref_is_percpu(ref, &percpu_count))
 		return false;
-	return !atomic_long_read(&ref->count);
+	return !atomic_long_read_wrap(&ref->count);
 }
 
 #endif
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 9ac959e..2849e06 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -80,7 +80,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release,
 	else
 		start_count++;
 
-	atomic_long_set(&ref->count, start_count);
+	atomic_long_set_wrap(&ref->count, start_count);
 
 	ref->release = release;
 	ref->confirm_switch = NULL;
@@ -134,7 +134,7 @@ static void percpu_ref_switch_to_atomic_rcu(struct rcu_head *rcu)
 		count += *per_cpu_ptr(percpu_count, cpu);
 
 	pr_debug("global %ld percpu %ld",
-		 atomic_long_read(&ref->count), (long)count);
+		 atomic_long_read_wrap(&ref->count), (long)count);
 
 	/*
 	 * It's crucial that we sum the percpu counters _before_ adding the sum
@@ -148,11 +148,11 @@ static void percpu_ref_switch_to_atomic_rcu(struct rcu_head *rcu)
 	 * reaching 0 before we add the percpu counts. But doing it at the same
 	 * time is equivalent and saves us atomic operations:
 	 */
-	atomic_long_add((long)count - PERCPU_COUNT_BIAS, &ref->count);
+	atomic_long_add_wrap((long)count - PERCPU_COUNT_BIAS, &ref->count);
 
-	WARN_ONCE(atomic_long_read(&ref->count) <= 0,
+	WARN_ONCE(atomic_long_read_wrap(&ref->count) <= 0,
 		  "percpu ref (%pf) <= 0 (%ld) after switching to atomic",
-		  ref->release, atomic_long_read(&ref->count));
+		  ref->release, atomic_long_read_wrap(&ref->count));
 
 	/* @ref is viewed as dead on all CPUs, send out switch confirmation */
 	percpu_ref_call_confirm_rcu(rcu);
@@ -194,7 +194,7 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
 	if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC))
 		return;
 
-	atomic_long_add(PERCPU_COUNT_BIAS, &ref->count);
+	atomic_long_add_wrap(PERCPU_COUNT_BIAS, &ref->count);
 
 	/*
 	 * Restore per-cpu operation.  smp_store_release() is paired with
-- 
2.7.4

  parent reply	other threads:[~2016-11-10 20:24 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-10 20:24 [kernel-hardening] [RFC v4 PATCH 00/13] HARDENED_ATOMIC Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 01/13] Add architecture independent hardened atomic base Elena Reshetova
2016-11-10 20:41   ` [kernel-hardening] " David Windsor
2016-11-10 21:09     ` Peter Zijlstra
2016-11-10 21:35   ` Peter Zijlstra
2016-11-11  9:06     ` Reshetova, Elena
2016-11-10 20:24 ` Elena Reshetova [this message]
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 03/13] kernel: identify wrapping atomic usage Elena Reshetova
2016-11-10 21:58   ` [kernel-hardening] " Peter Zijlstra
2016-11-11  8:49     ` [kernel-hardening] " Reshetova, Elena
2016-11-19 13:28   ` [kernel-hardening] " Paul E. McKenney
2016-11-19 21:39     ` Kees Cook
2016-11-21 20:13       ` Paul E. McKenney
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 04/13] mm: " Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 05/13] fs: " Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 06/13] net: " Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 07/13] net: atm: " Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 08/13] security: " Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 09/13] drivers: identify wrapping atomic usage (part 1/2) Elena Reshetova
2016-11-10 21:48   ` [kernel-hardening] " Will Deacon
2016-11-11  8:57     ` [kernel-hardening] " Reshetova, Elena
2016-11-11 12:35       ` Mark Rutland
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 10/13] drivers: identify wrapping atomic usage (part 2/2) Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 11/13] x86: identify wrapping atomic usage Elena Reshetova
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 12/13] x86: implementation for HARDENED_ATOMIC Elena Reshetova
2016-11-10 20:40   ` [kernel-hardening] " Peter Zijlstra
2016-11-10 21:04     ` Kees Cook
2016-11-10 21:16       ` Peter Zijlstra
2016-11-10 21:32         ` Kees Cook
2016-11-10 21:46           ` Peter Zijlstra
2016-11-10 22:50     ` Peter Zijlstra
2016-11-10 23:07       ` Kees Cook
2016-11-10 23:30         ` Peter Zijlstra
2016-11-11  9:32           ` [kernel-hardening] " Reshetova, Elena
2016-11-11 10:29             ` [kernel-hardening] " Peter Zijlstra
2016-11-11 18:00           ` Kees Cook
2016-11-11 20:19             ` Peter Zijlstra
2016-11-10 21:33   ` Peter Zijlstra
2016-11-11  9:20     ` [kernel-hardening] " Reshetova, Elena
2016-11-10 20:24 ` [kernel-hardening] [RFC v4 PATCH 13/13] lkdtm: add tests for atomic over-/underflow Elena Reshetova
2016-11-10 20:37 ` [RFC v4 PATCH 00/13] HARDENED_ATOMIC Peter Zijlstra
2016-11-10 20:37   ` [kernel-hardening] " Peter Zijlstra
2016-11-10 20:48   ` Will Deacon
2016-11-10 20:48     ` [kernel-hardening] " Will Deacon
2016-11-10 21:01     ` Kees Cook
2016-11-10 21:01       ` [kernel-hardening] " Kees Cook
2016-11-10 21:23       ` David Windsor
2016-11-10 21:27         ` Kees Cook
2016-11-10 21:27           ` Kees Cook
2016-11-10 21:39           ` David Windsor
2016-11-10 21:39             ` David Windsor
2016-11-10 21:39         ` Peter Zijlstra
2016-11-10 21:13     ` Peter Zijlstra
2016-11-10 21:13       ` [kernel-hardening] " Peter Zijlstra
2016-11-10 21:23       ` Kees Cook
2016-11-10 21:23         ` [kernel-hardening] " Kees Cook
2016-11-11  4:25         ` Rik van Riel
2016-11-10 22:27       ` Greg KH
2016-11-10 23:15         ` Kees Cook
2016-11-10 23:15           ` Kees Cook
2016-11-10 23:38           ` Greg KH
2016-11-10 23:38             ` Greg KH
2016-11-11  7:50             ` David Windsor
2016-11-11 17:43               ` Kees Cook
2016-11-11 17:46                 ` Peter Zijlstra
2016-11-11 18:04                   ` Kees Cook
2016-11-11 20:17                     ` Peter Zijlstra
2016-11-14 20:31                       ` Kees Cook
2016-11-15  8:01                         ` Peter Zijlstra
2016-11-15 16:50                         ` Rik van Riel
2016-11-15 17:23                           ` Kees Cook
2016-11-16 17:09                             ` Rik van Riel
2016-11-16 17:32                               ` Peter Zijlstra
2016-11-16 17:41                                 ` Rik van Riel
2016-11-16 17:34                               ` Reshetova, Elena
2016-11-17  8:37                                 ` Peter Zijlstra
2016-11-17  9:04                                   ` Reshetova, Elena
2016-11-17  9:36                                     ` Peter Zijlstra
2016-11-17  9:36                                   ` Julia Lawall
2016-11-17 10:16                                     ` Peter Zijlstra
2016-11-17 11:19                                       ` Mark Rutland
2016-11-17 11:32                                         ` Julia Lawall
2016-11-17 12:59                                       ` Julia Lawall
2016-11-11 18:47                   ` Mark Rutland
2016-11-11 19:39                     ` Will Deacon
2016-11-11 18:31                 ` Mark Rutland
2016-11-11 20:05                   ` Peter Zijlstra
2016-11-15 10:36                     ` Mark Rutland
2016-11-15 11:21                       ` Peter Zijlstra
2016-11-15 18:02                         ` Mark Rutland
2016-11-10 23:57           ` Peter Zijlstra
2016-11-10 23:57             ` Peter Zijlstra
2016-11-11  0:29             ` Colin Vidal
2016-11-11 12:41               ` Mark Rutland
2016-11-11 12:47                 ` Peter Zijlstra
2016-11-11 13:00                   ` Peter Zijlstra
2016-11-11 14:39                     ` Thomas Gleixner
2016-11-11 14:48                       ` Peter Zijlstra
2016-11-11 23:07                     ` Peter Zijlstra
2016-11-13 11:03             ` Greg KH
2016-11-13 11:03               ` Greg KH
2016-11-10 20:56   ` Kees Cook
2016-11-10 20:56     ` [kernel-hardening] " Kees Cook
2016-11-11  3:20     ` David Windsor

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=1478809488-18303-3-git-send-email-elena.reshetova@intel.com \
    --to=elena.reshetova@intel.com \
    --cc=arnd@arndb.de \
    --cc=dwindsor@gmail.com \
    --cc=h.peter.anvin@intel.com \
    --cc=ishkamiel@gmail.com \
    --cc=keescook@chromium.org \
    --cc=kernel-hardening@lists.openwall.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    --cc=will.deacon@arm.com \
    /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.