1*11be35a1SLionel Sambuc // Copyright 2012 Google Inc.
2*11be35a1SLionel Sambuc // All rights reserved.
3*11be35a1SLionel Sambuc //
4*11be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
5*11be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
6*11be35a1SLionel Sambuc // met:
7*11be35a1SLionel Sambuc //
8*11be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
9*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer.
10*11be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
11*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer in the
12*11be35a1SLionel Sambuc //   documentation and/or other materials provided with the distribution.
13*11be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
14*11be35a1SLionel Sambuc //   may be used to endorse or promote products derived from this software
15*11be35a1SLionel Sambuc //   without specific prior written permission.
16*11be35a1SLionel Sambuc //
17*11be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*11be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*11be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*11be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*11be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*11be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*11be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*11be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*11be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*11be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*11be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc 
29*11be35a1SLionel Sambuc #if defined(HAVE_CONFIG_H)
30*11be35a1SLionel Sambuc #   include "config.h"
31*11be35a1SLionel Sambuc #endif
32*11be35a1SLionel Sambuc 
33*11be35a1SLionel Sambuc #include "run.h"
34*11be35a1SLionel Sambuc 
35*11be35a1SLionel Sambuc #include <sys/resource.h>
36*11be35a1SLionel Sambuc #include <sys/stat.h>
37*11be35a1SLionel Sambuc #include <sys/wait.h>
38*11be35a1SLionel Sambuc 
39*11be35a1SLionel Sambuc #include <err.h>
40*11be35a1SLionel Sambuc #include <errno.h>
41*11be35a1SLionel Sambuc #include <pwd.h>
42*11be35a1SLionel Sambuc #include <signal.h>
43*11be35a1SLionel Sambuc #include <stdbool.h>
44*11be35a1SLionel Sambuc #include <stdio.h>
45*11be35a1SLionel Sambuc #include <stdlib.h>
46*11be35a1SLionel Sambuc #include <unistd.h>
47*11be35a1SLionel Sambuc 
48*11be35a1SLionel Sambuc #include <atf-c.h>
49*11be35a1SLionel Sambuc 
50*11be35a1SLionel Sambuc #include "defs.h"
51*11be35a1SLionel Sambuc #include "env.h"
52*11be35a1SLionel Sambuc #include "error.h"
53*11be35a1SLionel Sambuc #include "fs.h"
54*11be35a1SLionel Sambuc 
55*11be35a1SLionel Sambuc 
56*11be35a1SLionel Sambuc /// Evalutes an expression and ensures it does not return an error.
57*11be35a1SLionel Sambuc ///
58*11be35a1SLionel Sambuc /// \param expr A expression that must evaluate to kyua_error_t.
59*11be35a1SLionel Sambuc #define RE(expr) ATF_REQUIRE(!kyua_error_is_set(expr))
60*11be35a1SLionel Sambuc 
61*11be35a1SLionel Sambuc 
62*11be35a1SLionel Sambuc static void check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
63*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
64*11be35a1SLionel Sambuc 
65*11be35a1SLionel Sambuc 
66*11be35a1SLionel Sambuc /// Subprocess that validates the cleanliness of the environment.
67*11be35a1SLionel Sambuc ///
68*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
69*11be35a1SLionel Sambuc ///
70*11be35a1SLionel Sambuc /// \post Exits with success if the environment is clean; failure otherwise.
71*11be35a1SLionel Sambuc static void
check_env(const void * KYUA_DEFS_UNUSED_PARAM (cookie))72*11be35a1SLionel Sambuc check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
73*11be35a1SLionel Sambuc {
74*11be35a1SLionel Sambuc     bool failed = false;
75*11be35a1SLionel Sambuc 
76*11be35a1SLionel Sambuc     const char* empty[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
77*11be35a1SLionel Sambuc                             "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC",
78*11be35a1SLionel Sambuc                             "LC_TIME", NULL };
79*11be35a1SLionel Sambuc     const char** iter;
80*11be35a1SLionel Sambuc     for (iter = empty; *iter != NULL; ++iter) {
81*11be35a1SLionel Sambuc         if (getenv(*iter) != NULL) {
82*11be35a1SLionel Sambuc             failed = true;
83*11be35a1SLionel Sambuc             printf("%s was not unset\n", *iter);
84*11be35a1SLionel Sambuc         }
85*11be35a1SLionel Sambuc     }
86*11be35a1SLionel Sambuc 
87*11be35a1SLionel Sambuc     if (strcmp(getenv("HOME"), ".") != 0) {
88*11be35a1SLionel Sambuc         failed = true;
89*11be35a1SLionel Sambuc         printf("HOME was not set to .\n");
90*11be35a1SLionel Sambuc     }
91*11be35a1SLionel Sambuc     if (strcmp(getenv("TZ"), "UTC") != 0) {
92*11be35a1SLionel Sambuc         failed = true;
93*11be35a1SLionel Sambuc         printf("TZ was not set to UTC\n");
94*11be35a1SLionel Sambuc     }
95*11be35a1SLionel Sambuc     if (strcmp(getenv("LEAVE_ME_ALONE"), "kill-some-day") != 0) {
96*11be35a1SLionel Sambuc         failed = true;
97*11be35a1SLionel Sambuc         printf("LEAVE_ME_ALONE was modified while it should not have been\n");
98*11be35a1SLionel Sambuc     }
99*11be35a1SLionel Sambuc 
100*11be35a1SLionel Sambuc     exit(failed ? EXIT_FAILURE : EXIT_SUCCESS);
101*11be35a1SLionel Sambuc }
102*11be35a1SLionel Sambuc 
103*11be35a1SLionel Sambuc 
104*11be35a1SLionel Sambuc static void check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
105*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
106*11be35a1SLionel Sambuc 
107*11be35a1SLionel Sambuc 
108*11be35a1SLionel Sambuc /// Subprocess that validates that it has become the leader of a process group.
109*11be35a1SLionel Sambuc ///
110*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
111*11be35a1SLionel Sambuc ///
112*11be35a1SLionel Sambuc /// \post Exits with success if the process lives in its own process group;
113*11be35a1SLionel Sambuc /// failure otherwise.
114*11be35a1SLionel Sambuc static void
check_process_group(const void * KYUA_DEFS_UNUSED_PARAM (cookie))115*11be35a1SLionel Sambuc check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
116*11be35a1SLionel Sambuc {
117*11be35a1SLionel Sambuc #if defined(__minix)
118*11be35a1SLionel Sambuc     // no pgid support on MINIX
119*11be35a1SLionel Sambuc     exit(EXIT_FAILURE);
120*11be35a1SLionel Sambuc #else
121*11be35a1SLionel Sambuc     exit(getpgid(getpid()) == getpid() ? EXIT_SUCCESS : EXIT_FAILURE);
122*11be35a1SLionel Sambuc #endif /* defined(__minix) */
123*11be35a1SLionel Sambuc }
124*11be35a1SLionel Sambuc 
125*11be35a1SLionel Sambuc 
126*11be35a1SLionel Sambuc static void check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
127*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
128*11be35a1SLionel Sambuc 
129*11be35a1SLionel Sambuc 
130*11be35a1SLionel Sambuc /// Subprocess that validates that signals have been reset to their defaults.
131*11be35a1SLionel Sambuc ///
132*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
133*11be35a1SLionel Sambuc ///
134*11be35a1SLionel Sambuc /// \post Exits with success if the process has its signals reset to their
135*11be35a1SLionel Sambuc /// default values; failure otherwise.
136*11be35a1SLionel Sambuc static void
check_signals(const void * KYUA_DEFS_UNUSED_PARAM (cookie))137*11be35a1SLionel Sambuc check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
138*11be35a1SLionel Sambuc {
139*11be35a1SLionel Sambuc     int signo;
140*11be35a1SLionel Sambuc     for (signo = 1; signo <= LAST_SIGNO; signo++) {
141*11be35a1SLionel Sambuc         if (signo == SIGKILL || signo == SIGSTOP) {
142*11be35a1SLionel Sambuc             // Don't attempt to check immutable signals, as this results in
143*11be35a1SLionel Sambuc             // an unconditional error in some systems.  E.g. Mac OS X 10.8
144*11be35a1SLionel Sambuc             // reports 'Invalid argument' when querying SIGKILL.
145*11be35a1SLionel Sambuc             continue;
146*11be35a1SLionel Sambuc         }
147*11be35a1SLionel Sambuc 
148*11be35a1SLionel Sambuc         struct sigaction old_sa;
149*11be35a1SLionel Sambuc         if (sigaction(signo, NULL, &old_sa) == -1) {
150*11be35a1SLionel Sambuc             err(EXIT_FAILURE, "Failed to query signal information for %d",
151*11be35a1SLionel Sambuc                 signo);
152*11be35a1SLionel Sambuc         }
153*11be35a1SLionel Sambuc         if (old_sa.sa_handler != SIG_DFL) {
154*11be35a1SLionel Sambuc             errx(EXIT_FAILURE, "Signal %d not reset to its default handler",
155*11be35a1SLionel Sambuc                  signo);
156*11be35a1SLionel Sambuc         }
157*11be35a1SLionel Sambuc         printf("Signal %d has its default handler set\n", signo);
158*11be35a1SLionel Sambuc     }
159*11be35a1SLionel Sambuc 
160*11be35a1SLionel Sambuc     exit(EXIT_SUCCESS);
161*11be35a1SLionel Sambuc }
162*11be35a1SLionel Sambuc 
163*11be35a1SLionel Sambuc 
164*11be35a1SLionel Sambuc static void check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
165*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
166*11be35a1SLionel Sambuc 
167*11be35a1SLionel Sambuc 
168*11be35a1SLionel Sambuc /// Subprocess that validates that the umask has been reset.
169*11be35a1SLionel Sambuc ///
170*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
171*11be35a1SLionel Sambuc ///
172*11be35a1SLionel Sambuc /// \post Exits with success if the umask matches the expected value; failure
173*11be35a1SLionel Sambuc /// otherwise.
174*11be35a1SLionel Sambuc static void
check_umask(const void * KYUA_DEFS_UNUSED_PARAM (cookie))175*11be35a1SLionel Sambuc check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
176*11be35a1SLionel Sambuc {
177*11be35a1SLionel Sambuc     exit(umask(0) == 0022 ? EXIT_SUCCESS : EXIT_FAILURE);
178*11be35a1SLionel Sambuc }
179*11be35a1SLionel Sambuc 
180*11be35a1SLionel Sambuc 
181*11be35a1SLionel Sambuc static void check_work_directory(const void* cookie) KYUA_DEFS_NORETURN;
182*11be35a1SLionel Sambuc 
183*11be35a1SLionel Sambuc 
184*11be35a1SLionel Sambuc /// Subprocess that validates that the umask has been reset.
185*11be35a1SLionel Sambuc ///
186*11be35a1SLionel Sambuc /// \param cookie The name of a file to expect in the current directory.
187*11be35a1SLionel Sambuc ///
188*11be35a1SLionel Sambuc /// \post Exits with success if the umask matches the expected value; failure
189*11be35a1SLionel Sambuc /// otherwise.
190*11be35a1SLionel Sambuc static void
check_work_directory(const void * cookie)191*11be35a1SLionel Sambuc check_work_directory(const void* cookie)
192*11be35a1SLionel Sambuc {
193*11be35a1SLionel Sambuc     const char* exp_file = (const char*)cookie;
194*11be35a1SLionel Sambuc     exit(atf_utils_file_exists(exp_file) ? EXIT_SUCCESS : EXIT_FAILURE);
195*11be35a1SLionel Sambuc }
196*11be35a1SLionel Sambuc 
197*11be35a1SLionel Sambuc 
198*11be35a1SLionel Sambuc static void check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
199*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
200*11be35a1SLionel Sambuc 
201*11be35a1SLionel Sambuc 
202*11be35a1SLionel Sambuc /// Subprocess that validates that the UID is not root.
203*11be35a1SLionel Sambuc ///
204*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
205*11be35a1SLionel Sambuc ///
206*11be35a1SLionel Sambuc /// \post Exits with success if the UID is not root; failure otherwise.
207*11be35a1SLionel Sambuc static void
check_uid_not_root(const void * KYUA_DEFS_UNUSED_PARAM (cookie))208*11be35a1SLionel Sambuc check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
209*11be35a1SLionel Sambuc {
210*11be35a1SLionel Sambuc     exit(getuid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
211*11be35a1SLionel Sambuc }
212*11be35a1SLionel Sambuc 
213*11be35a1SLionel Sambuc 
214*11be35a1SLionel Sambuc static void check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
215*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
216*11be35a1SLionel Sambuc 
217*11be35a1SLionel Sambuc 
218*11be35a1SLionel Sambuc /// Subprocess that validates that the GID is not root.
219*11be35a1SLionel Sambuc ///
220*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
221*11be35a1SLionel Sambuc ///
222*11be35a1SLionel Sambuc /// \post Exits with success if the GID is not root; failure otherwise.
223*11be35a1SLionel Sambuc static void
check_gid_not_root(const void * KYUA_DEFS_UNUSED_PARAM (cookie))224*11be35a1SLionel Sambuc check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
225*11be35a1SLionel Sambuc {
226*11be35a1SLionel Sambuc     exit(getgid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
227*11be35a1SLionel Sambuc }
228*11be35a1SLionel Sambuc 
229*11be35a1SLionel Sambuc 
230*11be35a1SLionel Sambuc static void check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
231*11be35a1SLionel Sambuc     KYUA_DEFS_NORETURN;
232*11be35a1SLionel Sambuc 
233*11be35a1SLionel Sambuc 
234*11be35a1SLionel Sambuc /// Subprocess that validates that the UID and GID are not root.
235*11be35a1SLionel Sambuc ///
236*11be35a1SLionel Sambuc /// \param unused_cookie NULL.
237*11be35a1SLionel Sambuc ///
238*11be35a1SLionel Sambuc /// \post Exits with success if the UID and GID are not root; failure otherwise.
239*11be35a1SLionel Sambuc static void
check_not_root(const void * KYUA_DEFS_UNUSED_PARAM (cookie))240*11be35a1SLionel Sambuc check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
241*11be35a1SLionel Sambuc {
242*11be35a1SLionel Sambuc     exit(getuid() != 0 && getgid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
243*11be35a1SLionel Sambuc }
244*11be35a1SLionel Sambuc 
245*11be35a1SLionel Sambuc 
246*11be35a1SLionel Sambuc /// Uses kyua_fork, kyua_exec and kyua_wait to execute a subprocess.
247*11be35a1SLionel Sambuc ///
248*11be35a1SLionel Sambuc /// \param program Path to the program to run.
249*11be35a1SLionel Sambuc /// \param args Arguments to the program.
250*11be35a1SLionel Sambuc /// \param [out] exitstatus The exit status of the subprocess, if it exits
251*11be35a1SLionel Sambuc ///     successfully without timing out nor receiving a signal.
252*11be35a1SLionel Sambuc ///
253*11be35a1SLionel Sambuc /// \return Returns the error code of kyua_run_wait (which should have the
254*11be35a1SLionel Sambuc ///     error representation of the exec call in the subprocess).
255*11be35a1SLionel Sambuc static kyua_error_t
exec_check(const char * program,const char * const * args,int * exitstatus)256*11be35a1SLionel Sambuc exec_check(const char* program, const char* const* args, int* exitstatus)
257*11be35a1SLionel Sambuc {
258*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
259*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
260*11be35a1SLionel Sambuc 
261*11be35a1SLionel Sambuc     pid_t pid;
262*11be35a1SLionel Sambuc     kyua_error_t error = kyua_run_fork(&run_params, &pid);
263*11be35a1SLionel Sambuc     if (!kyua_error_is_set(error) && pid == 0)
264*11be35a1SLionel Sambuc         kyua_run_exec(program, args);
265*11be35a1SLionel Sambuc     ATF_REQUIRE(!kyua_error_is_set(error));
266*11be35a1SLionel Sambuc     int status; bool timed_out;
267*11be35a1SLionel Sambuc     error = kyua_run_wait(pid, &status, &timed_out);
268*11be35a1SLionel Sambuc     if (!kyua_error_is_set(error)) {
269*11be35a1SLionel Sambuc         ATF_REQUIRE(!timed_out);
270*11be35a1SLionel Sambuc         ATF_REQUIRE_MSG(WIFEXITED(status),
271*11be35a1SLionel Sambuc                         "Subprocess expected to exit successfully");
272*11be35a1SLionel Sambuc         *exitstatus = WEXITSTATUS(status);
273*11be35a1SLionel Sambuc     }
274*11be35a1SLionel Sambuc     return error;
275*11be35a1SLionel Sambuc }
276*11be35a1SLionel Sambuc 
277*11be35a1SLionel Sambuc 
278*11be35a1SLionel Sambuc /// Uses kyua_fork and kyua_wait to spawn a subprocess.
279*11be35a1SLionel Sambuc ///
280*11be35a1SLionel Sambuc /// \param run_params The parameters to configure the subprocess.  Can be NULL
281*11be35a1SLionel Sambuc ///     to indicate to use the default set of parameters.
282*11be35a1SLionel Sambuc /// \param hook Any of the check_* functions provided in this module.
283*11be35a1SLionel Sambuc /// \param cookie The data to pass to the hook.
284*11be35a1SLionel Sambuc ///
285*11be35a1SLionel Sambuc /// \return True if the subprocess exits successfully; false otherwise.
286*11be35a1SLionel Sambuc static bool
fork_check(const kyua_run_params_t * run_params,void (* hook)(const void *),const void * cookie)287*11be35a1SLionel Sambuc fork_check(const kyua_run_params_t* run_params,
288*11be35a1SLionel Sambuc            void (*hook)(const void*), const void* cookie)
289*11be35a1SLionel Sambuc {
290*11be35a1SLionel Sambuc     kyua_run_params_t default_run_params;
291*11be35a1SLionel Sambuc     if (run_params == NULL) {
292*11be35a1SLionel Sambuc         kyua_run_params_init(&default_run_params);
293*11be35a1SLionel Sambuc         run_params = &default_run_params;
294*11be35a1SLionel Sambuc     }
295*11be35a1SLionel Sambuc 
296*11be35a1SLionel Sambuc     pid_t pid;
297*11be35a1SLionel Sambuc     kyua_error_t error = kyua_run_fork(run_params, &pid);
298*11be35a1SLionel Sambuc     if (!kyua_error_is_set(error) && pid == 0)
299*11be35a1SLionel Sambuc         hook(cookie);
300*11be35a1SLionel Sambuc     ATF_REQUIRE(!kyua_error_is_set(error));
301*11be35a1SLionel Sambuc     int status; bool timed_out;
302*11be35a1SLionel Sambuc     error = kyua_run_wait(pid, &status, &timed_out);
303*11be35a1SLionel Sambuc     if (kyua_error_is_set(error))
304*11be35a1SLionel Sambuc         atf_tc_fail("wait failed; unexpected problem during exec?");
305*11be35a1SLionel Sambuc     ATF_REQUIRE(!timed_out);
306*11be35a1SLionel Sambuc     return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
307*11be35a1SLionel Sambuc }
308*11be35a1SLionel Sambuc 
309*11be35a1SLionel Sambuc 
310*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(run_params_init__defaults);
ATF_TC_BODY(run_params_init__defaults,tc)311*11be35a1SLionel Sambuc ATF_TC_BODY(run_params_init__defaults, tc)
312*11be35a1SLionel Sambuc {
313*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
314*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
315*11be35a1SLionel Sambuc 
316*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(60, run_params.timeout_seconds);
317*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(getuid(), run_params.unprivileged_user);
318*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(getgid(), run_params.unprivileged_group);
319*11be35a1SLionel Sambuc     ATF_REQUIRE_STREQ(".", run_params.work_directory);
320*11be35a1SLionel Sambuc }
321*11be35a1SLionel Sambuc 
322*11be35a1SLionel Sambuc 
323*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_exec_wait__ok);
ATF_TC_BODY(fork_exec_wait__ok,tc)324*11be35a1SLionel Sambuc ATF_TC_BODY(fork_exec_wait__ok, tc)
325*11be35a1SLionel Sambuc {
326*11be35a1SLionel Sambuc     const char* const args[] = {"sh", "-c", "exit 42", NULL};
327*11be35a1SLionel Sambuc     int exitstatus = -1;  // Shut up GCC warning.
328*11be35a1SLionel Sambuc     const kyua_error_t error = exec_check("/bin/sh", args, &exitstatus);
329*11be35a1SLionel Sambuc     ATF_REQUIRE(!kyua_error_is_set(error));
330*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(42, exitstatus);
331*11be35a1SLionel Sambuc }
332*11be35a1SLionel Sambuc 
333*11be35a1SLionel Sambuc 
334*11be35a1SLionel Sambuc ATF_TC(fork_exec_wait__eacces);
ATF_TC_HEAD(fork_exec_wait__eacces,tc)335*11be35a1SLionel Sambuc ATF_TC_HEAD(fork_exec_wait__eacces, tc)
336*11be35a1SLionel Sambuc {
337*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "unprivileged");
338*11be35a1SLionel Sambuc }
ATF_TC_BODY(fork_exec_wait__eacces,tc)339*11be35a1SLionel Sambuc ATF_TC_BODY(fork_exec_wait__eacces, tc)
340*11be35a1SLionel Sambuc {
341*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir("dir", 0000) != -1);
342*11be35a1SLionel Sambuc 
343*11be35a1SLionel Sambuc     const char* const args[] = {"foo", NULL};
344*11be35a1SLionel Sambuc     int unused_exitstatus;
345*11be35a1SLionel Sambuc     const kyua_error_t error = exec_check("./dir/foo", args,
346*11be35a1SLionel Sambuc                                           &unused_exitstatus);
347*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_set(error));
348*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
349*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(EACCES, kyua_libc_error_errno(error));
350*11be35a1SLionel Sambuc }
351*11be35a1SLionel Sambuc 
352*11be35a1SLionel Sambuc 
353*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_exec_wait__enoent);
ATF_TC_BODY(fork_exec_wait__enoent,tc)354*11be35a1SLionel Sambuc ATF_TC_BODY(fork_exec_wait__enoent, tc)
355*11be35a1SLionel Sambuc {
356*11be35a1SLionel Sambuc     const char* const args[] = {"foo", NULL};
357*11be35a1SLionel Sambuc     int unused_exitstatus;
358*11be35a1SLionel Sambuc     const kyua_error_t error = exec_check("./foo", args, &unused_exitstatus);
359*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_set(error));
360*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
361*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(ENOENT, kyua_libc_error_errno(error));
362*11be35a1SLionel Sambuc }
363*11be35a1SLionel Sambuc 
364*11be35a1SLionel Sambuc 
365*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__core_size);
ATF_TC_BODY(fork_wait__core_size,tc)366*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__core_size, tc)
367*11be35a1SLionel Sambuc {
368*11be35a1SLionel Sambuc     struct rlimit rl;
369*11be35a1SLionel Sambuc     rl.rlim_cur = 0;
370*11be35a1SLionel Sambuc     rl.rlim_max = RLIM_INFINITY;
371*11be35a1SLionel Sambuc     if (setrlimit(RLIMIT_CORE, &rl) == -1)
372*11be35a1SLionel Sambuc         atf_tc_skip("Failed to lower the core size limit");
373*11be35a1SLionel Sambuc 
374*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
375*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
376*11be35a1SLionel Sambuc 
377*11be35a1SLionel Sambuc     pid_t pid;
378*11be35a1SLionel Sambuc     kyua_error_t error = kyua_run_fork(&run_params, &pid);
379*11be35a1SLionel Sambuc     if (!kyua_error_is_set(error) && pid == 0)
380*11be35a1SLionel Sambuc         abort();
381*11be35a1SLionel Sambuc 
382*11be35a1SLionel Sambuc     ATF_REQUIRE(!kyua_error_is_set(error));
383*11be35a1SLionel Sambuc     int status; bool timed_out;
384*11be35a1SLionel Sambuc     error = kyua_run_wait(pid, &status, &timed_out);
385*11be35a1SLionel Sambuc     if (kyua_error_is_set(error))
386*11be35a1SLionel Sambuc         atf_tc_fail("wait failed; unexpected problem during exec?");
387*11be35a1SLionel Sambuc 
388*11be35a1SLionel Sambuc     ATF_REQUIRE(!timed_out);
389*11be35a1SLionel Sambuc     ATF_REQUIRE(WIFSIGNALED(status));
390*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(WCOREDUMP(status), "Core not dumped as expected");
391*11be35a1SLionel Sambuc }
392*11be35a1SLionel Sambuc 
393*11be35a1SLionel Sambuc 
394*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__env);
ATF_TC_BODY(fork_wait__env,tc)395*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__env, tc)
396*11be35a1SLionel Sambuc {
397*11be35a1SLionel Sambuc     kyua_env_set("HOME", "/non-existent/directory");
398*11be35a1SLionel Sambuc     kyua_env_set("LANG", "C");
399*11be35a1SLionel Sambuc     kyua_env_set("LC_ALL", "C");
400*11be35a1SLionel Sambuc     kyua_env_set("LC_COLLATE", "C");
401*11be35a1SLionel Sambuc     kyua_env_set("LC_CTYPE", "C");
402*11be35a1SLionel Sambuc     kyua_env_set("LC_MESSAGES", "C");
403*11be35a1SLionel Sambuc     kyua_env_set("LC_MONETARY", "C");
404*11be35a1SLionel Sambuc     kyua_env_set("LC_NUMERIC", "C");
405*11be35a1SLionel Sambuc     kyua_env_set("LC_TIME", "C");
406*11be35a1SLionel Sambuc     kyua_env_set("LEAVE_ME_ALONE", "kill-some-day");
407*11be35a1SLionel Sambuc     kyua_env_set("TZ", "EST+5");
408*11be35a1SLionel Sambuc 
409*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(NULL, check_env, NULL),
410*11be35a1SLionel Sambuc                     "Unclean environment in subprocess");
411*11be35a1SLionel Sambuc }
412*11be35a1SLionel Sambuc 
413*11be35a1SLionel Sambuc 
414*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__process_group);
ATF_TC_BODY(fork_wait__process_group,tc)415*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__process_group, tc)
416*11be35a1SLionel Sambuc {
417*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(NULL, check_process_group, NULL),
418*11be35a1SLionel Sambuc                     "Subprocess not in its own process group");
419*11be35a1SLionel Sambuc }
420*11be35a1SLionel Sambuc 
421*11be35a1SLionel Sambuc 
422*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__signals);
ATF_TC_BODY(fork_wait__signals,tc)423*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__signals, tc)
424*11be35a1SLionel Sambuc {
425*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(LAST_SIGNO > 10, "LAST_SIGNO as detected by configure is "
426*11be35a1SLionel Sambuc                     "suspiciously low");
427*11be35a1SLionel Sambuc 
428*11be35a1SLionel Sambuc     int signo;
429*11be35a1SLionel Sambuc     for (signo = 1; signo <= LAST_SIGNO; signo++) {
430*11be35a1SLionel Sambuc         if (signo == SIGKILL || signo == SIGSTOP) {
431*11be35a1SLionel Sambuc             // Ignore immutable signals.
432*11be35a1SLionel Sambuc             continue;
433*11be35a1SLionel Sambuc         }
434*11be35a1SLionel Sambuc         if (signo == SIGCHLD) {
435*11be35a1SLionel Sambuc             // If we were to reset SIGCHLD to SIG_IGN (which is different than
436*11be35a1SLionel Sambuc             // not touching the signal at all, leaving it at its default value),
437*11be35a1SLionel Sambuc             // our child process will not become a zombie and the call to
438*11be35a1SLionel Sambuc             // kyua_run_wait will fail.  Avoid this.
439*11be35a1SLionel Sambuc             continue;
440*11be35a1SLionel Sambuc         }
441*11be35a1SLionel Sambuc 
442*11be35a1SLionel Sambuc         struct sigaction sa;
443*11be35a1SLionel Sambuc         sa.sa_handler = SIG_IGN;
444*11be35a1SLionel Sambuc         sigemptyset(&sa.sa_mask);
445*11be35a1SLionel Sambuc         sa.sa_flags = 0;
446*11be35a1SLionel Sambuc         printf("Ignoring signal %d\n", signo);
447*11be35a1SLionel Sambuc         ATF_REQUIRE(sigaction(signo, &sa, NULL) != -1);
448*11be35a1SLionel Sambuc     }
449*11be35a1SLionel Sambuc 
450*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(NULL, check_signals, NULL),
451*11be35a1SLionel Sambuc                     "Signals not reset to their default state");
452*11be35a1SLionel Sambuc }
453*11be35a1SLionel Sambuc 
454*11be35a1SLionel Sambuc 
455*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__timeout);
ATF_TC_BODY(fork_wait__timeout,tc)456*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__timeout, tc)
457*11be35a1SLionel Sambuc {
458*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
459*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
460*11be35a1SLionel Sambuc     run_params.timeout_seconds = 1;
461*11be35a1SLionel Sambuc 
462*11be35a1SLionel Sambuc     pid_t pid;
463*11be35a1SLionel Sambuc     kyua_error_t error = kyua_run_fork(&run_params, &pid);
464*11be35a1SLionel Sambuc     if (!kyua_error_is_set(error) && pid == 0) {
465*11be35a1SLionel Sambuc         sigset_t mask;
466*11be35a1SLionel Sambuc         sigemptyset(&mask);
467*11be35a1SLionel Sambuc         for (;;)
468*11be35a1SLionel Sambuc             sigsuspend(&mask);
469*11be35a1SLionel Sambuc     }
470*11be35a1SLionel Sambuc     ATF_REQUIRE(!kyua_error_is_set(error));
471*11be35a1SLionel Sambuc     int status; bool timed_out;
472*11be35a1SLionel Sambuc     kyua_run_wait(pid, &status, &timed_out);
473*11be35a1SLionel Sambuc     ATF_REQUIRE(timed_out);
474*11be35a1SLionel Sambuc     ATF_REQUIRE(WIFSIGNALED(status));
475*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(SIGKILL, WTERMSIG(status));
476*11be35a1SLionel Sambuc }
477*11be35a1SLionel Sambuc 
478*11be35a1SLionel Sambuc 
479*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__umask);
ATF_TC_BODY(fork_wait__umask,tc)480*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__umask, tc)
481*11be35a1SLionel Sambuc {
482*11be35a1SLionel Sambuc     (void)umask(0222);
483*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(NULL, check_umask, NULL),
484*11be35a1SLionel Sambuc                     "Subprocess does not have the predetermined 0022 umask");
485*11be35a1SLionel Sambuc }
486*11be35a1SLionel Sambuc 
487*11be35a1SLionel Sambuc 
488*11be35a1SLionel Sambuc ATF_TC(fork_wait__unprivileged_user);
ATF_TC_HEAD(fork_wait__unprivileged_user,tc)489*11be35a1SLionel Sambuc ATF_TC_HEAD(fork_wait__unprivileged_user, tc)
490*11be35a1SLionel Sambuc {
491*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
492*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "root");
493*11be35a1SLionel Sambuc }
ATF_TC_BODY(fork_wait__unprivileged_user,tc)494*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__unprivileged_user, tc)
495*11be35a1SLionel Sambuc {
496*11be35a1SLionel Sambuc     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
497*11be35a1SLionel Sambuc         tc, "unprivileged-user"));
498*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
499*11be35a1SLionel Sambuc 
500*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
501*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
502*11be35a1SLionel Sambuc     run_params.unprivileged_user = pw->pw_uid;
503*11be35a1SLionel Sambuc 
504*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(&run_params, check_uid_not_root, NULL),
505*11be35a1SLionel Sambuc                     "Subprocess is still running with UID set to root");
506*11be35a1SLionel Sambuc }
507*11be35a1SLionel Sambuc 
508*11be35a1SLionel Sambuc 
509*11be35a1SLionel Sambuc ATF_TC(fork_wait__unprivileged_group);
ATF_TC_HEAD(fork_wait__unprivileged_group,tc)510*11be35a1SLionel Sambuc ATF_TC_HEAD(fork_wait__unprivileged_group, tc)
511*11be35a1SLionel Sambuc {
512*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
513*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "root");
514*11be35a1SLionel Sambuc }
ATF_TC_BODY(fork_wait__unprivileged_group,tc)515*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__unprivileged_group, tc)
516*11be35a1SLionel Sambuc {
517*11be35a1SLionel Sambuc     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
518*11be35a1SLionel Sambuc         tc, "unprivileged-user"));
519*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
520*11be35a1SLionel Sambuc 
521*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
522*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
523*11be35a1SLionel Sambuc     run_params.unprivileged_group = pw->pw_gid;
524*11be35a1SLionel Sambuc 
525*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(&run_params, check_gid_not_root, NULL),
526*11be35a1SLionel Sambuc                     "Subprocess is still running with GID set to root");
527*11be35a1SLionel Sambuc }
528*11be35a1SLionel Sambuc 
529*11be35a1SLionel Sambuc 
530*11be35a1SLionel Sambuc ATF_TC(fork_wait__unprivileged_both);
ATF_TC_HEAD(fork_wait__unprivileged_both,tc)531*11be35a1SLionel Sambuc ATF_TC_HEAD(fork_wait__unprivileged_both, tc)
532*11be35a1SLionel Sambuc {
533*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
534*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "root");
535*11be35a1SLionel Sambuc }
ATF_TC_BODY(fork_wait__unprivileged_both,tc)536*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__unprivileged_both, tc)
537*11be35a1SLionel Sambuc {
538*11be35a1SLionel Sambuc     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
539*11be35a1SLionel Sambuc         tc, "unprivileged-user"));
540*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
541*11be35a1SLionel Sambuc 
542*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
543*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
544*11be35a1SLionel Sambuc     run_params.unprivileged_user = pw->pw_uid;
545*11be35a1SLionel Sambuc     run_params.unprivileged_group = pw->pw_gid;
546*11be35a1SLionel Sambuc 
547*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(&run_params, check_not_root, NULL),
548*11be35a1SLionel Sambuc                     "Subprocess is still running with root privileges");
549*11be35a1SLionel Sambuc }
550*11be35a1SLionel Sambuc 
551*11be35a1SLionel Sambuc 
552*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(fork_wait__work_directory);
ATF_TC_BODY(fork_wait__work_directory,tc)553*11be35a1SLionel Sambuc ATF_TC_BODY(fork_wait__work_directory, tc)
554*11be35a1SLionel Sambuc {
555*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir("the-work-directory", 0755) != -1);
556*11be35a1SLionel Sambuc     atf_utils_create_file("the-work-directory/data-file", "%s", "");
557*11be35a1SLionel Sambuc 
558*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
559*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
560*11be35a1SLionel Sambuc     run_params.work_directory = "./the-work-directory";
561*11be35a1SLionel Sambuc     ATF_REQUIRE_MSG(fork_check(&run_params, check_work_directory, "data-file"),
562*11be35a1SLionel Sambuc                     "Subprocess not in its own process group");
563*11be35a1SLionel Sambuc }
564*11be35a1SLionel Sambuc 
565*11be35a1SLionel Sambuc 
566*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(work_directory__builtin_tmpdir);
ATF_TC_BODY(work_directory__builtin_tmpdir,tc)567*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__builtin_tmpdir, tc)
568*11be35a1SLionel Sambuc {
569*11be35a1SLionel Sambuc     char* tmpdir;
570*11be35a1SLionel Sambuc     RE(kyua_fs_make_absolute("worktest", &tmpdir));
571*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
572*11be35a1SLionel Sambuc     RE(kyua_env_unset("TMPDIR"));
573*11be35a1SLionel Sambuc     kyua_run_tmpdir = tmpdir;
574*11be35a1SLionel Sambuc 
575*11be35a1SLionel Sambuc     char* work_directory;
576*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
577*11be35a1SLionel Sambuc                                      &work_directory));
578*11be35a1SLionel Sambuc 
579*11be35a1SLionel Sambuc     {
580*11be35a1SLionel Sambuc         char* template_test;
581*11be35a1SLionel Sambuc         RE(kyua_fs_concat(&template_test, atf_tc_get_config_var(tc, "srcdir"),
582*11be35a1SLionel Sambuc                           "worktest", "template.XXXXXX", NULL));
583*11be35a1SLionel Sambuc         ATF_REQUIRE(access(template_test, X_OK) == -1);
584*11be35a1SLionel Sambuc         free(template_test);
585*11be35a1SLionel Sambuc     }
586*11be35a1SLionel Sambuc 
587*11be35a1SLionel Sambuc     ATF_REQUIRE(access(work_directory, X_OK) != -1);
588*11be35a1SLionel Sambuc 
589*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
590*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_leave(&work_directory));
591*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) != -1);
592*11be35a1SLionel Sambuc     free(tmpdir);
593*11be35a1SLionel Sambuc }
594*11be35a1SLionel Sambuc 
595*11be35a1SLionel Sambuc 
596*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(work_directory__env_tmpdir);
ATF_TC_BODY(work_directory__env_tmpdir,tc)597*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__env_tmpdir, tc)
598*11be35a1SLionel Sambuc {
599*11be35a1SLionel Sambuc     char* tmpdir;
600*11be35a1SLionel Sambuc     RE(kyua_fs_make_absolute("worktest", &tmpdir));
601*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
602*11be35a1SLionel Sambuc     RE(kyua_env_set("TMPDIR", tmpdir));
603*11be35a1SLionel Sambuc 
604*11be35a1SLionel Sambuc     char* work_directory;
605*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
606*11be35a1SLionel Sambuc                                      &work_directory));
607*11be35a1SLionel Sambuc 
608*11be35a1SLionel Sambuc     {
609*11be35a1SLionel Sambuc         char* template_test;
610*11be35a1SLionel Sambuc         RE(kyua_fs_concat(&template_test, atf_tc_get_config_var(tc, "srcdir"),
611*11be35a1SLionel Sambuc                           "worktest", "template.XXXXXX", NULL));
612*11be35a1SLionel Sambuc         ATF_REQUIRE(access(template_test, X_OK) == -1);
613*11be35a1SLionel Sambuc         free(template_test);
614*11be35a1SLionel Sambuc     }
615*11be35a1SLionel Sambuc 
616*11be35a1SLionel Sambuc     ATF_REQUIRE(access(work_directory, X_OK) != -1);
617*11be35a1SLionel Sambuc 
618*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
619*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_leave(&work_directory));
620*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) != -1);
621*11be35a1SLionel Sambuc     free(tmpdir);
622*11be35a1SLionel Sambuc }
623*11be35a1SLionel Sambuc 
624*11be35a1SLionel Sambuc 
625*11be35a1SLionel Sambuc ATF_TC(work_directory__permissions);
ATF_TC_HEAD(work_directory__permissions,tc)626*11be35a1SLionel Sambuc ATF_TC_HEAD(work_directory__permissions, tc)
627*11be35a1SLionel Sambuc {
628*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
629*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "root");
630*11be35a1SLionel Sambuc }
ATF_TC_BODY(work_directory__permissions,tc)631*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__permissions, tc)
632*11be35a1SLionel Sambuc {
633*11be35a1SLionel Sambuc     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
634*11be35a1SLionel Sambuc         tc, "unprivileged-user"));
635*11be35a1SLionel Sambuc 
636*11be35a1SLionel Sambuc     printf("%d %d %d %d\n", getuid(), getgid(), pw->pw_uid, pw->pw_gid);
637*11be35a1SLionel Sambuc 
638*11be35a1SLionel Sambuc     char* work_directory;
639*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_enter("template.XXXXXX", pw->pw_uid, pw->pw_gid,
640*11be35a1SLionel Sambuc                                      &work_directory));
641*11be35a1SLionel Sambuc 
642*11be35a1SLionel Sambuc     struct stat sb;
643*11be35a1SLionel Sambuc     ATF_REQUIRE(stat(work_directory, &sb) != -1);
644*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(pw->pw_uid, sb.st_uid);
645*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(pw->pw_gid, sb.st_gid);
646*11be35a1SLionel Sambuc 
647*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_leave(&work_directory));
648*11be35a1SLionel Sambuc }
649*11be35a1SLionel Sambuc 
650*11be35a1SLionel Sambuc 
651*11be35a1SLionel Sambuc ATF_TC(work_directory__mkdtemp_error);
ATF_TC_HEAD(work_directory__mkdtemp_error,tc)652*11be35a1SLionel Sambuc ATF_TC_HEAD(work_directory__mkdtemp_error, tc)
653*11be35a1SLionel Sambuc {
654*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "unprivileged");
655*11be35a1SLionel Sambuc }
ATF_TC_BODY(work_directory__mkdtemp_error,tc)656*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__mkdtemp_error, tc)
657*11be35a1SLionel Sambuc {
658*11be35a1SLionel Sambuc     char* tmpdir;
659*11be35a1SLionel Sambuc     RE(kyua_fs_make_absolute("worktest", &tmpdir));
660*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir(tmpdir, 0555) != -1);
661*11be35a1SLionel Sambuc     RE(kyua_env_set("TMPDIR", tmpdir));
662*11be35a1SLionel Sambuc 
663*11be35a1SLionel Sambuc     char* work_directory;
664*11be35a1SLionel Sambuc     const kyua_error_t error = kyua_run_work_directory_enter(
665*11be35a1SLionel Sambuc         "template.XXXXXX", getuid(), getgid(), &work_directory);
666*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_set(error));
667*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
668*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(EACCES, kyua_libc_error_errno(error));
669*11be35a1SLionel Sambuc     kyua_error_free(error);
670*11be35a1SLionel Sambuc 
671*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) != -1);  // Empty; subdirectory not created.
672*11be35a1SLionel Sambuc     free(tmpdir);
673*11be35a1SLionel Sambuc }
674*11be35a1SLionel Sambuc 
675*11be35a1SLionel Sambuc 
676*11be35a1SLionel Sambuc ATF_TC(work_directory__permissions_error);
ATF_TC_HEAD(work_directory__permissions_error,tc)677*11be35a1SLionel Sambuc ATF_TC_HEAD(work_directory__permissions_error, tc)
678*11be35a1SLionel Sambuc {
679*11be35a1SLionel Sambuc     atf_tc_set_md_var(tc, "require.user", "unprivileged");
680*11be35a1SLionel Sambuc }
ATF_TC_BODY(work_directory__permissions_error,tc)681*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__permissions_error, tc)
682*11be35a1SLionel Sambuc {
683*11be35a1SLionel Sambuc     char* tmpdir;
684*11be35a1SLionel Sambuc     RE(kyua_fs_make_absolute("worktest", &tmpdir));
685*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
686*11be35a1SLionel Sambuc     RE(kyua_env_set("TMPDIR", tmpdir));
687*11be35a1SLionel Sambuc 
688*11be35a1SLionel Sambuc     char* work_directory;
689*11be35a1SLionel Sambuc     const kyua_error_t error = kyua_run_work_directory_enter(
690*11be35a1SLionel Sambuc         "template.XXXXXX", getuid() + 1, getgid(), &work_directory);
691*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_set(error));
692*11be35a1SLionel Sambuc     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
693*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(EPERM, kyua_libc_error_errno(error));
694*11be35a1SLionel Sambuc     kyua_error_free(error);
695*11be35a1SLionel Sambuc 
696*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) != -1);  // Empty; subdirectory not created.
697*11be35a1SLionel Sambuc     free(tmpdir);
698*11be35a1SLionel Sambuc }
699*11be35a1SLionel Sambuc 
700*11be35a1SLionel Sambuc 
701*11be35a1SLionel Sambuc /// Performs a signal delivery test to the work directory handling code.
702*11be35a1SLionel Sambuc ///
703*11be35a1SLionel Sambuc /// \param signo The signal to deliver.
704*11be35a1SLionel Sambuc static void
work_directory_signal_check(const int signo)705*11be35a1SLionel Sambuc work_directory_signal_check(const int signo)
706*11be35a1SLionel Sambuc {
707*11be35a1SLionel Sambuc     char* tmpdir;
708*11be35a1SLionel Sambuc     RE(kyua_fs_make_absolute("worktest", &tmpdir));
709*11be35a1SLionel Sambuc     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
710*11be35a1SLionel Sambuc     RE(kyua_env_set("TMPDIR", tmpdir));
711*11be35a1SLionel Sambuc 
712*11be35a1SLionel Sambuc     char* work_directory;
713*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
714*11be35a1SLionel Sambuc                                      &work_directory));
715*11be35a1SLionel Sambuc 
716*11be35a1SLionel Sambuc     kyua_run_params_t run_params;
717*11be35a1SLionel Sambuc     kyua_run_params_init(&run_params);
718*11be35a1SLionel Sambuc     run_params.work_directory = work_directory;
719*11be35a1SLionel Sambuc 
720*11be35a1SLionel Sambuc     pid_t pid;
721*11be35a1SLionel Sambuc     RE(kyua_run_fork(&run_params, &pid));
722*11be35a1SLionel Sambuc     if (pid == 0) {
723*11be35a1SLionel Sambuc         sleep(run_params.timeout_seconds * 2);
724*11be35a1SLionel Sambuc         abort();
725*11be35a1SLionel Sambuc     }
726*11be35a1SLionel Sambuc 
727*11be35a1SLionel Sambuc     // This should cause the handled installed by the work_directory management
728*11be35a1SLionel Sambuc     // code to terminate the subprocess so that we get a chance to run the
729*11be35a1SLionel Sambuc     // cleanup code ourselves.
730*11be35a1SLionel Sambuc     kill(getpid(), signo);
731*11be35a1SLionel Sambuc 
732*11be35a1SLionel Sambuc     int status; bool timed_out;
733*11be35a1SLionel Sambuc     RE(kyua_run_wait(pid, &status, &timed_out));
734*11be35a1SLionel Sambuc     ATF_REQUIRE(!timed_out);
735*11be35a1SLionel Sambuc     ATF_REQUIRE(WIFSIGNALED(status));
736*11be35a1SLionel Sambuc     ATF_REQUIRE_EQ(SIGKILL, WTERMSIG(status));
737*11be35a1SLionel Sambuc 
738*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
739*11be35a1SLionel Sambuc     RE(kyua_run_work_directory_leave(&work_directory));
740*11be35a1SLionel Sambuc     ATF_REQUIRE(rmdir(tmpdir) != -1);
741*11be35a1SLionel Sambuc     free(tmpdir);
742*11be35a1SLionel Sambuc }
743*11be35a1SLionel Sambuc 
744*11be35a1SLionel Sambuc 
745*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(work_directory__sighup);
ATF_TC_BODY(work_directory__sighup,tc)746*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__sighup, tc)
747*11be35a1SLionel Sambuc {
748*11be35a1SLionel Sambuc     work_directory_signal_check(SIGHUP);
749*11be35a1SLionel Sambuc }
750*11be35a1SLionel Sambuc 
751*11be35a1SLionel Sambuc 
752*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(work_directory__sigint);
ATF_TC_BODY(work_directory__sigint,tc)753*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__sigint, tc)
754*11be35a1SLionel Sambuc {
755*11be35a1SLionel Sambuc     work_directory_signal_check(SIGINT);
756*11be35a1SLionel Sambuc }
757*11be35a1SLionel Sambuc 
758*11be35a1SLionel Sambuc 
759*11be35a1SLionel Sambuc ATF_TC_WITHOUT_HEAD(work_directory__sigterm);
ATF_TC_BODY(work_directory__sigterm,tc)760*11be35a1SLionel Sambuc ATF_TC_BODY(work_directory__sigterm, tc)
761*11be35a1SLionel Sambuc {
762*11be35a1SLionel Sambuc     work_directory_signal_check(SIGTERM);
763*11be35a1SLionel Sambuc }
764*11be35a1SLionel Sambuc 
765*11be35a1SLionel Sambuc 
ATF_TP_ADD_TCS(tp)766*11be35a1SLionel Sambuc ATF_TP_ADD_TCS(tp)
767*11be35a1SLionel Sambuc {
768*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, run_params_init__defaults);
769*11be35a1SLionel Sambuc 
770*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_exec_wait__ok);
771*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_exec_wait__eacces);
772*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_exec_wait__enoent);
773*11be35a1SLionel Sambuc 
774*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__core_size);
775*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__env);
776*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__process_group);
777*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__signals);
778*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__timeout);
779*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__umask);
780*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_user);
781*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_group);
782*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_both);
783*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, fork_wait__work_directory);
784*11be35a1SLionel Sambuc 
785*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__builtin_tmpdir);
786*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__env_tmpdir);
787*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__permissions);
788*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__permissions_error);
789*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__mkdtemp_error);
790*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__sighup);
791*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__sigint);
792*11be35a1SLionel Sambuc     ATF_TP_ADD_TC(tp, work_directory__sigterm);
793*11be35a1SLionel Sambuc 
794*11be35a1SLionel Sambuc     return atf_no_error();
795*11be35a1SLionel Sambuc }
796