1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 SUSE LLC
4  * Author: Christian Amann <camann@suse.com>
5  */
6 /*
7  * Tests basic error handling of the pidfd_send_signal
8  * system call.
9  *
10  * 1) Pass invalid flag value to syscall (value chosen
11  *    to be unlikely to collide with future extensions)
12  *    -> EINVAL
13  * 2) Pass a file descriptor that is corresponding to a
14  *    regular file instead of a pid directory
15  *    -> EBADF
16  * 3) Pass a signal that is different from the one used
17  *    to initialize the siginfo_t struct
18  *    -> EINVAL
19  * 4) Try to send signal to other process (init) with
20  *    missing privileges
21  *    -> EPERM
22  */
23 
24 #define _GNU_SOURCE
25 #include <pwd.h>
26 #include <signal.h>
27 #include "tst_safe_pthread.h"
28 #include "pidfd_send_signal.h"
29 
30 #define CORRECT_SIGNAL		SIGUSR1
31 #define DIFFERENT_SIGNAL	SIGUSR2
32 
33 static siginfo_t info;
34 static int pidfd;
35 static int init_pidfd;
36 static int dummyfd;
37 
38 static struct tcase {
39 	int		*fd;
40 	siginfo_t	*siginf;
41 	int		signal;
42 	int		flags;
43 	int		exp_err;
44 } tcases[] = {
45 	{&pidfd, &info, CORRECT_SIGNAL, 99999, EINVAL},
46 	{&dummyfd, &info, CORRECT_SIGNAL, 0, EBADF},
47 	{&pidfd, &info, DIFFERENT_SIGNAL, 0, EINVAL},
48 	{&init_pidfd, &info, CORRECT_SIGNAL, 0, EPERM},
49 };
50 
verify_pidfd_send_signal(unsigned int n)51 static void verify_pidfd_send_signal(unsigned int n)
52 {
53 	struct tcase *tc = &tcases[n];
54 
55 	TEST(pidfd_send_signal(*tc->fd, tc->signal, tc->siginf, tc->flags));
56 	if (tc->exp_err != TST_ERR) {
57 		tst_res(TFAIL | TTERRNO,
58 			"pidfd_send_signal() did not fail with %s but",
59 			tst_strerrno(tc->exp_err));
60 		return;
61 	}
62 
63 	tst_res(TPASS | TTERRNO,
64 		"pidfd_send_signal() failed as expected");
65 }
66 
setup(void)67 static void setup(void)
68 {
69 	struct passwd *pw;
70 
71 	check_syscall_support();
72 
73 	pidfd = SAFE_OPEN("/proc/self", O_DIRECTORY | O_CLOEXEC);
74 	init_pidfd = SAFE_OPEN("/proc/1", O_DIRECTORY | O_CLOEXEC);
75 	dummyfd = SAFE_OPEN("dummy_file", O_RDWR | O_CREAT, 0664);
76 
77 	if (getuid() == 0) {
78 		pw = SAFE_GETPWNAM("nobody");
79 		SAFE_SETUID(pw->pw_uid);
80 	}
81 
82 	memset(&info, 0, sizeof(info));
83 	info.si_signo = CORRECT_SIGNAL;
84 	info.si_code = SI_QUEUE;
85 	info.si_pid = getpid();
86 	info.si_uid = getuid();
87 }
88 
cleanup(void)89 static void cleanup(void)
90 {
91 	if (dummyfd > 0)
92 		SAFE_CLOSE(dummyfd);
93 	if (init_pidfd > 0)
94 		SAFE_CLOSE(init_pidfd);
95 	if (pidfd > 0)
96 		SAFE_CLOSE(pidfd);
97 }
98 
99 static struct tst_test test = {
100 	.test = verify_pidfd_send_signal,
101 	.tcnt = ARRAY_SIZE(tcases),
102 	.setup = setup,
103 	.cleanup = cleanup,
104 	.needs_tmpdir = 1,
105 };
106