162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2020 Bernd Edlinger <bernd.edlinger@hotmail.de>
462306a36Sopenharmony_ci * All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Check whether /proc/$pid/mem can be accessed without causing deadlocks
762306a36Sopenharmony_ci * when de_thread is blocked with ->cred_guard_mutex held.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "../kselftest_harness.h"
1162306a36Sopenharmony_ci#include <stdio.h>
1262306a36Sopenharmony_ci#include <fcntl.h>
1362306a36Sopenharmony_ci#include <pthread.h>
1462306a36Sopenharmony_ci#include <signal.h>
1562306a36Sopenharmony_ci#include <unistd.h>
1662306a36Sopenharmony_ci#include <sys/ptrace.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic void *thread(void *arg)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	ptrace(PTRACE_TRACEME, 0, 0L, 0L);
2162306a36Sopenharmony_ci	return NULL;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciTEST(vmaccess)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int f, pid = fork();
2762306a36Sopenharmony_ci	char mm[64];
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (!pid) {
3062306a36Sopenharmony_ci		pthread_t pt;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		pthread_create(&pt, NULL, thread, NULL);
3362306a36Sopenharmony_ci		pthread_join(pt, NULL);
3462306a36Sopenharmony_ci		execlp("true", "true", NULL);
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	sleep(1);
3862306a36Sopenharmony_ci	sprintf(mm, "/proc/%d/mem", pid);
3962306a36Sopenharmony_ci	f = open(mm, O_RDONLY);
4062306a36Sopenharmony_ci	ASSERT_GE(f, 0);
4162306a36Sopenharmony_ci	close(f);
4262306a36Sopenharmony_ci	f = kill(pid, SIGCONT);
4362306a36Sopenharmony_ci	ASSERT_EQ(f, 0);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciTEST(attach)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int s, k, pid = fork();
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!pid) {
5162306a36Sopenharmony_ci		pthread_t pt;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		pthread_create(&pt, NULL, thread, NULL);
5462306a36Sopenharmony_ci		pthread_join(pt, NULL);
5562306a36Sopenharmony_ci		execlp("sleep", "sleep", "2", NULL);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	sleep(1);
5962306a36Sopenharmony_ci	k = ptrace(PTRACE_ATTACH, pid, 0L, 0L);
6062306a36Sopenharmony_ci	ASSERT_EQ(errno, EAGAIN);
6162306a36Sopenharmony_ci	ASSERT_EQ(k, -1);
6262306a36Sopenharmony_ci	k = waitpid(-1, &s, WNOHANG);
6362306a36Sopenharmony_ci	ASSERT_NE(k, -1);
6462306a36Sopenharmony_ci	ASSERT_NE(k, 0);
6562306a36Sopenharmony_ci	ASSERT_NE(k, pid);
6662306a36Sopenharmony_ci	ASSERT_EQ(WIFEXITED(s), 1);
6762306a36Sopenharmony_ci	ASSERT_EQ(WEXITSTATUS(s), 0);
6862306a36Sopenharmony_ci	sleep(1);
6962306a36Sopenharmony_ci	k = ptrace(PTRACE_ATTACH, pid, 0L, 0L);
7062306a36Sopenharmony_ci	ASSERT_EQ(k, 0);
7162306a36Sopenharmony_ci	k = waitpid(-1, &s, 0);
7262306a36Sopenharmony_ci	ASSERT_EQ(k, pid);
7362306a36Sopenharmony_ci	ASSERT_EQ(WIFSTOPPED(s), 1);
7462306a36Sopenharmony_ci	ASSERT_EQ(WSTOPSIG(s), SIGSTOP);
7562306a36Sopenharmony_ci	k = ptrace(PTRACE_DETACH, pid, 0L, 0L);
7662306a36Sopenharmony_ci	ASSERT_EQ(k, 0);
7762306a36Sopenharmony_ci	k = waitpid(-1, &s, 0);
7862306a36Sopenharmony_ci	ASSERT_EQ(k, pid);
7962306a36Sopenharmony_ci	ASSERT_EQ(WIFEXITED(s), 1);
8062306a36Sopenharmony_ci	ASSERT_EQ(WEXITSTATUS(s), 0);
8162306a36Sopenharmony_ci	k = waitpid(-1, NULL, 0);
8262306a36Sopenharmony_ci	ASSERT_EQ(k, -1);
8362306a36Sopenharmony_ci	ASSERT_EQ(errno, ECHILD);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciTEST_HARNESS_MAIN
87