1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
4 * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
5 */
6
7/*\
8 * [Description]
9 *
10 * Tests basic error handling of the pidfd_open syscall.
11 *
12 * - EBADF pidfd is not a valid PID file descriptor
13 * - EBADF targetfd is not an open file descriptor in the process referred
14 *   to by pidfd
15 * - EINVAL flags is not 0
16 * - ESRCH the process referred to by pidfd does not exist (it has terminated
17 *   and been waited on)
18 * - EPERM the calling process doesn't have PTRACE_MODE_ATTACH_REALCREDS permissions
19 *   over the process referred to by pidfd
20 */
21
22#include <stdlib.h>
23#include <pwd.h>
24#include "tst_test.h"
25#include "tst_safe_macros.h"
26#include "lapi/pidfd.h"
27
28static int valid_pidfd = -1, invalid_pidfd = -1, pidfd = -1;
29static uid_t uid;
30
31static struct tcase {
32	char *name;
33	int *pidfd;
34	int targetfd;
35	int flags;
36	int exp_errno;
37} tcases[] = {
38	{"invalid pidfd", &invalid_pidfd, 0, 0, EBADF},
39	{"invalid targetfd", &valid_pidfd, -1, 0, EBADF},
40	{"invalid flags", &valid_pidfd, 0, 1, EINVAL},
41	{"the process referred to by pidfd doesn't exist", NULL, 0, 0, ESRCH},
42	{"lack of required permission", &valid_pidfd, 0, 0, EPERM},
43};
44
45static void setup(void)
46{
47	pidfd_open_supported();
48	pidfd_getfd_supported();
49
50	struct passwd *pw;
51
52	pw = SAFE_GETPWNAM("nobody");
53	uid = pw->pw_uid;
54
55	valid_pidfd = SAFE_PIDFD_OPEN(getpid(), 0);
56}
57
58static void cleanup(void)
59{
60	if (valid_pidfd > -1)
61		SAFE_CLOSE(valid_pidfd);
62	if (pidfd > -1)
63		SAFE_CLOSE(pidfd);
64}
65
66static void run(unsigned int n)
67{
68	struct tcase *tc = &tcases[n];
69	int pid;
70
71	if (tc->exp_errno == EPERM) {
72		pid = SAFE_FORK();
73		if (!pid) {
74			SAFE_SETUID(uid);
75			TST_EXP_FAIL2(pidfd_getfd(valid_pidfd, tc->targetfd, tc->flags),
76				tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
77				valid_pidfd, tc->targetfd, tc->flags, tc->name);
78			TST_CHECKPOINT_WAKE(0);
79			exit(0);
80		}
81		TST_CHECKPOINT_WAIT(0);
82		SAFE_WAIT(NULL);
83		return;
84	} else if (tc->exp_errno == ESRCH) {
85		pid = SAFE_FORK();
86		if (!pid) {
87			TST_CHECKPOINT_WAIT(0);
88			exit(0);
89		}
90		pidfd = SAFE_PIDFD_OPEN(pid, 0);
91		TST_CHECKPOINT_WAKE(0);
92		SAFE_WAIT(NULL);
93		TST_EXP_FAIL2(pidfd_getfd(pidfd, tc->targetfd, tc->flags),
94			tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
95			pidfd, tc->targetfd, tc->flags, tc->name);
96		SAFE_CLOSE(pidfd);
97	} else	{
98		TST_EXP_FAIL2(pidfd_getfd(*tc->pidfd, tc->targetfd, tc->flags),
99			tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
100			*tc->pidfd, tc->targetfd, tc->flags, tc->name);
101	}
102}
103
104static struct tst_test test = {
105	.tcnt = ARRAY_SIZE(tcases),
106	.test = run,
107	.setup = setup,
108	.cleanup = cleanup,
109	.needs_root = 1,
110	.forks_child = 1,
111	.needs_checkpoints = 1,
112};
113