lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250110200508.353290-5-andrealmeid@igalia.com>
Date: Fri, 10 Jan 2025 17:05:08 -0300
From: André Almeida <andrealmeid@...lia.com>
To: Thomas Gleixner <tglx@...utronix.de>,
	Ingo Molnar <mingo@...hat.com>,
	Peter Zijlstra <peterz@...radead.org>,
	Darren Hart <dvhart@...radead.org>,
	Davidlohr Bueso <dave@...olabs.net>,
	Arnd Bergmann <arnd@...db.de>,
	Florian Weimer <fweimer@...hat.com>
Cc: linux-kernel@...r.kernel.org,
	kernel-dev@...lia.com,
	Vinicius Peixoto <vpeixoto@...amp.dev>,
	André Almeida <andrealmeid@...lia.com>
Subject: [PATCH 4/4] selftests/futex: Create tests for long and circular robust lists

After dropping ROBUST_LIST_LIMIT, create new robust list tests to ensure
two conditions:

 - That the kernel can correctly handle circular lists
 - That the kernel can correctly wake up elements in very long lists,
   larger that the old ROBUST_LIST_LIMIT.

Signed-off-by: André Almeida <andrealmeid@...lia.com>
---
 .../selftests/futex/functional/robust_list.c  | 127 +++++++++++++++++-
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index bd4437c6aebb..4bd6795b3ac5 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -471,6 +471,128 @@ static void test_robust_list_multiple_elements(void)
 	ksft_test_result_pass("%s\n", __func__);
 }
 
+/*
+ * This is the old limit defined by the kernel
+ */
+#define ROBUST_LIST_LIMIT	2048
+#define CHILD_LIST_LIMIT (ROBUST_LIST_LIMIT + 10)
+
+static int child_robust_list_limit(void *arg)
+{
+	struct lock_struct *locks;
+	struct robust_list *list;
+	struct robust_list_head head;
+	int ret, i;
+
+	locks = (struct lock_struct *) arg;
+
+	ret = set_list(&head);
+	if (ret)
+		ksft_test_result_fail("set_list error\n");
+
+	/*
+	 * Create a very long list of locks
+	 */
+	head.list.next = &locks[0].list;
+
+	list = head.list.next;
+	for (i = 0; i < CHILD_LIST_LIMIT - 1; i++) {
+		list->next = &locks[i+1].list;
+		list = list->next;
+	}
+	list->next = &head.list;
+
+	/*
+	 * Grab the lock in the last one, and die without releasing it
+	 */
+	mutex_lock(&locks[CHILD_LIST_LIMIT], &head, false);
+	pthread_barrier_wait(&barrier);
+
+	sleep(1);
+
+	return 0;
+}
+
+/*
+ * Robust list used to have a limit of 2048 items from the kernel side. After
+ * this limit the kernel would stop walking the list and ignore the other
+ * futexes, causing deadlocks.
+ *
+ * After this limit has been dropped, test if we can wait for a list of more
+ * than 2048 elements.
+ */
+static void test_robust_list_limit(void)
+{
+	struct lock_struct locks[CHILD_LIST_LIMIT + 1];
+	_Atomic(unsigned int) *futex = &locks[CHILD_LIST_LIMIT].futex;
+	struct robust_list_head head;
+	int ret;
+
+	*futex = 0;
+
+	ret = set_list(&head);
+	ASSERT_EQ(ret, 0);
+
+	ret = pthread_barrier_init(&barrier, NULL, 2);
+	ASSERT_EQ(ret, 0);
+
+	create_child(child_robust_list_limit, locks);
+
+	/*
+	 * After the child thread creates the very long list of locks, wait on
+	 * the last one.
+	 */
+	pthread_barrier_wait(&barrier);
+	ret = mutex_lock(&locks[CHILD_LIST_LIMIT], &head, false);
+
+	if (ret != 0)
+		printf("futex wait returned %d\n", errno);
+	ASSERT_EQ(ret, 0);
+
+	ASSERT_TRUE(*futex | FUTEX_OWNER_DIED);
+
+	wait(NULL);
+	pthread_barrier_destroy(&barrier);
+
+	ksft_test_result_pass("%s\n", __func__);
+}
+
+static int child_circular_list(void *arg)
+{
+	static struct robust_list_head head;
+	struct lock_struct a, b, c;
+	int ret;
+
+	ret = set_list(&head);
+	if (ret)
+		ksft_test_result_fail("set_list error\n");
+
+	head.list.next = &a.list;
+
+	/*
+	 * The last element should point to head list, but we short circuit it
+	 */
+	a.list.next = &b.list;
+	b.list.next = &c.list;
+	c.list.next = &a.list;
+
+	return 0;
+}
+
+/*
+ * Create a circular robust list. The kernel should be able to destroy the list
+ * while processing it so it won't be trapped in an infinite loop while handling
+ * a process exit
+ */
+static void test_circular_list(void)
+{
+	create_child(child_circular_list, NULL);
+
+	wait(NULL);
+
+	ksft_test_result_pass("%s\n", __func__);
+}
+
 void usage(char *prog)
 {
 	printf("Usage: %s\n", prog);
@@ -502,14 +624,17 @@ int main(int argc, char *argv[])
 	}
 
 	ksft_print_header();
-	ksft_set_plan(6);
+	ksft_set_plan(8);
 
 	test_robustness();
+
 	test_set_robust_list_invalid_size();
 	test_get_robust_list_self();
 	test_get_robust_list_child();
 	test_set_list_op_pending();
 	test_robust_list_multiple_elements();
+	test_robust_list_limit();
+	test_circular_list();
 
 	ksft_print_cnts();
 	return 0;
-- 
2.47.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