1 /*
2 * Copyright (c) International Business Machines Corp., 2007
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
10 * the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 ***************************************************************************
16 * File: pidns12.c
17 * *
18 * * Description:
19 * *  The pidns12.c testcase verifies that siginfo->si_pid is set to 0
20 * *  if sender (parent process) is not in receiver's namespace.
21 * *
22 * * Test Assertion & Strategy:
23 * *  Create a PID namespace container.
24 * *  Initialise signal handler for SIGUSR1 in container.
25 * *  Let parent send SIGUSR1 to container.
26 * *  Check if sender pid is set to 0 from signal info.
27 * *
28 * * Usage: <for command-line>
29 * *  pidns12
30 * *
31 * * History:
32 * *  DATE      NAME                             DESCRIPTION
33 * *  13/11/08  Gowrishankar M 			Creation of this test.
34 * *            <gowrishankar.m@in.ibm.com>
35 *
36 ******************************************************************************/
37 #define _GNU_SOURCE 1
38 #include <sys/wait.h>
39 #include <sys/types.h>
40 #include <signal.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include "test.h"
46 #include <libclone.h>
47 #include "pidns_helper.h"
48 
49 char *TCID = "pidns12";
50 int TST_TOTAL = 1;
51 int errno;
52 int pipefd[2];
53 
54 #define CHILD_PID       1
55 #define PARENT_PID      0
56 
57 /*
58  * child_signal_handler() - dummy function for sigaction()
59  */
child_signal_handler(int sig,siginfo_t * si,void * unused)60 static void child_signal_handler(int sig, siginfo_t * si, void *unused)
61 {
62 	/* Recieved SIGUSR1. Check sender pid */
63 	if (si->si_pid == 0)
64 		tst_resm(TPASS, "cinit: signalling PID (from other namespace)"
65 			 " is 0 as expected");
66 	else
67 		tst_resm(TFAIL, "cinit: signalling PID (from other namespace)"
68 			 " is not 0, but %d.", si->si_pid);
69 }
70 
71 /*
72  * child_fn() - Inside container
73  */
child_fn(void * arg)74 int child_fn(void *arg)
75 {
76 	struct sigaction sa;
77 	pid_t pid, ppid;
78 
79 	/* Set process id and parent pid */
80 	pid = getpid();
81 	ppid = getppid();
82 	if (pid != CHILD_PID || ppid != PARENT_PID) {
83 		tst_resm(TBROK, "cinit: pidns is not created.");
84 	}
85 
86 	/* Close read end of pipe */
87 	close(pipefd[0]);
88 
89 	/* Set signal handler for SIGUSR1 */
90 	sa.sa_flags = SA_SIGINFO;
91 	sigfillset(&sa.sa_mask);
92 	sa.sa_sigaction = child_signal_handler;
93 	if (sigaction(SIGUSR1, &sa, NULL) == -1) {
94 		tst_resm(TBROK, "cinit: sigaction() failed(%s).",
95 			 strerror(errno));
96 	}
97 
98 	/* Let parent to signal SIGUSR1 */
99 	if (write(pipefd[1], "c:go\0", 5) != 5) {
100 		tst_resm(TBROK, "cinit: pipe is broken to write");
101 	}
102 
103 	sleep(3);
104 
105 	/* cleanup and exit */
106 	close(pipefd[1]);
107 
108 	/* Control won't reach below */
109 	exit(0);
110 }
111 
setup(void)112 static void setup(void)
113 {
114 	tst_require_root();
115 	check_newpid();
116 }
117 
118 /***********************************************************************
119 *   M A I N
120 ***********************************************************************/
121 
main(int argc,char * argv[])122 int main(int argc, char *argv[])
123 {
124 	int status;
125 	pid_t pid, cpid;
126 	char buf[5];
127 
128 	setup();
129 
130 	pid = getpid();
131 	tst_resm(TINFO, "parent: PID is %d", pid);
132 
133 	/* Create pipe for intercommunication */
134 	if (pipe(pipefd) == -1) {
135 		tst_resm(TBROK, "parent: pipe() failed. aborting!");
136 	}
137 
138 	cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL);
139 	if (cpid < 0) {
140 		tst_resm(TBROK, "parent: clone() failed(%s).", strerror(errno));
141 	}
142 
143 	/* Close write end of pipe */
144 	close(pipefd[1]);
145 
146 	/* Check if container is ready */
147 	read(pipefd[0], buf, 5);
148 	if (strcmp(buf, "c:go") != 0) {
149 		tst_resm(TBROK, "parent: container did not respond!");
150 	}
151 
152 	/* Send SIGUSR1 to container init */
153 	if (kill(cpid, SIGUSR1) == -1) {
154 		tst_resm(TBROK, "parent: kill() failed(%s).", strerror(errno));
155 	}
156 
157 	if (waitpid(cpid, &status, 0) < 0)
158 		tst_resm(TWARN, "parent: waitpid() failed(%s).",
159 			 strerror(errno));
160 
161 	if (WIFSIGNALED(status) && WTERMSIG(status))
162 		tst_resm(TBROK, "child is terminated by signal(%s)",
163 			 strsignal(WTERMSIG(status)));
164 
165 	/* Cleanup and exit */
166 	close(pipefd[0]);
167 
168 	/* Control won't reach below */
169 	exit(0);
170 
171 }
172