From nobody Sun Apr 5 16:26:20 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BED4D2F5A1F; Fri, 20 Feb 2026 20:27:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771619263; cv=none; b=LS4Lm4b6HZE23vXjo4acUGOrxvBLFCle0fG5/cj/F7c8/Qh6aIEzYwAUhhF6qNR2FhzYfu7VLzzx3n1MXAdKc1lLdQ1UAxHEI2QQeNv1NI/VUewnIivO1IC3k9abWOpZU2KfDP1zOaL0eMDwNGp62OEFjg2RGDWAVtVe0NZurxk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771619263; c=relaxed/simple; bh=zQ90A7PhGI/vVQKatiddeLn00Z5zIy+RVunNVR9GD1E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YunF4/ufzJogaNt1/SvBER6v6IpKZ1XfG6aMPZcZNwZ8Mxvyi0VuTK5kgC+CYDxNVjmuS2f3VVp7mlSW7yO2zQDWOXxehJ8gnIEz99oah3h2oKhNRJYOMcSY3VvL45Xai6Zol5D/QQBory6SOOB4mD3qUeUkh93uwTnMmbUCYFk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=NszLq8Sj; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="NszLq8Sj" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=IniDsBH2iOsUsO3hzLdsQgJJn816ZqQiEcTVLPFvY6o=; b=NszLq8SjJiZuYARE6nJ0AD49TG 6RvTWqS2bd9SnNzCMpod8tay+TWaXoixUlLKTV9gCzqyG+dWbBmIL+Md/nOq+LEHJZEvQs7l2XFs1 kqSDsXtmpv9DCPJvVIXztTo/+9qml5jdhzMXRMKZqBlNshVqn4gIm1L9ipLqmYuqgrjWt90p7LuCW aYQtreWiTTRQeegD1BhK/w7njav7oSgIUtpJzZkmbagTAA7m5lqnB5dByFXarZCK+GSgzZmEzSuKF fPINf/0zQWkq6ZswiL5nRps8RFkdjJ0lHpjNje00uVB4gLCxjQDHgY8q1XCQ0xh6kCIf2FeK/EiqP ktsoo62g==; Received: from [187.57.77.133] (helo=computador) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1vtX5H-0036Zi-JX; Fri, 20 Feb 2026 21:26:44 +0100 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= To: Carlos O'Donell , Sebastian Andrzej Siewior , Peter Zijlstra , Florian Weimer , Rich Felker , Torvald Riegel , Darren Hart , Thomas Gleixner , Ingo Molnar , Davidlohr Bueso , Arnd Bergmann , Mathieu Desnoyers , "Liam R . Howlett" Cc: kernel-dev@igalia.com, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= Subject: [RFC PATCH 1/2] futex: Create reproducer for robust_list race condition Date: Fri, 20 Feb 2026 17:26:19 -0300 Message-ID: <20260220202620.139584-2-andrealmeid@igalia.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260220202620.139584-1-andrealmeid@igalia.com> References: <20260220202620.139584-1-andrealmeid@igalia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Create a reproducer for https://sourceware.org/bugzilla/show_bug.cgi?id=3D1= 4485 This is not supposed to be merged. Signed-off-by: Andr=C3=A9 Almeida --- robust_bug.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 robust_bug.c diff --git a/robust_bug.c b/robust_bug.c new file mode 100644 index 000000000000..1ade4e6d66dd --- /dev/null +++ b/robust_bug.c @@ -0,0 +1,178 @@ +/* + * gcc robust_bug.c -o robust_bug + * + * This is a reproducer for "File corruption race condition in robust + * mutex unlocking" from https://sourceware.org/bugzilla/show_bug.cgi?id= =3D14485 + * + * To increase the changes of reaching the race condition, a delay can be = added + * to the kernel function handle_futex_death(), just before the user memory + * write futex_cmpxchg_value_locked(). + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define cpu_relax() asm volatile("rep; nop"); + +/* + * This struct is an example of a lock struct, shared between the threads. + */ +struct lock_struct { + uint32_t futex; + struct robust_list list; +}; + +static struct lock_struct *lock; + +/* + * This is the struct that we are going to use to allocate on top of the=20 + * freed memory to observe the race condition. + */ +struct another_struct { + uint64_t value; +}; + +static pthread_barrier_t barrier; + +static int set_robust_list(struct robust_list_head *head) +{ + return syscall(SYS_set_robust_list, head, sizeof(*head)); +} + +/* + * This thread emulates the behaviour of a thread releasing a robust mutex: + * - It starts by adding the mutex to the op_pending field + * - Remove the mutex from the robust list + * - Release the lock and wake up waiters + * - Remove the mutex from the op_pending field + * + * However, this thread dies before doing this last step, leaving the mutex + * behind in the op_pending field. + */ +void *func_b(void *arg) +{ + static struct robust_list_head head; + pid_t tid =3D gettid() | FUTEX_WAITERS; + + /* + * Initial thread setup. This would happen in an earlier stage of the + * thread execution. + */ + set_robust_list(&head); + head.list.next =3D &head.list; + head.futex_offset =3D (size_t) offsetof(struct lock_struct, futex) - + (size_t) offsetof(struct lock_struct, list); + + /* This thread takes the lock... */ + lock->futex =3D tid; + + /* ...would do some work here... */ + + /* + * ...and starts the release process. Adds the mutex to be released on + * the op_pending. + */ + head.list_op_pending =3D &lock->list; + + /* Barrier to synchronize thread B taking the lock */ + pthread_barrier_wait(&barrier); + usleep(100); + + /* + * Here we would release the lock and wake up any waiters. + * + * lock->futex =3D LOCK_FREE; + * futex_wake(lock->futex, 1); + */ + + /* + * We would remove the lock from op_pending, but we emulate a thread + * exiting before doing it. + */ + return NULL; +} + +int main(int argc, char *argv[]) +{ + struct another_struct *new; + uint64_t original_val; + pthread_t thread_b; + uint32_t value; + int ret; + + ret =3D pthread_barrier_init(&barrier, NULL, 2); + if (ret) { + puts("pthread_barrier_init failed"); + return -1; + } + + /* Initialize the lock */ + lock =3D mmap(NULL, sizeof(struct lock_struct), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (lock =3D=3D MAP_FAILED) { + puts("mmap failed"); + return -1; + } + memset(lock, 0, sizeof(*lock)); + + /* Create the thread B that will take the lock */ + pthread_create(&thread_b, NULL, func_b, NULL); + + /* Barrier to synchronize thread B taking the lock */ + pthread_barrier_wait(&barrier); + + /* Copy this value as we will use it later */ + value =3D lock->futex; + + /* + * Here, this thread would do the following: + * - It would wait for the lock, and be wake from thread B + * - Take the lock, do some work, and release it + * - After releasing the lock and being the last user, it can correctly + * free it + */ + munmap(lock, sizeof(struct lock_struct)); + + /* + * After freeing the lock, this thread allocates memory, which + * happens to be at the same address of the lock, and by chance, it fills + * the memory with the TID of thread B. + */ + new =3D mmap(NULL, sizeof(struct another_struct), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (new =3D=3D MAP_FAILED) { + puts("mmap failed"); + return -1; + } + if ((uintptr_t) lock !=3D (uintptr_t) new) { + puts("mmap got a different address"); + return -1; + } + + new->value =3D ((uint64_t) value << 32) + value; + + /* Create a backup of the current value */ + original_val =3D new->value; + + /* Wait for the memory corruption to happen... */=09 + while (new->value =3D=3D original_val) + cpu_relax(); + + /* ...and now the kernel just overwrote an unrelated user memory! */ + printf("Memory was corrupted by the kernel: %lx vs %lx\n", + original_val, new->value); + + munmap(new, sizeof(struct another_struct)); + + return 0; +} --=20 2.53.0 From nobody Sun Apr 5 16:26:20 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BEDC72FB99A; Fri, 20 Feb 2026 20:27:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771619263; cv=none; b=EViYmEZJGctlGCGImb9zVcHxY8WKkI5DDqWkRVdnFWgmY18IiYL5iWI48tlHvfZsErN0QWRQ1/j50Jmf73l/vnAq2GUNAA5TroEUX/FPuBNAmZuNVGvdEG4Ry7HR36m23a9WYE5olOmUSomW1XeT8oGpschN63ErqmGLVSGmHAE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771619263; c=relaxed/simple; bh=qfgc6WxgjzSuKeiRpMAd9MocMsWaTgKveADr+1kuvD0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iVSE4hh/KMKuNfFx5hesuEpnzfNXManPmGUiqGUtjDdTpYzFrhhE6f7A304fdAH490kQx1/r3kCn64ovztIi/VT1ZqVDkeNRey2/ZHnBf231D3BoSLPte9xK96tWlbr4YlR5d3pR5RMM7HEWZgb7Kbi7a4s0nkmI1SIAQdR/WJw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=ZBYl1FzM; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="ZBYl1FzM" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=C+xTVEgi7UaEFZNNdjOZRbwxjimZapcq1Tyr+3xwoD0=; b=ZBYl1FzM8ozc332kzDFs/B8ewN CUcvOudwg1CzmbUdjKiSbVazSeY6VIAX9nN9NWHHZ5lq0dlTeYTeRuoZpdtuLihLH9ov+Fzx9VvZj l4VFzgmI7ICTxjEonq3kI8n57EW1ejl66OGatFXqRrxat4Luh1hVTfqX6j5qYjyBx60sDzDfVKzAj phSduiAiU6nqjc45mOVJv1TDWjves5gYEFJoPLVJkBNrRHG2qLRBZtAnzSFe0YZp10ErTk1KVceyc dUwNdMTFJ3zfhDe/6btOIETDrfrG/GcAYXYJt4W6rsE1DMJX1YiVI9Kmidhjw8XibH2Sk6lJdnV2H s8OMQb7g==; Received: from [187.57.77.133] (helo=computador) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1vtX5L-0036Zi-PD; Fri, 20 Feb 2026 21:26:48 +0100 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= To: Carlos O'Donell , Sebastian Andrzej Siewior , Peter Zijlstra , Florian Weimer , Rich Felker , Torvald Riegel , Darren Hart , Thomas Gleixner , Ingo Molnar , Davidlohr Bueso , Arnd Bergmann , Mathieu Desnoyers , "Liam R . Howlett" Cc: kernel-dev@igalia.com, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= Subject: [RFC PATCH 2/2] futex: hack: Add debug delays Date: Fri, 20 Feb 2026 17:26:20 -0300 Message-ID: <20260220202620.139584-3-andrealmeid@igalia.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260220202620.139584-1-andrealmeid@igalia.com> References: <20260220202620.139584-1-andrealmeid@igalia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add delays to handle_futex_death() to increase the chance of hitting the ra= ce condition. Signed-off-by: Andr=C3=A9 Almeida --- kernel/futex/core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/futex/core.c b/kernel/futex/core.c index cf7e610eac42..d409b3368cb3 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -44,6 +44,7 @@ #include #include #include +#include =20 #include "futex.h" #include "../locking/rtmutex_common.h" @@ -1095,6 +1096,12 @@ static int handle_futex_death(u32 __user *uaddr, str= uct task_struct *curr, * does not guarantee R/W access. If that fails we * give up and leave the futex locked. */ + + if (!strcmp(current->comm, "robust_bug")) { + printk("robust_bug is exiting\n"); + msleep(500); + } + if ((err =3D futex_cmpxchg_value_locked(&nval, uaddr, uval, mval))) { switch (err) { case -EFAULT: @@ -1112,6 +1119,9 @@ static int handle_futex_death(u32 __user *uaddr, stru= ct task_struct *curr, } } =20 + if (!strcmp(current->comm, "robust_bug")) + printk("memory written\n"); + if (nval !=3D uval) goto retry; =20 --=20 2.53.0