4 * Copyright Ralph Boehme <slow@samba.org> 2017
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "system/select.h"
26 #include "libcli/util/ntstatus.h"
27 #include "torture/torture.h"
28 #include "lib/util/data_blob.h"
29 #include "torture/local/proto.h"
30 #include "lib/util/tfork.h"
31 #include "lib/util/samba_util.h"
32 #include "lib/util/sys_rw.h"
35 #include <sys/syscall.h>
38 static bool test_tfork_simple(struct torture_context *tctx)
40 pid_t parent = getpid();
41 struct tfork *t = NULL;
47 torture_fail(tctx, "tfork failed\n");
50 child = tfork_child_pid(t);
52 torture_comment(tctx, "my parent pid is %d\n", parent);
53 torture_assert(tctx, getpid() != parent, "tfork failed\n");
57 ret = tfork_destroy(&t);
58 torture_assert(tctx, ret == 0, "tfork_destroy failed\n");
63 static bool test_tfork_status(struct torture_context *tctx)
65 struct tfork *t = NULL;
72 torture_fail(tctx, "tfork failed\n");
75 child = tfork_child_pid(t);
80 status = tfork_status(&t, true);
82 torture_fail(tctx, "tfork_status failed\n");
85 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
87 torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
90 torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
96 static bool test_tfork_sigign(struct torture_context *tctx)
98 struct tfork *t = NULL;
105 act = (struct sigaction) {
106 .sa_flags = SA_NOCLDWAIT,
107 .sa_handler = SIG_IGN,
110 ret = sigaction(SIGCHLD, &act, NULL);
111 torture_assert_goto(tctx, ret == 0, ok, done, "sigaction failed\n");
115 torture_fail(tctx, "tfork failed\n");
118 child = tfork_child_pid(t);
126 torture_fail(tctx, "fork failed\n");
133 status = tfork_status(&t, true);
135 torture_fail(tctx, "tfork_status failed\n");
138 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
140 torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
142 torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
148 static void sigchld_handler1(int signum, siginfo_t *si, void *u)
153 if (signum != SIGCHLD) {
157 pid = waitpid(si->si_pid, &status, 0);
158 if (pid != si->si_pid) {
163 static bool test_tfork_sighandler(struct torture_context *tctx)
165 struct tfork *t = NULL;
166 struct sigaction act;
167 struct sigaction oldact;
173 act = (struct sigaction) {
174 .sa_flags = SA_SIGINFO,
175 .sa_sigaction = sigchld_handler1,
178 ret = sigaction(SIGCHLD, &act, &oldact);
179 torture_assert_goto(tctx, ret == 0, ok, done, "sigaction failed\n");
183 torture_fail(tctx, "tfork failed\n");
186 child = tfork_child_pid(t);
194 torture_fail(tctx, "fork failed\n");
201 status = tfork_status(&t, true);
203 torture_fail(tctx, "tfork_status failed\n");
206 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
208 torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
210 torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
213 sigaction(SIGCHLD, &oldact, NULL);
218 static bool test_tfork_process_hierarchy(struct torture_context *tctx)
220 struct tfork *t = NULL;
221 pid_t pid = getpid();
223 pid_t pgid = getpgid(0);
224 pid_t sid = getsid(0);
225 char *procpath = NULL;
231 procpath = talloc_asprintf(tctx, "/proc/%d/status", getpid());
232 torture_assert_not_null(tctx, procpath, "talloc_asprintf failed\n");
234 ret = stat(procpath, &st);
235 TALLOC_FREE(procpath);
237 if (errno == ENOENT) {
238 torture_skip(tctx, "/proc missing\n");
240 torture_fail(tctx, "stat failed\n");
245 torture_fail(tctx, "tfork failed\n");
248 child = tfork_child_pid(t);
256 torture_assert_goto(tctx, pgid == getpgid(0), ok, child_fail, "tfork failed\n");
257 torture_assert_goto(tctx, sid == getsid(0), ok, child_fail, "tfork failed\n");
259 cmd = talloc_asprintf(tctx, "cat /proc/%d/status | awk '/^PPid:/ {print $2}'", getppid());
260 torture_assert_goto(tctx, cmd != NULL, ok, child_fail, "talloc_asprintf failed\n");
262 fp = popen(cmd, "r");
263 torture_assert_goto(tctx, fp != NULL, ok, child_fail, "popen failed\n");
265 p = fgets(line, sizeof(line) - 1, fp);
267 torture_assert_goto(tctx, p != NULL, ok, child_fail, "popen failed\n");
269 ret = sscanf(line, "%d", &ppid);
270 torture_assert_goto(tctx, ret == 1, ok, child_fail, "sscanf failed\n");
271 torture_assert_goto(tctx, ppid == pid, ok, child_fail, "process hierachy not rooted at caller\n");
279 status = tfork_status(&t, true);
281 torture_fail(tctx, "tfork_status failed\n");
284 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
286 torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
288 torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
294 static bool test_tfork_pipe(struct torture_context *tctx)
296 struct tfork *t = NULL;
306 torture_assert(tctx, ret == 0, "pipe failed\n");
308 ret = pipe(&down[0]);
309 torture_assert(tctx, ret == 0, "pipe failed\n");
313 torture_fail(tctx, "tfork failed\n");
316 child = tfork_child_pid(t);
321 ret = read(down[0], &c, 1);
322 torture_assert_goto(tctx, ret == 1, ok, child_fail, "read failed\n");
323 torture_assert_goto(tctx, c == 1, ok, child_fail, "read failed\n");
325 ret = write(up[1], &(char){2}, 1);
326 torture_assert_goto(tctx, ret == 1, ok, child_fail, "write failed\n");
337 ret = write(down[1], &(char){1}, 1);
338 torture_assert(tctx, ret == 1, "read failed\n");
340 ret = read(up[0], &c, 1);
341 torture_assert(tctx, ret == 1, "read failed\n");
342 torture_assert(tctx, c == 2, "read failed\n");
344 status = tfork_status(&t, true);
346 torture_fail(tctx, "tfork_status failed\n");
349 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
351 torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
357 static bool test_tfork_twice(struct torture_context *tctx)
359 struct tfork *t = NULL;
368 torture_assert(tctx, ret == 0, "pipe failed\n");
372 torture_fail(tctx, "tfork failed\n");
375 child = tfork_child_pid(t);
381 torture_fail(tctx, "tfork failed\n");
384 child = tfork_child_pid(t);
388 ret = write(up[1], &pid, sizeof(pid_t));
389 torture_assert_goto(tctx, ret == sizeof(pid_t), ok, child_fail, "write failed\n");
402 ret = read(up[0], &pid, sizeof(pid_t));
403 torture_assert(tctx, ret == sizeof(pid_t), "read failed\n");
405 status = tfork_status(&t, true);
406 torture_assert_goto(tctx, status != -1, ok, done, "tfork_status failed\n");
408 torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
410 torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
416 static void *tfork_thread(void *p)
418 struct tfork *t = NULL;
421 pthread_t *ptid = (pthread_t *)p;
423 uint64_t *result = NULL;
433 tid = (uint64_t)*ptid;
439 child = tfork_child_pid(t);
445 nwritten = sys_write(up[1], &tid, sizeof(uint64_t));
446 if (nwritten != sizeof(uint64_t)) {
453 result = malloc(sizeof(uint64_t));
454 if (result == NULL) {
458 nread = sys_read(up[0], result, sizeof(uint64_t));
459 if (nread != sizeof(uint64_t)) {
463 status = tfork_status(&t, true);
468 pthread_exit(result);
471 static bool test_tfork_threads(struct torture_context *tctx)
475 const int num_threads = 64;
476 pthread_t threads[num_threads];
480 torture_skip(tctx, "no pthread support\n");
483 for (i = 0; i < num_threads; i++) {
484 ret = pthread_create(&threads[i], NULL, tfork_thread, &threads[i]);
485 torture_assert_goto(tctx, ret == 0, ok, done,
486 "pthread_create failed\n");
489 for (i = 0; i < num_threads; i++) {
493 ret = pthread_join(threads[i], &p);
494 torture_assert_goto(tctx, ret == 0, ok, done,
495 "pthread_join failed\n");
496 result = (uint64_t *)p;
497 torture_assert_goto(tctx, *result == (uint64_t)threads[i] + 1,
498 ok, done, "thread failed\n");
506 static bool test_tfork_cmd_send(struct torture_context *tctx)
508 struct tevent_context *ev = NULL;
509 struct tevent_req *req = NULL;
510 const char *cmd[2] = { NULL, NULL };
513 ev = tevent_context_init(tctx);
514 torture_assert_goto(tctx, ev != NULL, ok, done,
515 "tevent_context_init failed\n");
517 cmd[0] = talloc_asprintf(tctx, "%s/testprogs/blackbox/tfork.sh", SRCDIR);
518 torture_assert_goto(tctx, cmd[0] != NULL, ok, done,
519 "talloc_asprintf failed\n");
521 req = samba_runcmd_send(tctx, ev, timeval_zero(), 0, 0,
523 torture_assert_goto(tctx, req != NULL, ok, done,
524 "samba_runcmd_send failed\n");
526 ok = tevent_req_poll(req, ev);
527 torture_assert_goto(tctx, ok, ok, done, "tevent_req_poll failed\n");
529 torture_comment(tctx, "samba_runcmd_send test finished\n");
538 * Test to ensure that the event_fd becomes readable after
539 * a tfork_process terminates.
541 static bool test_tfork_event_file_handle(struct torture_context *tctx)
545 struct tfork *t1 = NULL;
547 struct pollfd poll1[] = { {-1, POLLIN} };
549 struct tfork *t2 = NULL;
551 struct pollfd poll2[] = { {-1, POLLIN} };
556 torture_fail(tctx, "tfork failed\n");
560 child1 = tfork_child_pid(t1);
563 * Parent process will kill this with a SIGTERM
564 * so 10 seconds should be plenty
569 poll1[0].fd = tfork_event_fd(t1);
573 torture_fail(tctx, "tfork failed\n");
576 child2 = tfork_child_pid(t2);
579 * Parent process will kill this with a SIGTERM
580 * so 10 seconds should be plenty
585 poll2[0].fd = tfork_event_fd(t2);
588 * Have forked two process and are in the master process
589 * Expect that both event_fds are unreadable
592 ok = !(poll1[0].revents & POLLIN);
593 torture_assert_goto(tctx, ok, ok, done,
594 "tfork process 1 event fd readable\n");
596 ok = !(poll2[0].revents & POLLIN);
597 torture_assert_goto(tctx, ok, ok, done,
598 "tfork process 1 event fd readable\n");
600 /* Kill the first child process */
601 kill(child1, SIGKILL);
605 * Have killed the first child, so expect it's event_fd to have gone
610 ok = (poll1[0].revents & POLLIN);
611 torture_assert_goto(tctx, ok, ok, done,
612 "tfork process 1 event fd not readable\n");
614 ok = !(poll2[0].revents & POLLIN);
615 torture_assert_goto(tctx, ok, ok, done,
616 "tfork process 2 event fd readable\n");
618 /* Kill the secind child process */
619 kill(child2, SIGKILL);
622 * Have killed the children, so expect their event_fd's to have gone
627 ok = (poll1[0].revents & POLLIN);
628 torture_assert_goto(tctx, ok, ok, done,
629 "tfork process 1 event fd not readable\n");
631 ok = (poll2[0].revents & POLLIN);
632 torture_assert_goto(tctx, ok, ok, done,
633 "tfork process 2 event fd not readable\n");
640 * Test to ensure that the status calls behave as expected after a process
643 * As the parent process owns the status fd's they get passed to all
644 * subsequent children after a tfork. So it's possible for another
645 * child process to hold the status pipe open.
647 * The event fd needs to be left open by tfork, as a close in the status
648 * code can cause issues in tevent code.
651 static bool test_tfork_status_handle(struct torture_context *tctx)
655 struct tfork *t1 = NULL;
658 struct tfork *t2 = NULL;
669 torture_fail(tctx, "tfork failed\n");
673 child1 = tfork_child_pid(t1);
676 * Parent process will kill this with a SIGTERM
677 * so 10 seconds should be plenty
682 ev1_fd = tfork_event_fd(t1);
686 torture_fail(tctx, "tfork failed\n");
689 child2 = tfork_child_pid(t2);
692 * Parent process will kill this with a SIGTERM
693 * so 10 seconds should be plenty
698 ev2_fd = tfork_event_fd(t2);
701 * Have forked two process and are in the master process
702 * expect that the status call will block, and hence return -1
703 * as the processes are still running
704 * The event fd's should be open.
706 status = tfork_status(&t1, false);
708 torture_assert_goto(tctx, ok, ok, done,
709 "tfork status available for non terminated "
711 /* Is the event fd open? */
714 torture_assert_goto(tctx, ok, ok, done,
715 "tfork process 1 event fd is not open");
717 status = tfork_status(&t2, false);
719 torture_assert_goto(tctx, ok, ok, done,
720 "tfork status avaiable for non terminated "
722 /* Is the event fd open? */
725 torture_assert_goto(tctx, ok, ok, done,
726 "tfork process 2 event fd is not open");
729 * Kill the first process, it's status should be readable
730 * and it's event_fd should be open
731 * The second process's status should be unreadable.
733 kill(child1, SIGTERM);
735 status = tfork_status(&t1, false);
737 torture_assert_goto(tctx, ok, ok, done,
738 "tfork status for child 1 not available after "
740 /* Is the event fd open? */
743 torture_assert_goto(tctx, ok, ok, done,
744 "tfork process 1 event fd is not open");
746 status = tfork_status(&t2, false);
748 torture_assert_goto(tctx, ok, ok, done,
749 "tfork status available for child 2 after "
750 "termination of child 1\n");
753 * Kill the second process, it's status should be readable
755 kill(child2, SIGTERM);
757 status = tfork_status(&t2, false);
759 torture_assert_goto(tctx, ok, ok, done,
760 "tfork status for child 2 not available after "
763 /* Check that the event fd's are still open */
764 /* Is the event fd open? */
767 torture_assert_goto(tctx, ok, ok, done,
768 "tfork process 1 event fd is not open");
769 /* Is the event fd open? */
772 torture_assert_goto(tctx, ok, ok, done,
773 "tfork process 2 event fd is not open");
779 struct torture_suite *torture_local_tfork(TALLOC_CTX *mem_ctx)
781 struct torture_suite *suite =
782 torture_suite_create(mem_ctx, "tfork");
784 torture_suite_add_simple_test(suite,
788 torture_suite_add_simple_test(suite,
792 torture_suite_add_simple_test(suite,
796 torture_suite_add_simple_test(suite,
798 test_tfork_sighandler);
800 torture_suite_add_simple_test(suite,
801 "tfork_process_hierarchy",
802 test_tfork_process_hierarchy);
804 torture_suite_add_simple_test(suite,
808 torture_suite_add_simple_test(suite,
812 torture_suite_add_simple_test(suite,
816 torture_suite_add_simple_test(suite,
818 test_tfork_cmd_send);
820 torture_suite_add_simple_test(suite,
821 "tfork_event_file_handle",
822 test_tfork_event_file_handle);
824 torture_suite_add_simple_test(suite,
825 "tfork_status_handle",
826 test_tfork_status_handle);