futex: Ensure that futex address is aligned in handle_futex_death() [Linux 3.16.72]

This Linux kernel change "futex: Ensure that futex address is aligned in handle_futex_death()" is included in the Linux 3.16.72 release. This change is authored by Chen Jie <chenjie6 [at] huawei.com> on Fri Mar 15 03:44:38 2019 +0000. The commit for this change in Linux stable tree is c5f75dd (patch) which is from upstream commit 5a07168. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 5a07168.

futex: Ensure that futex address is aligned in handle_futex_death()

commit 5a07168d8d89b00fe1760120714378175b3ef992 upstream.

The futex code requires that the user space addresses of futexes are 32bit
aligned. sys_futex() checks this in futex_get_keys() but the robust list
code has no alignment check in place.

As a consequence the kernel crashes on architectures with strict alignment
requirements in handle_futex_death() when trying to cmpxchg() on an
unaligned futex address which was retrieved from the robust list.

[ tglx: Rewrote changelog, proper sizeof() based alignement check and add
    comment ]

Fixes: 0771dfefc9e5 ("[PATCH] lightweight robust futexes: core")
Signed-off-by: Chen Jie <chenjie6@huawei.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: <dvhart@infradead.org>
Cc: <peterz@infradead.org>
Cc: <zengweilin@huawei.com>
Link: https://lkml.kernel.org/r/1552621478-119787-1-git-send-email-chenjie6@huawei.com
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>

There are 4 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 kernel/futex.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/futex.c b/kernel/futex.c
index 0ee2f54..99679c0 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2909,6 +2909,10 @@ int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
    u32 uval, uninitialized_var(nval), mval;

+   /* Futex address must be 32bit aligned */
+   if ((((unsigned long)uaddr) % sizeof(*uaddr)) != 0)
+       return -1;
    if (get_user(uval, uaddr))
        return -1;

Leave a Reply

Your email address will not be published. Required fields are marked *