int main(int ac, char **av) { int lc; const char *msg; if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { /* Check ONLYDIR on a directory */ CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL); /* Check ONLYDIR without a directory */ CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL); /* Check DONT_FOLLOW for a symlink */ CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink); /* Check without DONT_FOLLOW for a symlink */ CHECK_MARK(sname, 0, 0, test_open_file); /* Verify FAN_MARK_FLUSH destroys all inode marks */ if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, " "AT_FDCWD, '%s') failed", fd_notify, fname); } if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | " "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify, dir); } open_file(fname); verify_event(S_IFREG); open_dir(dir); verify_event(S_IFDIR); if (myfanotify_mark(fd_notify, FAN_MARK_FLUSH, 0, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_FLUSH, 0, " "AT_FDCWD, '.') failed", fd_notify); } open_dir(dir); verify_no_event(); } cleanup(); tst_exit(); }
void test01(void) { /* Check ONLYDIR on a directory */ CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL); /* Check ONLYDIR without a directory */ CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL); /* Check DONT_FOLLOW for a symlink */ CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink); /* Check without DONT_FOLLOW for a symlink */ CHECK_MARK(sname, 0, 0, test_open_file); /* Verify FAN_MARK_FLUSH destroys all inode marks */ if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, fname) < 0) { tst_brk(TBROK | TERRNO, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, " "AT_FDCWD, '%s') failed", fd_notify, fname); } if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) { tst_brk(TBROK | TERRNO, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | " "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify, dir); } open_file(fname); verify_event(S_IFREG); open_dir(dir); verify_event(S_IFDIR); if (fanotify_mark(fd_notify, FAN_MARK_FLUSH, 0, AT_FDCWD, ".") < 0) { tst_brk(TBROK | TERRNO, "fanotify_mark (%d, FAN_MARK_FLUSH, 0, " "AT_FDCWD, '.') failed", fd_notify); } open_dir(dir); verify_no_event(); }
static void do_spawn (void) { int n; int size; uid_t uid; gid_t gid; int env_inherit; pid_t child; int envs = 0; int log_stderr = 0; char *interpreter = NULL; char *log_file = NULL; char *uid_str = NULL; char *chroot_dir = NULL; char **envp = NULL; char *p = spawn_shared; const char *argv[] = {"sh", "-c", NULL, NULL}; #define CHECK_MARK(val) \ if ((*(int *)p) != val) { \ goto cleanup; \ } else { \ p += sizeof(int); \ } #define ALIGN4(buf) while ((long)p & 0x3) p++; /* Read the shared memory */ /* 1.- Interpreter */ CHECK_MARK (0xF0); size = *((int *)p); p += sizeof(int); if (size <= 0) { goto cleanup; } interpreter = malloc (sizeof("exec ") + size); if (interpreter == NULL) { goto cleanup; } strncpy (interpreter, "exec ", 5); strncpy (interpreter + 5, p, size + 1); p += size + 1; ALIGN4 (p); /* 2.- UID & GID */ CHECK_MARK (0xF1); size = *((int *)p); if (size > 0) { uid_str = strdup (p + sizeof(int)); } p += sizeof(int) + size + 1; ALIGN4 (p); memcpy (&uid, p, sizeof(uid_t)); p += sizeof(uid_t); memcpy (&gid, p, sizeof(gid_t)); p += sizeof(gid_t); /* 3.- Chroot directory */ CHECK_MARK (0xF2); size = *((int *) p); p += sizeof(int); if (size > 0) { chroot_dir = malloc(size + 1); memcpy(chroot_dir, p, size + 1); } p += size + 1; ALIGN4 (p); /* 4.- Environment */ CHECK_MARK (0xF3); env_inherit = *((int *)p); p += sizeof(int); envs = *((int *)p); p += sizeof(int); envp = malloc (sizeof(char *) * (envs + 1)); if (envp == NULL) { goto cleanup; } envp[envs] = NULL; for (n=0; n<envs; n++) { char *e; size = *((int *)p); p += sizeof(int); e = malloc (size + 1); if (e == NULL) { goto cleanup; } memcpy (e, p, size); e[size] = '\0'; envp[n] = e; p += size + 1; ALIGN4 (p); } /* 5.- Error log */ CHECK_MARK (0xF4); size = *((int *)p); p += sizeof(int); if (size > 0) { if (! strncmp (p, "stderr", 6)) { log_stderr = 1; } else if (! strncmp (p, "file,", 5)) { log_file = p+5; } p += (size + 1); ALIGN4 (p); } /* 6.- PID: it's -1 now */ CHECK_MARK (0xF5); n = *((int *)p); if (n > 0) { kill (n, SIGTERM); *p = -1; } /* Spawn */ child = fork(); switch (child) { case 0: { int i; struct sigaction sig_action; /* Reset signal handlers */ sig_action.sa_handler = SIG_DFL; sig_action.sa_flags = 0; sigemptyset (&sig_action.sa_mask); for (i=0 ; i < NSIG ; i++) { sigaction (i, &sig_action, NULL); } /* Logging */ if (log_file) { int fd; fd = open (log_file, O_WRONLY | O_APPEND | O_CREAT, 0600); if (fd < 0) { PRINT_ERROR ("(warning) Couldn't open '%s' for writing..\n", log_file); } close (STDOUT_FILENO); close (STDERR_FILENO); dup2 (fd, STDOUT_FILENO); dup2 (fd, STDERR_FILENO); } else if (log_stderr) { /* do nothing */ } else { int tmp_fd; tmp_fd = open ("/dev/null", O_WRONLY); close (STDOUT_FILENO); close (STDERR_FILENO); dup2 (tmp_fd, STDOUT_FILENO); dup2 (tmp_fd, STDERR_FILENO); } /* Change root */ if (chroot_dir) { int re = chroot(chroot_dir); if (re < 0) { PRINT_ERROR ("(critial) Couldn't chroot to %s\n", chroot_dir); exit (1); } } /* Change user & group */ if (uid_str != NULL) { n = initgroups (uid_str, gid); if (n == -1) { PRINT_ERROR ("(warning) initgroups failed User=%s, GID=%d\n", uid_str, gid); } } if ((int)gid != -1) { n = setgid (gid); if (n != 0) { PRINT_ERROR ("(warning) Couldn't set GID=%d\n", gid); } } if ((int)uid != -1) { n = setuid (uid); if (n != 0) { PRINT_ERROR ("(warning) Couldn't set UID=%d\n", uid); } } /* Clean the shared memory */ size = (p - spawn_shared) - sizeof(int); memset (spawn_shared, 0, size); /* Execute the interpreter */ argv[2] = interpreter; if (env_inherit) { do { execv ("/bin/sh", (char **)argv); } while (errno == EINTR); } else { do { execve ("/bin/sh", (char **)argv, envp); } while (errno == EINTR); } PRINT_MSG ("(critical) Couldn't spawn: sh -c %s\n", interpreter); exit (1); } case -1: /* Error */ PRINT_MSG ("(critical) Couldn't fork(): %s\n", strerror(errno)); goto cleanup; default: break; } /* Return the PID */ memcpy (p, (char *)&child, sizeof(int)); printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, chroot=%s, env=%s\n", child, interpreter, uid, gid, chroot_dir, env_inherit ? "inherited":"custom"); cleanup: /* Unlock worker */ do_sem_op (SEM_LAUNCH_READY, 1); /* Clean up */ free (uid_str); free (interpreter); free (chroot_dir); if (envp != NULL) { for (n=0; n<envs; n++) { free (envp[n]); } free (envp); } }