[CRIU] [PATCH 3/3] compel: Test for FDs stealing
Pavel Emelyanov
xemul at virtuozzo.com
Mon Mar 6 10:38:45 PST 2017
An example, that steals stderr descriptor from victim task.
Signed-off-by: Pavel Emelyanov <xemul at 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
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;
+}
--
2.1.4
More information about the CRIU
mailing list