ACK: [T SRU][PATCH] timerfd: Protect the might cancel mechanism proper
Stefan Bader
stefan.bader at canonical.com
Thu Oct 5 06:47:44 UTC 2017
On 02.10.2017 16:07, Shrirang Bagul wrote:
> From: Thomas Gleixner <tglx at linutronix.de>
>
> The handling of the might_cancel queueing is not properly protected, so
> parallel operations on the file descriptor can race with each other and
> lead to list corruptions or use after free.
>
> Protect the context for these operations with a seperate lock.
>
> The wait queue lock cannot be reused for this because that would create a
> lock inversion scenario vs. the cancel lock. Replacing might_cancel with an
> atomic (atomic_t or atomic bit) does not help either because it still can
> race vs. the actual list operation.
>
> Reported-by: Dmitry Vyukov <dvyukov at google.com>
> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
> Cc: "linux-fsdevel at vger.kernel.org"
> Cc: syzkaller <syzkaller at googlegroups.com>
> Cc: Al Viro <viro at zeniv.linux.org.uk>
> Cc: linux-fsdevel at vger.kernel.org
> Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1701311521430.3457@nanos
> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
>
> This fixes CVE-2017-10661
>
> (cherry picked from commit 1e38da300e1e395a15048b0af1e5305bd91402f6)
> Signed-off-by: Shrirang Bagul <shrirang.bagul at canonical.com>
Acked-by: Stefan Bader <stefan.bader at canonical.com>
> ---
> fs/timerfd.c | 17 ++++++++++++++---
> 1 file changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/fs/timerfd.c b/fs/timerfd.c
> index 929312180dd0..4ed3c8c0c24c 100644
> --- a/fs/timerfd.c
> +++ b/fs/timerfd.c
> @@ -39,6 +39,7 @@ struct timerfd_ctx {
> int clockid;
> struct rcu_head rcu;
> struct list_head clist;
> + spinlock_t cancel_lock;
> bool might_cancel;
> };
>
> @@ -111,7 +112,7 @@ void timerfd_clock_was_set(void)
> rcu_read_unlock();
> }
>
> -static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
> +static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
> {
> if (ctx->might_cancel) {
> ctx->might_cancel = false;
> @@ -121,6 +122,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
> }
> }
>
> +static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
> +{
> + spin_lock(&ctx->cancel_lock);
> + __timerfd_remove_cancel(ctx);
> + spin_unlock(&ctx->cancel_lock);
> +}
> +
> static bool timerfd_canceled(struct timerfd_ctx *ctx)
> {
> if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
> @@ -131,6 +139,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)
>
> static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
> {
> + spin_lock(&ctx->cancel_lock);
> if ((ctx->clockid == CLOCK_REALTIME ||
> ctx->clockid == CLOCK_REALTIME_ALARM) &&
> (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
> @@ -140,9 +149,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
> list_add_rcu(&ctx->clist, &cancel_list);
> spin_unlock(&cancel_lock);
> }
> - } else if (ctx->might_cancel) {
> - timerfd_remove_cancel(ctx);
> + } else {
> + __timerfd_remove_cancel(ctx);
> }
> + spin_unlock(&ctx->cancel_lock);
> }
>
> static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
> @@ -325,6 +335,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
> return -ENOMEM;
>
> init_waitqueue_head(&ctx->wqh);
> + spin_lock_init(&ctx->cancel_lock);
> ctx->clockid = clockid;
>
> if (isalarm(ctx))
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20171005/b2049684/attachment.sig>
More information about the kernel-team
mailing list