[7/5] compel: Test for remote syscall execution

Submitted by Pavel Emelianov on Nov. 25, 2016, 1:45 p.m.

Details

Message ID 5838408B.5020906@virtuozzo.com
State Accepted
Headers show

Commit Message

Pavel Emelianov Nov. 25, 2016, 1:45 p.m.
The library can be used not only to run infection blobs,
but also just to execute syscalls remotely and here's
an example of how to do this.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
---
 compel/test/rsys/.gitignore |   2 +
 compel/test/rsys/Makefile   |  18 ++++++
 compel/test/rsys/spy.c      | 136 ++++++++++++++++++++++++++++++++++++++++++++
 compel/test/rsys/victim.c   |  16 ++++++
 4 files changed, 172 insertions(+)
 create mode 100644 compel/test/rsys/.gitignore
 create mode 100644 compel/test/rsys/Makefile
 create mode 100644 compel/test/rsys/spy.c
 create mode 100644 compel/test/rsys/victim.c

Patch hide | download patch | download mbox

diff --git a/compel/test/rsys/.gitignore b/compel/test/rsys/.gitignore
new file mode 100644
index 0000000..e3e9602
--- /dev/null
+++ b/compel/test/rsys/.gitignore
@@ -0,0 +1,2 @@ 
+spy
+victim
diff --git a/compel/test/rsys/Makefile b/compel/test/rsys/Makefile
new file mode 100644
index 0000000..e8e395f
--- /dev/null
+++ b/compel/test/rsys/Makefile
@@ -0,0 +1,18 @@ 
+ifeq ($(ARCH),)
+        ARCH := x86
+endif
+
+# FIXME -- generate common symlink in compel/uapi
+COMMON_IDIR	:= ../../../include
+COMPEL_IDIR	:= ../../../compel/include/uapi
+COMPEL_LIBRARY	:= ../../../compel/libcompel.a
+
+clean:
+	rm -f victim
+	rm -f spy
+
+victim: victim.c
+	gcc -o $@ $^
+
+spy: spy.c $(COMPEL_LIBRARY)
+	gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^
diff --git a/compel/test/rsys/spy.c b/compel/test/rsys/spy.c
new file mode 100644
index 0000000..482a44e
--- /dev/null
+++ b/compel/test/rsys/spy.c
@@ -0,0 +1,136 @@ 
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+
+#include <compel/compel.h>
+
+static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms)
+{
+	printf("\tLC%u: ", lvl);
+	vprintf(fmt, parms);
+}
+
+static int do_rsetsid(int pid)
+{
+#define err_and_ret(msg) do { fprintf(stderr, msg); return -1; } while (0)
+
+	int state;
+	long ret;
+	struct parasite_ctl *ctl;
+
+	compel_log_init(print_vmsg, 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");
+
+	ret = -1000;
+	if (compel_syscall(ctl, __NR_getpid, &ret, 0, 0, 0, 0, 0, 0) < 0)
+		err_and_ret("Can't run rgetpid");
+
+	printf("Remote getpid returned %ld\n", ret);
+	if (ret != pid)
+		err_and_ret("Pid mismatch!");
+
+	ret = -1000;
+	if (compel_syscall(ctl, __NR_setsid, &ret, 0, 0, 0, 0, 0, 0) < 0)
+		err_and_ret("Can't run rsetsid");
+	printf("Remote setsid returned %ld\n", ret);
+
+	/*
+	 * 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 inline int chk(int fd, int val)
+{
+	int v = 0;
+
+	read(fd, &v, sizeof(v));
+	printf("%d, want %d\n", v, val);
+	return v == val;
+}
+
+int main(int argc, char **argv)
+{
+	int p_in[2], p_out[2], p_err[2], pid, i, pass = 1, sid;
+
+	/*
+	 * 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;
+	}
+
+	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]);
+	sid = getsid(0);
+
+	/*
+	 * Kick the victim once
+	 */
+	i = 0;
+	write(p_in[1], &i, sizeof(i));
+
+	printf("Checking the victim session to be %d\n", sid);
+	pass = chk(p_out[0], sid);
+	if (!pass)
+		return 1;
+
+	/*
+	 * Now do the infection with parasite.c
+	 */
+
+	printf("Setsid() the victim\n");
+	if (do_rsetsid(pid))
+		return 1;
+
+	/*
+	 * Kick the victim again so it tells new session
+	 */
+	write(p_in[1], &i, sizeof(i));
+
+	/*
+	 * Stop the victim and check the intrusion went well
+	 */
+	printf("Closing victim stdin\n");
+	close(p_in[1]);
+	printf("Waiting for victim to die\n");
+	wait(NULL);
+
+	printf("Checking the new session to be %d\n", pid);
+	pass = chk(p_out[0], pid);
+
+	if (pass)
+		printf("All OK\n");
+	else
+		printf("Something went WRONG\n");
+
+	return 0;
+}
diff --git a/compel/test/rsys/victim.c b/compel/test/rsys/victim.c
new file mode 100644
index 0000000..2f1943d
--- /dev/null
+++ b/compel/test/rsys/victim.c
@@ -0,0 +1,16 @@ 
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	while (1) {
+		if (read(0, &i, sizeof(i)) != sizeof(i))
+			break;
+
+		i = getsid(0);
+		write(1, &i, sizeof(i));
+	}
+
+	return 0;
+}