Drop patches applied upstream in 3.15

svn path=/dists/trunk/linux/; revision=21424
This commit is contained in:
Ben Hutchings 2014-06-12 20:40:28 +00:00
parent 354e48794a
commit d86d3a0ffb
7 changed files with 0 additions and 843 deletions

View File

@ -1,114 +0,0 @@
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 15 Mar 2014 22:34:09 +0000
Subject: [PATCH 1/2] Staging: speakup: Move pasting into a work item
Bug-Debian: https://bugs.debian.org/735202
Bug-Debian: https://bugs.debian.org/744015
Input is handled in softirq context, but when pasting we may
need to sleep. speakup_paste_selection() currently tries to
bodge this by busy-waiting if in_atomic(), but that doesn't
help because the ldisc may also sleep.
For bonus breakage, speakup_paste_selection() changes the
state of current, even though it's not running in process
context.
Move it into a work item and make sure to cancel it on exit.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/staging/speakup/main.c | 1 +
drivers/staging/speakup/selection.c | 38 +++++++++++++++++++++++++++++++------
drivers/staging/speakup/speakup.h | 1 +
3 files changed, 34 insertions(+), 6 deletions(-)
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -2218,6 +2218,7 @@ static void __exit speakup_exit(void)
unregister_keyboard_notifier(&keyboard_notifier_block);
unregister_vt_notifier(&vt_notifier_block);
speakup_unregister_devsynth();
+ speakup_cancel_paste();
del_timer(&cursor_timer);
kthread_stop(speakup_task);
speakup_task = NULL;
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -4,6 +4,8 @@
#include <linux/sched.h>
#include <linux/device.h> /* for dev_warn */
#include <linux/selection.h>
+#include <linux/workqueue.h>
+#include <asm/cmpxchg.h>
#include "speakup.h"
@@ -121,20 +123,24 @@ int speakup_set_selection(struct tty_str
return 0;
}
-/* TODO: move to some helper thread, probably. That'd fix having to check for
- * in_atomic(). */
-int speakup_paste_selection(struct tty_struct *tty)
-{
+struct speakup_paste_work {
+ struct work_struct work;
+ struct tty_struct *tty;
+};
+
+static void __speakup_paste_selection(struct work_struct *work)
+{
+ struct speakup_paste_work *spw =
+ container_of(work, struct speakup_paste_work, work);
+ struct tty_struct *tty = xchg(&spw->tty, NULL);
struct vc_data *vc = (struct vc_data *) tty->driver_data;
int pasted = 0, count;
DECLARE_WAITQUEUE(wait, current);
+
add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
if (test_bit(TTY_THROTTLED, &tty->flags)) {
- if (in_atomic())
- /* if we are in an interrupt handler, abort */
- break;
schedule();
continue;
}
@@ -146,6 +152,26 @@ int speakup_paste_selection(struct tty_s
}
remove_wait_queue(&vc->paste_wait, &wait);
current->state = TASK_RUNNING;
+ tty_kref_put(tty);
+}
+
+static struct speakup_paste_work speakup_paste_work = {
+ .work = __WORK_INITIALIZER(speakup_paste_work.work,
+ __speakup_paste_selection)
+};
+
+int speakup_paste_selection(struct tty_struct *tty)
+{
+ if (cmpxchg(&speakup_paste_work.tty, NULL, tty) != NULL)
+ return -EBUSY;
+
+ tty_kref_get(tty);
+ schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work);
return 0;
}
+void speakup_cancel_paste(void)
+{
+ cancel_work_sync(&speakup_paste_work.work);
+ tty_kref_put(speakup_paste_work.tty);
+}
--- a/drivers/staging/speakup/speakup.h
+++ b/drivers/staging/speakup/speakup.h
@@ -77,6 +77,7 @@ extern void synth_buffer_clear(void);
extern void speakup_clear_selection(void);
extern int speakup_set_selection(struct tty_struct *tty);
extern int speakup_paste_selection(struct tty_struct *tty);
+extern void speakup_cancel_paste(void);
extern void speakup_register_devsynth(void);
extern void speakup_unregister_devsynth(void);
extern void synth_write(const char *buf, size_t count);

