1 // Copyright 2012 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #if defined(HAVE_CONFIG_H)
35 #include <sys/resource.h>
56 /// Evalutes an expression and ensures it does not return an error.
58 /// \param expr A expression that must evaluate to kyua_error_t.
59 #define RE(expr) ATF_REQUIRE(!kyua_error_is_set(expr))
62 static void check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
66 /// Subprocess that validates the cleanliness of the environment.
68 /// \param unused_cookie NULL.
70 /// \post Exits with success if the environment is clean; failure otherwise.
72 check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
76 const char* empty
[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
77 "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC",
80 for (iter
= empty
; *iter
!= NULL
; ++iter
) {
81 if (getenv(*iter
) != NULL
) {
83 printf("%s was not unset\n", *iter
);
87 if (strcmp(getenv("HOME"), ".") != 0) {
89 printf("HOME was not set to .\n");
91 if (strcmp(getenv("TZ"), "UTC") != 0) {
93 printf("TZ was not set to UTC\n");
95 if (strcmp(getenv("LEAVE_ME_ALONE"), "kill-some-day") != 0) {
97 printf("LEAVE_ME_ALONE was modified while it should not have been\n");
100 exit(failed
? EXIT_FAILURE
: EXIT_SUCCESS
);
104 static void check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
108 /// Subprocess that validates that it has become the leader of a process group.
110 /// \param unused_cookie NULL.
112 /// \post Exits with success if the process lives in its own process group;
113 /// failure otherwise.
115 check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
118 // no pgid support on MINIX
121 exit(getpgid(getpid()) == getpid() ? EXIT_SUCCESS
: EXIT_FAILURE
);
122 #endif /* defined(__minix) */
126 static void check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
130 /// Subprocess that validates that signals have been reset to their defaults.
132 /// \param unused_cookie NULL.
134 /// \post Exits with success if the process has its signals reset to their
135 /// default values; failure otherwise.
137 check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
140 for (signo
= 1; signo
<= LAST_SIGNO
; signo
++) {
141 if (signo
== SIGKILL
|| signo
== SIGSTOP
) {
142 // Don't attempt to check immutable signals, as this results in
143 // an unconditional error in some systems. E.g. Mac OS X 10.8
144 // reports 'Invalid argument' when querying SIGKILL.
148 struct sigaction old_sa
;
149 if (sigaction(signo
, NULL
, &old_sa
) == -1) {
150 err(EXIT_FAILURE
, "Failed to query signal information for %d",
153 if (old_sa
.sa_handler
!= SIG_DFL
) {
154 errx(EXIT_FAILURE
, "Signal %d not reset to its default handler",
157 printf("Signal %d has its default handler set\n", signo
);
164 static void check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
168 /// Subprocess that validates that the umask has been reset.
170 /// \param unused_cookie NULL.
172 /// \post Exits with success if the umask matches the expected value; failure
175 check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
177 exit(umask(0) == 0022 ? EXIT_SUCCESS
: EXIT_FAILURE
);
181 static void check_work_directory(const void* cookie
) KYUA_DEFS_NORETURN
;
184 /// Subprocess that validates that the umask has been reset.
186 /// \param cookie The name of a file to expect in the current directory.
188 /// \post Exits with success if the umask matches the expected value; failure
191 check_work_directory(const void* cookie
)
193 const char* exp_file
= (const char*)cookie
;
194 exit(atf_utils_file_exists(exp_file
) ? EXIT_SUCCESS
: EXIT_FAILURE
);
198 static void check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
202 /// Subprocess that validates that the UID is not root.
204 /// \param unused_cookie NULL.
206 /// \post Exits with success if the UID is not root; failure otherwise.
208 check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
210 exit(getuid() != 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
214 static void check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
218 /// Subprocess that validates that the GID is not root.
220 /// \param unused_cookie NULL.
222 /// \post Exits with success if the GID is not root; failure otherwise.
224 check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
226 exit(getgid() != 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
230 static void check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
234 /// Subprocess that validates that the UID and GID are not root.
236 /// \param unused_cookie NULL.
238 /// \post Exits with success if the UID and GID are not root; failure otherwise.
240 check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie
))
242 exit(getuid() != 0 && getgid() != 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
246 /// Uses kyua_fork, kyua_exec and kyua_wait to execute a subprocess.
248 /// \param program Path to the program to run.
249 /// \param args Arguments to the program.
250 /// \param [out] exitstatus The exit status of the subprocess, if it exits
251 /// successfully without timing out nor receiving a signal.
253 /// \return Returns the error code of kyua_run_wait (which should have the
254 /// error representation of the exec call in the subprocess).
256 exec_check(const char* program
, const char* const* args
, int* exitstatus
)
258 kyua_run_params_t run_params
;
259 kyua_run_params_init(&run_params
);
262 kyua_error_t error
= kyua_run_fork(&run_params
, &pid
);
263 if (!kyua_error_is_set(error
) && pid
== 0)
264 kyua_run_exec(program
, args
);
265 ATF_REQUIRE(!kyua_error_is_set(error
));
266 int status
; bool timed_out
;
267 error
= kyua_run_wait(pid
, &status
, &timed_out
);
268 if (!kyua_error_is_set(error
)) {
269 ATF_REQUIRE(!timed_out
);
270 ATF_REQUIRE_MSG(WIFEXITED(status
),
271 "Subprocess expected to exit successfully");
272 *exitstatus
= WEXITSTATUS(status
);
278 /// Uses kyua_fork and kyua_wait to spawn a subprocess.
280 /// \param run_params The parameters to configure the subprocess. Can be NULL
281 /// to indicate to use the default set of parameters.
282 /// \param hook Any of the check_* functions provided in this module.
283 /// \param cookie The data to pass to the hook.
285 /// \return True if the subprocess exits successfully; false otherwise.
287 fork_check(const kyua_run_params_t
* run_params
,
288 void (*hook
)(const void*), const void* cookie
)
290 kyua_run_params_t default_run_params
;
291 if (run_params
== NULL
) {
292 kyua_run_params_init(&default_run_params
);
293 run_params
= &default_run_params
;
297 kyua_error_t error
= kyua_run_fork(run_params
, &pid
);
298 if (!kyua_error_is_set(error
) && pid
== 0)
300 ATF_REQUIRE(!kyua_error_is_set(error
));
301 int status
; bool timed_out
;
302 error
= kyua_run_wait(pid
, &status
, &timed_out
);
303 if (kyua_error_is_set(error
))
304 atf_tc_fail("wait failed; unexpected problem during exec?");
305 ATF_REQUIRE(!timed_out
);
306 return WIFEXITED(status
) && WEXITSTATUS(status
) == EXIT_SUCCESS
;
310 ATF_TC_WITHOUT_HEAD(run_params_init__defaults
);
311 ATF_TC_BODY(run_params_init__defaults
, tc
)
313 kyua_run_params_t run_params
;
314 kyua_run_params_init(&run_params
);
316 ATF_REQUIRE_EQ(60, run_params
.timeout_seconds
);
317 ATF_REQUIRE_EQ(getuid(), run_params
.unprivileged_user
);
318 ATF_REQUIRE_EQ(getgid(), run_params
.unprivileged_group
);
319 ATF_REQUIRE_STREQ(".", run_params
.work_directory
);
323 ATF_TC_WITHOUT_HEAD(fork_exec_wait__ok
);
324 ATF_TC_BODY(fork_exec_wait__ok
, tc
)
326 const char* const args
[] = {"sh", "-c", "exit 42", NULL
};
327 int exitstatus
= -1; // Shut up GCC warning.
328 const kyua_error_t error
= exec_check("/bin/sh", args
, &exitstatus
);
329 ATF_REQUIRE(!kyua_error_is_set(error
));
330 ATF_REQUIRE_EQ(42, exitstatus
);
334 ATF_TC(fork_exec_wait__eacces
);
335 ATF_TC_HEAD(fork_exec_wait__eacces
, tc
)
337 atf_tc_set_md_var(tc
, "require.user", "unprivileged");
339 ATF_TC_BODY(fork_exec_wait__eacces
, tc
)
341 ATF_REQUIRE(mkdir("dir", 0000) != -1);
343 const char* const args
[] = {"foo", NULL
};
344 int unused_exitstatus
;
345 const kyua_error_t error
= exec_check("./dir/foo", args
,
347 ATF_REQUIRE(kyua_error_is_set(error
));
348 ATF_REQUIRE(kyua_error_is_type(error
, "libc"));
349 ATF_REQUIRE_EQ(EACCES
, kyua_libc_error_errno(error
));
353 ATF_TC_WITHOUT_HEAD(fork_exec_wait__enoent
);
354 ATF_TC_BODY(fork_exec_wait__enoent
, tc
)
356 const char* const args
[] = {"foo", NULL
};
357 int unused_exitstatus
;
358 const kyua_error_t error
= exec_check("./foo", args
, &unused_exitstatus
);
359 ATF_REQUIRE(kyua_error_is_set(error
));
360 ATF_REQUIRE(kyua_error_is_type(error
, "libc"));
361 ATF_REQUIRE_EQ(ENOENT
, kyua_libc_error_errno(error
));
365 ATF_TC_WITHOUT_HEAD(fork_wait__core_size
);
366 ATF_TC_BODY(fork_wait__core_size
, tc
)
370 rl
.rlim_max
= RLIM_INFINITY
;
371 if (setrlimit(RLIMIT_CORE
, &rl
) == -1)
372 atf_tc_skip("Failed to lower the core size limit");
374 kyua_run_params_t run_params
;
375 kyua_run_params_init(&run_params
);
378 kyua_error_t error
= kyua_run_fork(&run_params
, &pid
);
379 if (!kyua_error_is_set(error
) && pid
== 0)
382 ATF_REQUIRE(!kyua_error_is_set(error
));
383 int status
; bool timed_out
;
384 error
= kyua_run_wait(pid
, &status
, &timed_out
);
385 if (kyua_error_is_set(error
))
386 atf_tc_fail("wait failed; unexpected problem during exec?");
388 ATF_REQUIRE(!timed_out
);
389 ATF_REQUIRE(WIFSIGNALED(status
));
390 ATF_REQUIRE_MSG(WCOREDUMP(status
), "Core not dumped as expected");
394 ATF_TC_WITHOUT_HEAD(fork_wait__env
);
395 ATF_TC_BODY(fork_wait__env
, tc
)
397 kyua_env_set("HOME", "/non-existent/directory");
398 kyua_env_set("LANG", "C");
399 kyua_env_set("LC_ALL", "C");
400 kyua_env_set("LC_COLLATE", "C");
401 kyua_env_set("LC_CTYPE", "C");
402 kyua_env_set("LC_MESSAGES", "C");
403 kyua_env_set("LC_MONETARY", "C");
404 kyua_env_set("LC_NUMERIC", "C");
405 kyua_env_set("LC_TIME", "C");
406 kyua_env_set("LEAVE_ME_ALONE", "kill-some-day");
407 kyua_env_set("TZ", "EST+5");
409 ATF_REQUIRE_MSG(fork_check(NULL
, check_env
, NULL
),
410 "Unclean environment in subprocess");
414 ATF_TC_WITHOUT_HEAD(fork_wait__process_group
);
415 ATF_TC_BODY(fork_wait__process_group
, tc
)
417 ATF_REQUIRE_MSG(fork_check(NULL
, check_process_group
, NULL
),
418 "Subprocess not in its own process group");
422 ATF_TC_WITHOUT_HEAD(fork_wait__signals
);
423 ATF_TC_BODY(fork_wait__signals
, tc
)
425 ATF_REQUIRE_MSG(LAST_SIGNO
> 10, "LAST_SIGNO as detected by configure is "
429 for (signo
= 1; signo
<= LAST_SIGNO
; signo
++) {
430 if (signo
== SIGKILL
|| signo
== SIGSTOP
) {
431 // Ignore immutable signals.
434 if (signo
== SIGCHLD
) {
435 // If we were to reset SIGCHLD to SIG_IGN (which is different than
436 // not touching the signal at all, leaving it at its default value),
437 // our child process will not become a zombie and the call to
438 // kyua_run_wait will fail. Avoid this.
443 sa
.sa_handler
= SIG_IGN
;
444 sigemptyset(&sa
.sa_mask
);
446 printf("Ignoring signal %d\n", signo
);
447 ATF_REQUIRE(sigaction(signo
, &sa
, NULL
) != -1);
450 ATF_REQUIRE_MSG(fork_check(NULL
, check_signals
, NULL
),
451 "Signals not reset to their default state");
455 ATF_TC_WITHOUT_HEAD(fork_wait__timeout
);
456 ATF_TC_BODY(fork_wait__timeout
, tc
)
458 kyua_run_params_t run_params
;
459 kyua_run_params_init(&run_params
);
460 run_params
.timeout_seconds
= 1;
463 kyua_error_t error
= kyua_run_fork(&run_params
, &pid
);
464 if (!kyua_error_is_set(error
) && pid
== 0) {
470 ATF_REQUIRE(!kyua_error_is_set(error
));
471 int status
; bool timed_out
;
472 kyua_run_wait(pid
, &status
, &timed_out
);
473 ATF_REQUIRE(timed_out
);
474 ATF_REQUIRE(WIFSIGNALED(status
));
475 ATF_REQUIRE_EQ(SIGKILL
, WTERMSIG(status
));
479 ATF_TC_WITHOUT_HEAD(fork_wait__umask
);
480 ATF_TC_BODY(fork_wait__umask
, tc
)
483 ATF_REQUIRE_MSG(fork_check(NULL
, check_umask
, NULL
),
484 "Subprocess does not have the predetermined 0022 umask");
488 ATF_TC(fork_wait__unprivileged_user
);
489 ATF_TC_HEAD(fork_wait__unprivileged_user
, tc
)
491 atf_tc_set_md_var(tc
, "require.config", "unprivileged-user");
492 atf_tc_set_md_var(tc
, "require.user", "root");
494 ATF_TC_BODY(fork_wait__unprivileged_user
, tc
)
496 const struct passwd
* pw
= getpwnam(atf_tc_get_config_var(
497 tc
, "unprivileged-user"));
498 ATF_REQUIRE_MSG(pw
!= NULL
, "Cannot find unprivileged user");
500 kyua_run_params_t run_params
;
501 kyua_run_params_init(&run_params
);
502 run_params
.unprivileged_user
= pw
->pw_uid
;
504 ATF_REQUIRE_MSG(fork_check(&run_params
, check_uid_not_root
, NULL
),
505 "Subprocess is still running with UID set to root");
509 ATF_TC(fork_wait__unprivileged_group
);
510 ATF_TC_HEAD(fork_wait__unprivileged_group
, tc
)
512 atf_tc_set_md_var(tc
, "require.config", "unprivileged-user");
513 atf_tc_set_md_var(tc
, "require.user", "root");
515 ATF_TC_BODY(fork_wait__unprivileged_group
, tc
)
517 const struct passwd
* pw
= getpwnam(atf_tc_get_config_var(
518 tc
, "unprivileged-user"));
519 ATF_REQUIRE_MSG(pw
!= NULL
, "Cannot find unprivileged user");
521 kyua_run_params_t run_params
;
522 kyua_run_params_init(&run_params
);
523 run_params
.unprivileged_group
= pw
->pw_gid
;
525 ATF_REQUIRE_MSG(fork_check(&run_params
, check_gid_not_root
, NULL
),
526 "Subprocess is still running with GID set to root");
530 ATF_TC(fork_wait__unprivileged_both
);
531 ATF_TC_HEAD(fork_wait__unprivileged_both
, tc
)
533 atf_tc_set_md_var(tc
, "require.config", "unprivileged-user");
534 atf_tc_set_md_var(tc
, "require.user", "root");
536 ATF_TC_BODY(fork_wait__unprivileged_both
, tc
)
538 const struct passwd
* pw
= getpwnam(atf_tc_get_config_var(
539 tc
, "unprivileged-user"));
540 ATF_REQUIRE_MSG(pw
!= NULL
, "Cannot find unprivileged user");
542 kyua_run_params_t run_params
;
543 kyua_run_params_init(&run_params
);
544 run_params
.unprivileged_user
= pw
->pw_uid
;
545 run_params
.unprivileged_group
= pw
->pw_gid
;
547 ATF_REQUIRE_MSG(fork_check(&run_params
, check_not_root
, NULL
),
548 "Subprocess is still running with root privileges");
552 ATF_TC_WITHOUT_HEAD(fork_wait__work_directory
);
553 ATF_TC_BODY(fork_wait__work_directory
, tc
)
555 ATF_REQUIRE(mkdir("the-work-directory", 0755) != -1);
556 atf_utils_create_file("the-work-directory/data-file", "%s", "");
558 kyua_run_params_t run_params
;
559 kyua_run_params_init(&run_params
);
560 run_params
.work_directory
= "./the-work-directory";
561 ATF_REQUIRE_MSG(fork_check(&run_params
, check_work_directory
, "data-file"),
562 "Subprocess not in its own process group");
566 ATF_TC_WITHOUT_HEAD(work_directory__builtin_tmpdir
);
567 ATF_TC_BODY(work_directory__builtin_tmpdir
, tc
)
570 RE(kyua_fs_make_absolute("worktest", &tmpdir
));
571 ATF_REQUIRE(mkdir(tmpdir
, 0755) != -1);
572 RE(kyua_env_unset("TMPDIR"));
573 kyua_run_tmpdir
= tmpdir
;
575 char* work_directory
;
576 RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
581 RE(kyua_fs_concat(&template_test
, atf_tc_get_config_var(tc
, "srcdir"),
582 "worktest", "template.XXXXXX", NULL
));
583 ATF_REQUIRE(access(template_test
, X_OK
) == -1);
587 ATF_REQUIRE(access(work_directory
, X_OK
) != -1);
589 ATF_REQUIRE(rmdir(tmpdir
) == -1); // Not yet empty.
590 RE(kyua_run_work_directory_leave(&work_directory
));
591 ATF_REQUIRE(rmdir(tmpdir
) != -1);
596 ATF_TC_WITHOUT_HEAD(work_directory__env_tmpdir
);
597 ATF_TC_BODY(work_directory__env_tmpdir
, tc
)
600 RE(kyua_fs_make_absolute("worktest", &tmpdir
));
601 ATF_REQUIRE(mkdir(tmpdir
, 0755) != -1);
602 RE(kyua_env_set("TMPDIR", tmpdir
));
604 char* work_directory
;
605 RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
610 RE(kyua_fs_concat(&template_test
, atf_tc_get_config_var(tc
, "srcdir"),
611 "worktest", "template.XXXXXX", NULL
));
612 ATF_REQUIRE(access(template_test
, X_OK
) == -1);
616 ATF_REQUIRE(access(work_directory
, X_OK
) != -1);
618 ATF_REQUIRE(rmdir(tmpdir
) == -1); // Not yet empty.
619 RE(kyua_run_work_directory_leave(&work_directory
));
620 ATF_REQUIRE(rmdir(tmpdir
) != -1);
625 ATF_TC(work_directory__permissions
);
626 ATF_TC_HEAD(work_directory__permissions
, tc
)
628 atf_tc_set_md_var(tc
, "require.config", "unprivileged-user");
629 atf_tc_set_md_var(tc
, "require.user", "root");
631 ATF_TC_BODY(work_directory__permissions
, tc
)
633 const struct passwd
* pw
= getpwnam(atf_tc_get_config_var(
634 tc
, "unprivileged-user"));
636 printf("%d %d %d %d\n", getuid(), getgid(), pw
->pw_uid
, pw
->pw_gid
);
638 char* work_directory
;
639 RE(kyua_run_work_directory_enter("template.XXXXXX", pw
->pw_uid
, pw
->pw_gid
,
643 ATF_REQUIRE(stat(work_directory
, &sb
) != -1);
644 ATF_REQUIRE_EQ(pw
->pw_uid
, sb
.st_uid
);
645 ATF_REQUIRE_EQ(pw
->pw_gid
, sb
.st_gid
);
647 RE(kyua_run_work_directory_leave(&work_directory
));
651 ATF_TC(work_directory__mkdtemp_error
);
652 ATF_TC_HEAD(work_directory__mkdtemp_error
, tc
)
654 atf_tc_set_md_var(tc
, "require.user", "unprivileged");
656 ATF_TC_BODY(work_directory__mkdtemp_error
, tc
)
659 RE(kyua_fs_make_absolute("worktest", &tmpdir
));
660 ATF_REQUIRE(mkdir(tmpdir
, 0555) != -1);
661 RE(kyua_env_set("TMPDIR", tmpdir
));
663 char* work_directory
;
664 const kyua_error_t error
= kyua_run_work_directory_enter(
665 "template.XXXXXX", getuid(), getgid(), &work_directory
);
666 ATF_REQUIRE(kyua_error_is_set(error
));
667 ATF_REQUIRE(kyua_error_is_type(error
, "libc"));
668 ATF_REQUIRE_EQ(EACCES
, kyua_libc_error_errno(error
));
669 kyua_error_free(error
);
671 ATF_REQUIRE(rmdir(tmpdir
) != -1); // Empty; subdirectory not created.
676 ATF_TC(work_directory__permissions_error
);
677 ATF_TC_HEAD(work_directory__permissions_error
, tc
)
679 atf_tc_set_md_var(tc
, "require.user", "unprivileged");
681 ATF_TC_BODY(work_directory__permissions_error
, tc
)
684 RE(kyua_fs_make_absolute("worktest", &tmpdir
));
685 ATF_REQUIRE(mkdir(tmpdir
, 0755) != -1);
686 RE(kyua_env_set("TMPDIR", tmpdir
));
688 char* work_directory
;
689 const kyua_error_t error
= kyua_run_work_directory_enter(
690 "template.XXXXXX", getuid() + 1, getgid(), &work_directory
);
691 ATF_REQUIRE(kyua_error_is_set(error
));
692 ATF_REQUIRE(kyua_error_is_type(error
, "libc"));
693 ATF_REQUIRE_EQ(EPERM
, kyua_libc_error_errno(error
));
694 kyua_error_free(error
);
696 ATF_REQUIRE(rmdir(tmpdir
) != -1); // Empty; subdirectory not created.
701 /// Performs a signal delivery test to the work directory handling code.
703 /// \param signo The signal to deliver.
705 work_directory_signal_check(const int signo
)
708 RE(kyua_fs_make_absolute("worktest", &tmpdir
));
709 ATF_REQUIRE(mkdir(tmpdir
, 0755) != -1);
710 RE(kyua_env_set("TMPDIR", tmpdir
));
712 char* work_directory
;
713 RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
716 kyua_run_params_t run_params
;
717 kyua_run_params_init(&run_params
);
718 run_params
.work_directory
= work_directory
;
721 RE(kyua_run_fork(&run_params
, &pid
));
723 sleep(run_params
.timeout_seconds
* 2);
727 // This should cause the handled installed by the work_directory management
728 // code to terminate the subprocess so that we get a chance to run the
729 // cleanup code ourselves.
730 kill(getpid(), signo
);
732 int status
; bool timed_out
;
733 RE(kyua_run_wait(pid
, &status
, &timed_out
));
734 ATF_REQUIRE(!timed_out
);
735 ATF_REQUIRE(WIFSIGNALED(status
));
736 ATF_REQUIRE_EQ(SIGKILL
, WTERMSIG(status
));
738 ATF_REQUIRE(rmdir(tmpdir
) == -1); // Not yet empty.
739 RE(kyua_run_work_directory_leave(&work_directory
));
740 ATF_REQUIRE(rmdir(tmpdir
) != -1);
745 ATF_TC_WITHOUT_HEAD(work_directory__sighup
);
746 ATF_TC_BODY(work_directory__sighup
, tc
)
748 work_directory_signal_check(SIGHUP
);
752 ATF_TC_WITHOUT_HEAD(work_directory__sigint
);
753 ATF_TC_BODY(work_directory__sigint
, tc
)
755 work_directory_signal_check(SIGINT
);
759 ATF_TC_WITHOUT_HEAD(work_directory__sigterm
);
760 ATF_TC_BODY(work_directory__sigterm
, tc
)
762 work_directory_signal_check(SIGTERM
);
768 ATF_TP_ADD_TC(tp
, run_params_init__defaults
);
770 ATF_TP_ADD_TC(tp
, fork_exec_wait__ok
);
771 ATF_TP_ADD_TC(tp
, fork_exec_wait__eacces
);
772 ATF_TP_ADD_TC(tp
, fork_exec_wait__enoent
);
774 ATF_TP_ADD_TC(tp
, fork_wait__core_size
);
775 ATF_TP_ADD_TC(tp
, fork_wait__env
);
776 ATF_TP_ADD_TC(tp
, fork_wait__process_group
);
777 ATF_TP_ADD_TC(tp
, fork_wait__signals
);
778 ATF_TP_ADD_TC(tp
, fork_wait__timeout
);
779 ATF_TP_ADD_TC(tp
, fork_wait__umask
);
780 ATF_TP_ADD_TC(tp
, fork_wait__unprivileged_user
);
781 ATF_TP_ADD_TC(tp
, fork_wait__unprivileged_group
);
782 ATF_TP_ADD_TC(tp
, fork_wait__unprivileged_both
);
783 ATF_TP_ADD_TC(tp
, fork_wait__work_directory
);
785 ATF_TP_ADD_TC(tp
, work_directory__builtin_tmpdir
);
786 ATF_TP_ADD_TC(tp
, work_directory__env_tmpdir
);
787 ATF_TP_ADD_TC(tp
, work_directory__permissions
);
788 ATF_TP_ADD_TC(tp
, work_directory__permissions_error
);
789 ATF_TP_ADD_TC(tp
, work_directory__mkdtemp_error
);
790 ATF_TP_ADD_TC(tp
, work_directory__sighup
);
791 ATF_TP_ADD_TC(tp
, work_directory__sigint
);
792 ATF_TP_ADD_TC(tp
, work_directory__sigterm
);
794 return atf_no_error();