[2/5] fown: test -- Add file_fown_dead

Submitted by Cyrill Gorcunov on Dec. 7, 2018, 12:29 p.m.

Details

Message ID 20181207122948.26683-3-gorcunov@gmail.com
State New
Series "fown: Handle dead pids and O_PATH"
Headers show

Commit Message

Cyrill Gorcunov Dec. 7, 2018, 12:29 p.m.
Just setup owner to a pid which immediately exit
and file left with dead pid assigned.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 test/zdtm/static/Makefile            |   1 +
 test/zdtm/static/file_fown_dead.c    | 192 +++++++++++++++++++++++++++
 test/zdtm/static/file_fown_dead.desc |   1 +
 3 files changed, 194 insertions(+)
 create mode 100644 test/zdtm/static/file_fown_dead.c
 create mode 100644 test/zdtm/static/file_fown_dead.desc

Patch hide | download patch | download mbox

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 7b8d663778b6..ab20c61b3574 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -119,6 +119,7 @@  TST_NOFILE	:=				\
 		groups				\
 		pdeath_sig			\
 		file_fown			\
+		file_fown_dead			\
 		proc-self			\
 		eventfs00			\
 		epoll				\
diff --git a/test/zdtm/static/file_fown_dead.c b/test/zdtm/static/file_fown_dead.c
new file mode 100644
index 000000000000..3a99bc729f51
--- /dev/null
+++ b/test/zdtm/static/file_fown_dead.c
@@ -0,0 +1,192 @@ 
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+
+#include "zdtmtst.h"
+
+#ifndef F_SETSIG
+#define F_SETSIG	10	/* for sockets. */
+#define F_GETSIG	11	/* for sockets. */
+#endif
+
+const char *test_doc	= "Check for restore with dead file owners";
+const char *test_author	= "Cyrill Gorcunov <gorcunov@openvz.org>";
+
+struct params {
+	int	sigio;
+	int	pipe_flags[2];
+	int	pipe_pid[2];
+	int	pipe_sig[2];
+} *shared;
+
+static void signal_handler_io(int status)
+{
+	shared->sigio++;
+}
+
+static void fill_pipe_params(struct params *p, int *pipes)
+{
+	p->pipe_flags[0] = fcntl(pipes[0], F_GETFL);
+	p->pipe_flags[1] = fcntl(pipes[1], F_GETFL);
+
+	test_msg("pipe_flags0 %08o\n", p->pipe_flags[0]);
+	test_msg("pipe_flags1 %08o\n", p->pipe_flags[1]);
+
+	p->pipe_pid[0] = fcntl(pipes[0], F_GETOWN);
+	p->pipe_pid[1] = fcntl(pipes[1], F_GETOWN);
+
+	p->pipe_sig[0] = fcntl(pipes[0], F_GETSIG);
+	p->pipe_sig[1] = fcntl(pipes[1], F_GETSIG);
+}
+
+static int cmp_pipe_params(struct params *p1, struct params *p2)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (p1->pipe_flags[i] != p2->pipe_flags[i]) {
+			fail("pipe flags failed [%d] expected %08o got %08o\n",
+			     i, p1->pipe_flags[i], p2->pipe_flags[i]);
+			return -1;
+		}
+		if (p1->pipe_pid[i] != p2->pipe_pid[i]) {
+			fail("pipe pid failed [%d] expected %d got %d\n",
+			     i, p1->pipe_pid[i], p2->pipe_pid[i]);
+			return -1;
+		}
+		if (p1->pipe_sig[i] != p2->pipe_sig[i]) {
+			fail("pipe sig failed [%d] expected %d got %d\n",
+			     i, p1->pipe_sig[i], p2->pipe_sig[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct sigaction saio = { };
+	struct params obtained = { };
+	uid_t ruid, euid, suid;
+	int status, pipes[2];
+	pid_t pid;
+
+	test_init(argc, argv);
+
+	shared = (void *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if ((void *)shared == MAP_FAILED) {
+		fail("mmap failed");
+		exit(1);
+	}
+
+	if (getresuid(&ruid, &euid, &suid)) {
+		fail("getresuid failed\n");
+		exit(1);
+	}
+
+	if (pipe(pipes)) {
+		pr_perror("Can't create pipe");
+		exit(1);
+	}
+
+	saio.sa_handler	= (sig_t)signal_handler_io;
+	saio.sa_flags	= SA_RESTART;
+	if (sigaction(SIGIO, &saio, 0)) {
+		fail("sigaction failed\n");
+		exit(1);
+	}
+
+	if (!getuid() && setresuid(-1, 1, -1)) {
+		fail("setresuid failed\n");
+		exit(1);
+	}
+
+	if (fcntl(pipes[0], F_SETOWN, getpid())					||
+	    fcntl(pipes[1], F_SETOWN, getpid())					||
+	    fcntl(pipes[0], F_SETSIG, SIGIO)					||
+	    fcntl(pipes[1], F_SETSIG, SIGIO)					||
+	    fcntl(pipes[0], F_SETFL, fcntl(pipes[0], F_GETFL) | O_ASYNC)	||
+	    fcntl(pipes[1], F_SETFL, fcntl(pipes[1], F_GETFL) | O_ASYNC)) {
+		fail("fcntl failed\n");
+		exit(1);
+	}
+
+	fill_pipe_params(shared, pipes);
+
+	if (setresuid(-1, euid, -1)) {
+		fail("setresuid failed\n");
+		exit(1);
+	}
+
+	pid = test_fork();
+	if (pid < 0) {
+		pr_perror("can't fork");
+		exit(1);
+	} else if (pid == 0) {
+		struct params p = { };
+
+		fcntl(pipes[1], F_SETOWN, getpid());
+		fill_pipe_params(&p, pipes);
+
+		if (write(pipes[1], &p, sizeof(p)) != sizeof(p)) {
+			fail("write failed\n");
+			exit(1);
+		}
+
+		exit(0);
+	}
+
+	if (waitpid(pid, &status, P_ALL) == -1) {
+		fail("waitpid %d failed\n", pid);
+		exit(1);
+	}
+
+	test_daemon();
+	test_waitsig();
+
+	if (read(pipes[0], &obtained, sizeof(obtained)) != sizeof(obtained)) {
+		fail("read failed\n");
+		exit(1);
+	}
+
+	if (shared->sigio < 1) {
+		fail("shared->sigio = %d (> 0 expected)\n", shared->sigio);
+		exit(1);
+	}
+
+	shared->pipe_pid[1] = pid;
+
+	if (cmp_pipe_params(shared, &obtained)) {
+		fail("params comparison failed\n");
+		exit(1);
+	}
+
+	/*
+	 * The F_SETOWN above operates on child which
+	 * is already exited so in criu we should skip
+	 * setting PID back and in result there must
+	 * be a zero.
+	 */
+	obtained.pipe_pid[1] = 0;
+
+	fill_pipe_params(shared, pipes);
+
+	if (cmp_pipe_params(shared, &obtained)) {
+		fail("params comparison failed\n");
+		exit(1);
+	}
+
+	pass();
+	return 0;
+}
diff --git a/test/zdtm/static/file_fown_dead.desc b/test/zdtm/static/file_fown_dead.desc
new file mode 100644
index 000000000000..63df42aa670a
--- /dev/null
+++ b/test/zdtm/static/file_fown_dead.desc
@@ -0,0 +1 @@ 
+{'flavor': 'h'}