View File

@ -1,82 +0,0 @@
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 15 Mar 2014 22:42:27 +0000
Subject: [PATCH 2/2] Staging: speakup: Update __speakup_paste_selection() tty
(ab)usage to match vt
Bug-Debian: https://bugs.debian.org/735202
Bug-Debian: https://bugs.debian.org/744015
This function is largely a duplicate of paste_selection() in
drivers/tty/vt/selection.c, but with its own selection state. The
speakup selection mechanism should really be merged with vt.
For now, apply the changes from 'TTY: vt, fix paste_selection ldisc
handling', 'tty: Make ldisc input flow control concurrency-friendly',
and 'tty: Fix unsafe vt paste_selection()'.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/staging/speakup/selection.c | 14 +++++++++++---
drivers/tty/tty_buffer.c | 2 ++
2 files changed, 13 insertions(+), 3 deletions(-)
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -5,6 +5,8 @@
#include <linux/device.h> /* for dev_warn */
#include <linux/selection.h>
#include <linux/workqueue.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <asm/cmpxchg.h>
#include "speakup.h"
@@ -135,8 +137,12 @@ static void __speakup_paste_selection(st
struct tty_struct *tty = xchg(&spw->tty, NULL);
struct vc_data *vc = (struct vc_data *) tty->driver_data;
int pasted = 0, count;
+ struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current);
+ ld = tty_ldisc_ref_wait(tty);
+ tty_buffer_lock_exclusive(&vc->port);
+
add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -145,13 +151,15 @@ static void __speakup_paste_selection(st
continue;
}
count = sel_buffer_lth - pasted;
- count = min_t(int, count, tty->receive_room);
- tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
- NULL, count);
+ count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
+ count);
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
current->state = TASK_RUNNING;
+
+ tty_buffer_unlock_exclusive(&vc->port);
+ tty_ldisc_deref(ld);
tty_kref_put(tty);
}
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -60,6 +60,7 @@ void tty_buffer_lock_exclusive(struct tt
atomic_inc(&buf->priority);
mutex_lock(&buf->lock);
}
+EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive);
void tty_buffer_unlock_exclusive(struct tty_port *port)
{
@@ -73,6 +74,7 @@ void tty_buffer_unlock_exclusive(struct
if (restart)
queue_work(system_unbound_wq, &buf->work);
}
+EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive);
/**
* tty_buffer_space_avail - return unused buffer space

View File

@ -1,131 +0,0 @@
Return-Path: <tglx@linutronix.de>
Received: from Galois.linutronix.de (Galois.linutronix.de
[IPv6:2001:470:1f0b:db:abcd:42:0:1]) by vinyl.outflux.net
(8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id s53CRBS5010805
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for
<kees@outflux.net>; Tue, 3 Jun 2014 05:27:17 -0700
Received: from localhost ([127.0.0.1] helo=[127.0.1.1]) by
Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from
<tglx@linutronix.de>) id 1Wrno4-0002Sb-9g; Tue, 03 Jun 2014 14:27:08 +0200
Message-Id: <20140603121944.949737592@linutronix.de>
User-Agent: quilt/0.63-1
Date: Tue, 03 Jun 2014 12:27:07 -0000
From: Thomas Gleixner <tglx@linutronix.de>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Darren Hart <dvhart@linux.intel.com>, Kees Cook <kees@outflux.net>,
"security@kernel.org" <security@kernel.org>, linux-distros@vs.openwall.org,
Sebastian Krahmer <krahmer@suse.de>, Ingo Molnar <mingo@kernel.org>, Kees
Cook <keescook@chromium.org>, Will Drewry <wad@chromium.org>
Subject: [patch 3/4] futex: Always cleanup owner tid in unlock_pi
References: <20140603113303.799564413@linutronix.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-15
Content-Disposition: inline; filename=futex-cleanup-owner-tid-on-unlock.patch
X-Linutronix-Spam-Score: -1.0
X-Linutronix-Spam-Level: -
X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required,
ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001
Received-SPF: none (linutronix.de: No applicable sender policy available)
receiver=smtp.outflux.net; identity=mailfrom;
envelope-from="tglx@linutronix.de"; helo=Galois.linutronix.de;
client-ip="2001:470:1f0b:db:abcd:42:0:1"
Envelope-To: kees@outflux.net
X-MIMEDefang-Filter: outflux$Revision: 1.316 $
X-HELO: Galois.linutronix.de
X-Spam-Status: No, hits=-0.651 required=5 tests=RP_MATCHES_RCVD
X-Spam-Checker-Version: SpamAssassin 3.4.0-outflux_revision__1.66__
X-Scanned-By: MIMEDefang 2.73
Content-Length: 2854
Lines: 93
If the owner died bit is set at futex_unlock_pi, we currently do not
cleanup the user space futex. So the owner TID of the current owner
(the unlocker) persists. That's observable inconsistant state,
especially when the ownership of the pi state got transferred.
Clean it up unconditionally.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: stable@vger.kernel.org
---
kernel/futex.c | 44 ++++++++++++++++++++------------------------
1 file changed, 20 insertions(+), 24 deletions(-)
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1038,6 +1038,7 @@ static int wake_futex_pi(u32 __user *uad
struct task_struct *new_owner;
struct futex_pi_state *pi_state = this->pi_state;
u32 uninitialized_var(curval), newval;
+ int ret = 0;
if (!pi_state)
return -EINVAL;
@@ -1061,23 +1062,19 @@ static int wake_futex_pi(u32 __user *uad
new_owner = this->task;
/*
- * We pass it to the next owner. (The WAITERS bit is always
- * kept enabled while there is PI state around. We must also
- * preserve the owner died bit.)
- */
- if (!(uval & FUTEX_OWNER_DIED)) {
- int ret = 0;
-
- newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
-
- if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
- ret = -EFAULT;
- else if (curval != uval)
- ret = -EINVAL;
- if (ret) {
- raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
- return ret;
- }
+ * We pass it to the next owner. The WAITERS bit is always
+ * kept enabled while there is PI state around. We cleanup the
+ * owner died bit, because we are the owner.
+ */
+ newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
+
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
+ ret = -EFAULT;
+ else if (curval != uval)
+ ret = -EINVAL;
+ if (ret) {
+ raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
+ return ret;
}
raw_spin_lock_irq(&pi_state->owner->pi_lock);
@@ -2337,9 +2334,10 @@ retry:
/*
* To avoid races, try to do the TID -> 0 atomic transition
* again. If it succeeds then we can return without waking
- * anyone else up:
+ * anyone else up. We only try this if neither the waiters nor
+ * the owner died bit are set.
*/
- if (!(uval & FUTEX_OWNER_DIED) &&
+ if (!(uval & ~FUTEX_TID_MASK) &&
cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
goto pi_faulted;
/*
@@ -2369,11 +2367,9 @@ retry:
/*
* No waiters - kernel unlocks the futex:
*/
- if (!(uval & FUTEX_OWNER_DIED)) {
- ret = unlock_futex_pi(uaddr, uval);
- if (ret == -EFAULT)
- goto pi_faulted;
- }
+ ret = unlock_futex_pi(uaddr, uval);
+ if (ret == -EFAULT)
+ goto pi_faulted;
out_unlock:
spin_unlock(&hb->lock);

View File

@ -1,309 +0,0 @@
Return-Path: <tglx@linutronix.de>
Received: from Galois.linutronix.de (Galois.linutronix.de
[IPv6:2001:470:1f0b:db:abcd:42:0:1]) by vinyl.outflux.net
(8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id s53CRPJj010831
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for
<kees@outflux.net>; Tue, 3 Jun 2014 05:27:31 -0700
Received: from localhost ([127.0.0.1] helo=[127.0.1.1]) by
Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from
<tglx@linutronix.de>) id 1Wrno5-0002Se-1m; Tue, 03 Jun 2014 14:27:09 +0200
Message-Id: <20140603121945.039282525@linutronix.de>
User-Agent: quilt/0.63-1
Date: Tue, 03 Jun 2014 12:27:08 -0000
From: Thomas Gleixner <tglx@linutronix.de>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Darren Hart <dvhart@linux.intel.com>, Kees Cook <kees@outflux.net>,
"security@kernel.org" <security@kernel.org>, linux-distros@vs.openwall.org,
Sebastian Krahmer <krahmer@suse.de>, Ingo Molnar <mingo@kernel.org>, Kees
Cook <keescook@chromium.org>, Will Drewry <wad@chromium.org>
Subject: [patch 4/4] futex: Make lookup_pi_state more robust
References: <20140603113303.799564413@linutronix.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-15
Content-Disposition: inline; filename=futex-make-lookup-pi-state-more-robust.patch
X-Linutronix-Spam-Score: -1.0
X-Linutronix-Spam-Level: -
X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required,
ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001
Received-SPF: none (linutronix.de: No applicable sender policy available)
receiver=smtp.outflux.net; identity=mailfrom;
envelope-from="tglx@linutronix.de"; helo=Galois.linutronix.de;
client-ip="2001:470:1f0b:db:abcd:42:0:1"
Envelope-To: kees@outflux.net
X-MIMEDefang-Filter: outflux$Revision: 1.316 $
X-HELO: Galois.linutronix.de
X-Spam-Status: No, hits=-0.651 required=5 tests=RP_MATCHES_RCVD
X-Spam-Checker-Version: SpamAssassin 3.4.0-outflux_revision__1.66__
X-Scanned-By: MIMEDefang 2.73
Status: RO
Content-Length: 8955
Lines: 270
The current implementation of lookup_pi_state has ambigous handling of
the TID value 0 in the user space futex. We can get into the kernel
even if the TID value is 0, because either there is a stale waiters
bit or the owner died bit is set or we are called from the requeue_pi
path or from user space just for fun.
The current code avoids an explicit sanity check for pid = 0 in case
that kernel internal state (waiters) are found for the user space
address. This can lead to state leakage and worse under some
circumstances.
Handle the cases explicit:
Waiter | pi_state | pi->owner | uTID | uODIED | ?
[1] NULL | --- | --- | 0 | 0/1 | Valid
[2] NULL | --- | --- | >0 | 0/1 | Valid
[3] Found | NULL | -- | Any | 0/1 | Invalid
[4] Found | Found | NULL | 0 | 1 | Valid
[5] Found | Found | NULL | >0 | 1 | Invalid
[6] Found | Found | task | 0 | 1 | Valid
[7] Found | Found | NULL | Any | 0 | Invalid
[8] Found | Found | task | ==taskTID | 0/1 | Valid
[9] Found | Found | task | 0 | 0 | Invalid
[10] Found | Found | task | !=taskTID | 0/1 | Invalid
[1] Indicates that the kernel can acquire the futex atomically. We
came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
[2] Valid, if TID does not belong to a kernel thread. If no matching
thread is found then it indicates that the owner TID has died.
[3] Invalid. The waiter is queued on a non PI futex
[4] Valid state after exit_robust_list(), which sets the user space
value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
[5] The user space value got manipulated between exit_robust_list()
and exit_pi_state_list()
[6] Valid state after exit_pi_state_list() which sets the new owner in
the pi_state but cannot access the user space value.
[7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
[8] Owner and user space value match
[9] There is no transient state which sets the user space TID to 0
except exit_robust_list(), but this is indicated by the
FUTEX_OWNER_DIED bit. See [4]
[10] There is no transient state which leaves owner and user space
TID out of sync.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: stable@vger.kernel.org
---
kernel/futex.c | 134 +++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 106 insertions(+), 28 deletions(-)
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -729,10 +729,58 @@ void exit_pi_state_list(struct task_stru
raw_spin_unlock_irq(&curr->pi_lock);
}
+/*
+ * We need to check the following states:
+ *
+ * Waiter | pi_state | pi->owner | uTID | uODIED | ?
+ *
+ * [1] NULL | --- | --- | 0 | 0/1 | Valid
+ * [2] NULL | --- | --- | >0 | 0/1 | Valid
+ *
+ * [3] Found | NULL | -- | Any | 0/1 | Invalid
+ *
+ * [4] Found | Found | NULL | 0 | 1 | Valid
+ * [5] Found | Found | NULL | >0 | 1 | Invalid
+ *
+ * [6] Found | Found | task | 0 | 1 | Valid
+ *
+ * [7] Found | Found | NULL | Any | 0 | Invalid
+ *
+ * [8] Found | Found | task | ==taskTID | 0/1 | Valid
+ * [9] Found | Found | task | 0 | 0 | Invalid
+ * [10] Found | Found | task | !=taskTID | 0/1 | Invalid
+ *
+ * [1] Indicates that the kernel can acquire the futex atomically. We
+ * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
+ *
+ * [2] Valid, if TID does not belong to a kernel thread. If no matching
+ * thread is found then it indicates that the owner TID has died.
+ *
+ * [3] Invalid. The waiter is queued on a non PI futex
+ *
+ * [4] Valid state after exit_robust_list(), which sets the user space
+ * value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
+ *
+ * [5] The user space value got manipulated between exit_robust_list()
+ * and exit_pi_state_list()
+ *
+ * [6] Valid state after exit_pi_state_list() which sets the new owner in
+ * the pi_state but cannot access the user space value.
+ *
+ * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
+ *
+ * [8] Owner and user space value match
+ *
+ * [9] There is no transient state which sets the user space TID to 0
+ * except exit_robust_list(), but this is indicated by the
+ * FUTEX_OWNER_DIED bit. See [4]
+ *
+ * [10] There is no transient state which leaves owner and user space
+ * TID out of sync.
+ */
static int
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
- union futex_key *key, struct futex_pi_state **ps,
- struct task_struct *task)
+ union futex_key *key, struct futex_pi_state **ps)
{
struct futex_pi_state *pi_state = NULL;
struct futex_q *this, *next;
@@ -742,12 +790,13 @@ lookup_pi_state(u32 uval, struct futex_h
plist_for_each_entry_safe(this, next, &hb->chain, list) {
if (match_futex(&this->key, key)) {
/*
- * Another waiter already exists - bump up
- * the refcount and return its pi_state:
+ * Sanity check the waiter before increasing
+ * the refcount and attaching to it.
*/
pi_state = this->pi_state;
/*
- * Userspace might have messed up non-PI and PI futexes
+ * Userspace might have messed up non-PI and
+ * PI futexes [3]
*/
if (unlikely(!pi_state))
return -EINVAL;
@@ -755,44 +804,70 @@ lookup_pi_state(u32 uval, struct futex_h
WARN_ON(!atomic_read(&pi_state->refcount));
/*
- * When pi_state->owner is NULL then the owner died
- * and another waiter is on the fly. pi_state->owner
- * is fixed up by the task which acquires
- * pi_state->rt_mutex.
- *
- * We do not check for pid == 0 which can happen when
- * the owner died and robust_list_exit() cleared the
- * TID.
+ * Handle the owner died case:
*/
- if (pid && pi_state->owner) {
+ if (uval & FUTEX_OWNER_DIED) {
/*
- * Bail out if user space manipulated the
- * futex value.
+ * exit_pi_state_list sets owner to NULL and
+ * wakes the topmost waiter. The task which
+ * acquires the pi_state->rt_mutex will fixup
+ * owner.
*/
- if (pid != task_pid_vnr(pi_state->owner))
+ if (!pi_state->owner) {
+ /*
+ * No pi state owner, but the user
+ * space TID is not 0. Inconsistent
+ * state. [5]
+ */
+ if (pid)
+ return -EINVAL;
+ /*
+ * Take a ref on the state and
+ * return. [4]
+ */
+ goto out_state;
+ }
+
+ /*
+ * If TID is 0, then either the dying owner
+ * has not yet executed exit_pi_state_list()
+ * or some waiter acquired the rtmutex in the
+ * pi state, but did not yet fixup the TID in
+ * user space.
+ *
+ * Take a ref on the state and return. [6]
+ */
+ if (!pid)
+ goto out_state;
+ } else {
+ /*
+ * If the owner died bit is not set,
+ * then the pi_state must have an
+ * owner. [7]
+ */
+ if (!pi_state->owner)
return -EINVAL;
}
/*
- * Protect against a corrupted uval. If uval
- * is 0x80000000 then pid is 0 and the waiter
- * bit is set. So the deadlock check in the
- * calling code has failed and we did not fall
- * into the check above due to !pid.
+ * Bail out if user space manipulated the
+ * futex value. If pi state exists then the
+ * owner TID must be the same as the user
+ * space TID. [9/10]
*/
- if (task && pi_state->owner == task)
- return -EDEADLK;
+ if (pid != task_pid_vnr(pi_state->owner))
+ return -EINVAL;
+ out_state:
atomic_inc(&pi_state->refcount);
*ps = pi_state;
-
return 0;
}
}
/*
* We are the first waiter - try to look up the real owner and attach
- * the new pi_state to it, but bail out when TID = 0
+ * the new pi_state to it, but bail out when TID = 0 [1]
*/
if (!pid)
return -ESRCH;
@@ -825,6 +900,9 @@ lookup_pi_state(u32 uval, struct futex_h
return ret;
}
+ /*
+ * No existing pi state. First waiter. [2]
+ */
pi_state = alloc_pi_state();
/*
@@ -945,7 +1023,7 @@ retry:
* We dont have the lock. Look up the PI state (or create it if
* we are the first waiter):
*/
- ret = lookup_pi_state(uval, hb, key, ps, task);
+ ret = lookup_pi_state(uval, hb, key, ps);
if (unlikely(ret)) {
switch (ret) {
@@ -1551,7 +1629,7 @@ retry_private:
* rereading and handing potential crap to
* lookup_pi_state.
*/
- ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL);
+ ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
}
switch (ret) {

View File

@ -1,86 +0,0 @@
Return-Path: <tglx@linutronix.de>
Received: from Galois.linutronix.de (Galois.linutronix.de
[IPv6:2001:470:1f0b:db:abcd:42:0:1]) by vinyl.outflux.net
(8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id s53CRBqO010803
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for
<kees@outflux.net>; Tue, 3 Jun 2014 05:27:17 -0700
Received: from localhost ([127.0.0.1] helo=[127.0.1.1]) by
Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from
<tglx@linutronix.de>) id 1Wrno3-0002SY-Hl; Tue, 03 Jun 2014 14:27:07 +0200
Message-Id: <20140603121944.859726103@linutronix.de>
User-Agent: quilt/0.63-1
Date: Tue, 03 Jun 2014 12:27:06 -0000
From: Thomas Gleixner <tglx@linutronix.de>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Darren Hart <dvhart@linux.intel.com>, Kees Cook <kees@outflux.net>,
"security@kernel.org" <security@kernel.org>, linux-distros@vs.openwall.org,
Sebastian Krahmer <krahmer@suse.de>, Ingo Molnar <mingo@kernel.org>, Kees
Cook <keescook@chromium.org>, Will Drewry <wad@chromium.org>
Subject: [patch 2/4] futex: Validate atomic acquisition in
futex_lock_pi_atomic()
References: <20140603113303.799564413@linutronix.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-15
Content-Disposition: inline; filename=futex-validate-atomic-acquisiton.patch
X-Linutronix-Spam-Score: -1.0
X-Linutronix-Spam-Level: -
X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required,
ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001
Received-SPF: none (linutronix.de: No applicable sender policy available)
receiver=smtp.outflux.net; identity=mailfrom;
envelope-from="tglx@linutronix.de"; helo=Galois.linutronix.de;
client-ip="2001:470:1f0b:db:abcd:42:0:1"
Envelope-To: kees@outflux.net
X-MIMEDefang-Filter: outflux$Revision: 1.316 $
X-HELO: Galois.linutronix.de
X-Spam-Status: No, hits=-0.651 required=5 tests=RP_MATCHES_RCVD
X-Spam-Checker-Version: SpamAssassin 3.4.0-outflux_revision__1.66__
X-Scanned-By: MIMEDefang 2.73
Content-Length: 1615
Lines: 47
We need to protect the atomic acquisition in the kernel against rogue
user space which sets the user space futex to 0, so the kernel side
acquisition succeeds while there is existing state in the kernel
associated to the real owner.
Verify whether the futex has waiters associated with kernel state. If
it has, return -EINVAL. The state is corrupted already, so no point in
cleaning it up. Subsequent calls will fail as well. Not our problem.
[ tglx: Use futex_top_waiter() and explain why we do not need to try
restoring the already corrupted user space state. ]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/futex.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -896,10 +896,18 @@ retry:
return -EDEADLK;
/*
- * Surprise - we got the lock. Just return to userspace:
+ * Surprise - we got the lock, but we do not trust user space at all.
*/
- if (unlikely(!curval))
- return 1;
+ if (unlikely(!curval)) {
+ /*
+ * We verify whether there is kernel state for this
+ * futex. If not, we can safely assume, that the 0 ->
+ * TID transition is correct. If state exists, we do
+ * not bother to fixup the user space state as it was
+ * corrupted already.
+ */
+ return futex_top_waiter(hb, key) ? -EINVAL : 1;
+ }
uval = curval;

View File

@ -1,113 +0,0 @@
Return-Path: <tglx@linutronix.de>
Received: from Galois.linutronix.de (Galois.linutronix.de
[IPv6:2001:470:1f0b:db:abcd:42:0:1]) by vinyl.outflux.net
(8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id s53CRBLI010804
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for
<kees@outflux.net>; Tue, 3 Jun 2014 05:27:17 -0700
Received: from localhost ([127.0.0.1] helo=[127.0.1.1]) by
Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from
<tglx@linutronix.de>) id 1Wrno2-0002SV-Po; Tue, 03 Jun 2014 14:27:06 +0200
Message-Id: <20140603121944.770732571@linutronix.de>
User-Agent: quilt/0.63-1
Date: Tue, 03 Jun 2014 12:27:06 -0000
From: Thomas Gleixner <tglx@linutronix.de>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Darren Hart <dvhart@linux.intel.com>, Kees Cook <kees@outflux.net>,
"security@kernel.org" <security@kernel.org>, linux-distros@vs.openwall.org,
Sebastian Krahmer <krahmer@suse.de>, Ingo Molnar <mingo@kernel.org>, Will
Drewry <wad@chromium.org>, Kees Cook <keescook@chromium.org>
Subject: [patch 1/4] futex-prevent-requeue-pi-on-same-futex.patch futex:
Forbid uaddr == uaddr2 in futex_requeue(..., requeue_pi=1)
References: <20140603113303.799564413@linutronix.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-15
Content-Disposition: inline; filename=futex-prevent-requeue-pi-on-same-futex.patch
X-Linutronix-Spam-Score: -1.0
X-Linutronix-Spam-Level: -
X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required,
ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001
Received-SPF: none (linutronix.de: No applicable sender policy available)
receiver=smtp.outflux.net; identity=mailfrom;
envelope-from="tglx@linutronix.de"; helo=Galois.linutronix.de;
client-ip="2001:470:1f0b:db:abcd:42:0:1"
Envelope-To: kees@outflux.net
X-MIMEDefang-Filter: outflux$Revision: 1.316 $
X-HELO: Galois.linutronix.de
X-Spam-Status: No, hits=-0.651 required=5 tests=RP_MATCHES_RCVD
X-Spam-Checker-Version: SpamAssassin 3.4.0-outflux_revision__1.66__
X-Scanned-By: MIMEDefang 2.73
Status: RO
Content-Length: 2114
Lines: 73
If uaddr == uaddr2, then we have broken the rule of only requeueing
from a non-pi futex to a pi futex with this call. If we attempt this,
then dangling pointers may be left for rt_waiter resulting in an
exploitable condition.
This change brings futex_requeue() into line with
futex_wait_requeue_pi() which performs the same check as per commit
6f7b0a2a5 (futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi())
[ tglx: Compare the resulting keys as well, as uaddrs might be
different depending on the mapping ]
Fixes CVE-2014-3153.
Reported-by: Pinkie Pie
Signed-off-by: Will Drewry <wad@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/futex.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1428,6 +1428,13 @@ static int futex_requeue(u32 __user *uad
if (requeue_pi) {
/*
+ * Requeue PI only works on two distinct uaddrs. This
+ * check is only valid for private futexes. See below.
+ */
+ if (uaddr1 == uaddr2)
+ return -EINVAL;
+
+ /*
* requeue_pi requires a pi_state, try to allocate it now
* without any locks in case it fails.
*/
@@ -1465,6 +1472,15 @@ retry:
if (unlikely(ret != 0))
goto out_put_key1;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (requeue_pi && match_futex(&key1, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
hb1 = hash_futex(&key1);
hb2 = hash_futex(&key2);
@@ -2511,6 +2527,15 @@ static int futex_wait_requeue_pi(u32 __u
if (ret)
goto out_key2;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (match_futex(&q.key, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
futex_wait_queue_me(hb, &q, to);

View File

@ -62,8 +62,6 @@ bugfix/m68k/ethernat-kconfig.patch
bugfix/all/misc-bmp085-Enable-building-as-a-module.patch
bugfix/all/kbuild-use-nostdinc-in-compile-tests.patch
bugfix/all/disable-some-marvell-phys.patch
bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch
bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch
# Miscellaneous features
features/all/x86-memtest-WARN-if-bad-RAM-found.patch
@ -94,11 +92,5 @@ features/arm/ARM-dts-sun5i-Add-reg_vcc3v3-to-sun5i-board-mmc-node.patch
features/arm/ARM-dts-sun6i-Add-reg_vcc3v3-to-sun6i-board-mmc-node.patch
features/arm/ARM-dts-sun7i-Add-reg_vcc3v3-to-sun7i-board-mmc-node.patch
features/arm/ARM-dts-sun7i-cubietruck-set-mmc3-bus-width-property.patch
bugfix/all/futex-prevent-requeue-pi-on-same-futex.patch
bugfix/all/futex-Validate-atomic-acquisition-in-futex_lock_pi_atomic.patch
bugfix/all/futex-Always-cleanup-owner-tid-in-unlock_pi.patch
# bugfix/all/futex-Make-lookup_pi_state-more-robust.patch
features/arm/ARM-dts-imx6qdl-wandboard-Add-HDMI-support.patch
features/arm/ARM-imx-add-HDMI-support-for-SolidRun-HummingBoard-a.patch