mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-01-23 02:14:37 +00:00
compel: Test for FDs stealing
An example, that steals stderr descriptor from victim task. Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
a5752133c7
commit
36ebce8d9c
5 changed files with 233 additions and 0 deletions
4
compel/test/fdspy/.gitignore
vendored
Normal file
4
compel/test/fdspy/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
parasite.h
|
||||
parasite.po
|
||||
spy
|
||||
victim
|
||||
28
compel/test/fdspy/Makefile
Normal file
28
compel/test/fdspy/Makefile
Normal file
|
|
@ -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 $@ $^
|
||||
20
compel/test/fdspy/parasite.c
Normal file
20
compel/test/fdspy/parasite.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
169
compel/test/fdspy/spy.c
Normal file
169
compel/test/fdspy/spy.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
12
compel/test/fdspy/victim.c
Normal file
12
compel/test/fdspy/victim.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue