[3/3] compel: Test for FDs stealing

Submitted by Pavel Emelianov on March 6, 2017, 4:40 p.m.

Details

Message ID 58BD910A.8020804@virtuozzo.com
State New
Series "compel: Turn FDs plugin on"
Headers show

Commit Message

Pavel Emelianov March 6, 2017, 4:40 p.m.
An example, that steals stderr descriptor from victim task.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
---
 compel/test/fdspy/.gitignore |   4 +
 compel/test/fdspy/Makefile   |  28 +++++++
 compel/test/fdspy/parasite.c |  20 +++++
 compel/test/fdspy/spy.c      | 169 +++++++++++++++++++++++++++++++++++++++++++
 compel/test/fdspy/victim.c   |  12 +++
 5 files changed, 233 insertions(+)
 create mode 100644 compel/test/fdspy/.gitignore
 create mode 100644 compel/test/fdspy/Makefile
 create mode 100644 compel/test/fdspy/parasite.c
 create mode 100644 compel/test/fdspy/spy.c
 create mode 100644 compel/test/fdspy/victim.c

Patch hide | download patch | download mbox

diff --git a/compel/test/fdspy/.gitignore b/compel/test/fdspy/.gitignore
new file mode 100644
index 0000000..0a55475
--- /dev/null
+++ b/compel/test/fdspy/.gitignore
@@ -0,0 +1,4 @@ 
+parasite.h
+parasite.po
+spy
+victim
diff --git a/compel/test/fdspy/Makefile b/compel/test/fdspy/Makefile
new file mode 100644
index 0000000..4fed791
--- /dev/null
+++ b/compel/test/fdspy/Makefile
@@ -0,0 +1,28 @@ 
+CC	:= gcc
+CFLAGS	?= -O2 -g -Wall -Werror
+
+COMPEL		:= ../../../compel/compel-host
+
+all: victim spy
+
+clean:
+	rm -f victim
+	rm -f spy
+	rm -f parasite.h
+	rm -f parasite.po
+	rm -f parasite.o
+
+victim: victim.c
+	$(CC) $(CFLAGS) -o $@ $^
+
+spy: spy.c parasite.h
+	$(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(shell $(COMPEL) --static libs)
+
+parasite.h: parasite.po
+	$(COMPEL) hgen -o $@ -f $<
+
+parasite.po: parasite.o
+	ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins) ../../plugins/fds.built-in.o
+
+parasite.o: parasite.c
+	$(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^
diff --git a/compel/test/fdspy/parasite.c b/compel/test/fdspy/parasite.c
new file mode 100644
index 0000000..c14064b
--- /dev/null
+++ b/compel/test/fdspy/parasite.c
@@ -0,0 +1,20 @@ 
+#include <errno.h>
+
+#include <compel/plugins/plugin-fds.h>
+#include <compel/infect-rpc.h>
+
+/*
+ * Stubs for std compel plugin.
+ */
+int compel_main(void *arg_p, unsigned int arg_s) { return 0; }
+int parasite_trap_cmd(int cmd, void *args) { return 0; }
+void parasite_cleanup(void) { }
+
+#define PARASITE_CMD_GETFD	PARASITE_USER_CMDS
+
+int parasite_daemon_cmd(int cmd, void *args)
+{
+	if (cmd == PARASITE_CMD_GETFD)
+		fds_send_fd(2);
+	return 0;
+}
diff --git a/compel/test/fdspy/spy.c b/compel/test/fdspy/spy.c
new file mode 100644
index 0000000..258e3ab
--- /dev/null
+++ b/compel/test/fdspy/spy.c
@@ -0,0 +1,169 @@ 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include <compel/compel.h>
+#include "parasite.h"
+
+#define PARASITE_CMD_GETFD	PARASITE_USER_CMDS
+
+static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms)
+{
+	printf("\tLC%u: ", lvl);
+	vprintf(fmt, parms);
+}
+
+static int do_infection(int pid, int *stolen_fd)
+{
+#define err_and_ret(msg) do { fprintf(stderr, msg); return -1; } while (0)
+
+	int state;
+	struct parasite_ctl *ctl;
+	struct infect_ctx *ictx;
+
+	compel_log_init(print_vmsg, COMPEL_LOG_DEBUG);
+
+	printf("Stopping task\n");
+	state = compel_stop_task(pid);
+	if (state < 0)
+		err_and_ret("Can't stop task");
+
+	printf("Preparing parasite ctl\n");
+	ctl = compel_prepare(pid);
+	if (!ctl)
+		err_and_ret("Can't prepare for infection");
+
+	printf("Configuring contexts\n");
+
+	/*
+	 * First -- the infection context. Most of the stuff
+	 * is already filled by compel_prepare(), just set the
+	 * log descriptor for parasite side, library cannot
+	 * live w/o it.
+	 */
+	ictx = compel_infect_ctx(ctl);
+	ictx->log_fd = STDERR_FILENO;
+
+	parasite_setup_c_header(ctl);
+
+	printf("Infecting\n");
+	if (compel_infect(ctl, 1, sizeof(int)))
+		err_and_ret("Can't infect victim");
+
+	printf("Stealing fd\n");
+	if (compel_rpc_call(PARASITE_CMD_GETFD, ctl))
+		err_and_ret("Can't run cmd");
+
+	if (compel_util_recv_fd(ctl, stolen_fd))
+		err_and_ret("Can't recv fd");
+
+	if (compel_rpc_sync(PARASITE_CMD_GETFD, ctl))
+		err_and_ret("Con't finalize cmd");
+
+	printf("Stole %d fd\n", *stolen_fd);
+
+	/*
+	 * Done. Cure and resume the task.
+	 */
+	printf("Curing\n");
+	if (compel_cure(ctl))
+		err_and_ret("Can't cure victim");
+
+	if (compel_resume_task(pid, state, state))
+		err_and_ret("Can't unseize task");
+
+	printf("Done\n");
+	return 0;
+}
+
+static int check_pipe_ends(int wfd, int rfd)
+{
+	struct stat r, w;
+	char aux[4] = "0000";
+
+	printf("Check pipe ends are at hands\n");
+	if (fstat(wfd, &w) < 0) {
+		perror("Can't stat wfd");
+		return 0;
+	}
+
+	if (fstat(rfd, &r) < 0) {
+		perror("Can't stat rfd");
+		return 0;
+	}
+
+	if (w.st_dev != r.st_dev || w.st_ino != r.st_ino) {
+		perror("Pipe's not the same");
+		return 0;
+	}
+
+	printf("Check pipe ends are connected\n");
+	write(wfd, "1", 2);
+	read(rfd, aux, sizeof(aux));
+	if (aux[0] != '1' || aux[1] != '\0') {
+		fprintf(stderr, "Pipe connectivity lost\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+int main(int argc, char **argv)
+{
+	int p_in[2], p_out[2], p_err[2], pid, pass = 1, stolen_fd = -1;
+
+	/*
+	 * Prepare IO-s and fork the victim binary
+	 */
+	if (pipe(p_in) || pipe(p_out) || pipe(p_err)) {
+		perror("Can't make pipe");
+		return -1;
+	}
+
+	printf("Run the victim\n");
+	pid = vfork();
+	if (pid == 0) {
+		close(p_in[1]);  dup2(p_in[0], 0);  close(p_in[0]);
+		close(p_out[0]); dup2(p_out[1], 1); close(p_out[1]);
+		close(p_err[0]); dup2(p_err[1], 2); close(p_err[1]);
+		execl("./victim", "victim", NULL);
+		exit(1);
+	}
+
+	close(p_in[0]); close(p_out[1]); close(p_err[1]);
+
+	/*
+	 * Now do the infection with parasite.c
+	 */
+
+	printf("Infecting the victim\n");
+	if (do_infection(pid, &stolen_fd))
+		return 1;
+
+	/*
+	 * Stop the victim and check the infection went well
+	 */
+	printf("Closing victim stdin\n");
+	close(p_in[1]);
+	printf("Waiting for victim to die\n");
+	wait(NULL);
+
+	printf("Checking the result\n");
+	/*
+	 * Stolen fd is the stderr of the task
+	 * Check these are the ends of the same pipe
+	 * and message passing works OK
+	 */
+
+	pass = check_pipe_ends(stolen_fd, p_err[0]);
+
+	if (pass)
+		printf("All OK\n");
+	else
+		printf("Something went WRONG\n");
+
+	return 0;
+}
diff --git a/compel/test/fdspy/victim.c b/compel/test/fdspy/victim.c
new file mode 100644
index 0000000..3dbd274
--- /dev/null
+++ b/compel/test/fdspy/victim.c
@@ -0,0 +1,12 @@ 
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+	int i, aux;
+
+	do {
+		i = read(0, &aux, 1);
+	} while (i > 0);
+
+	return 0;
+}