Difference between revisions of "Compel"

From CRIU
Jump to navigation Jump to search
Line 52: Line 52:
 
After this the <code>parasite.h</code> file should be included into the infecting program and compiled with it.
 
After this the <code>parasite.h</code> file should be included into the infecting program and compiled with it.
  
== Communicating ==
+
== Running parasite code ==
  
There are several ways to pass parameters to the parasite code.
+
So, in order to infect a task with parasite one must.
  
If you run the parasite binary from CLI, the command line arguments after <code>--</code> are passed into the parasite's <code>main()</code> function.
+
* Stop the task with <code>compel_stop_task(int pid)</code> call and keep the return value if it's positive (it contains the task state)
 
+
* Prepare the infection handler with <code>compel_prepare(int pid)</code> call. The return value is an opaque pointer to <code>struct parasite_ctl()</code>
<pre>
+
* Run the remote code
$ compel run -f foo.compel.o -p 123 -- arg1 arg2 arg3
+
** Just execute a system call with <code>compel_syscall(ctl, int syscall_nr, long *ret, int arg ... (6 of them))</code>
</pre>
+
** Infect victim with parasite blob with <code>compel_infect(ctl, nr_thread, size_of_args_area)</code>
 
+
* Cure the victim with <code>compel_cure(ctl)</code> and stop using the ctl pointer as it's freed by the call
In <code>main()</code>, the standard <code>argc</code> and <code>argv</code> can be obtained using the following code:
+
* Resume the task with <code>compel_resume_task(pid)</code>
 
 
<source lang="C">
 
argc = std_argc(arg_p);
 
argv = std_argv(arg_p, argc);
 
</source>
 
 
 
These calls are available in <code>argv</code> [[compel plugins|plugin]]. Now, argc and argv can be handled as usual.
 
  
 
== See also ==
 
== See also ==

Revision as of 14:00, 25 November 2016

Compel is a utility to execute arbitrary code in a context of a foreign process. Compel is part of CRIU, and its sources are available from the criu-dev branch of CRIU repo, subdirectory compel.

The code to be executed is called parasite code. Once compiled with compel flags and packed, it can be executed in other task's context. Note the code is run in environment without glibc, thus it can not call the usual stdio/stdlib/etc. functions.

A set of compel plugins are provided for your convenience. Plugins get linked to the parasite binary during the pack stage.

Writing parasite code

Execution of parasite code always starts with a function in compel std plugin that should be linked with parasite binary (see below). From the parasite code these symbols should be available for libcompel to work

parasite_trap_cmd(int cmd, void *arg);
This routine gets called by compel_run_in_thread()
parasite_daemon_cmd(int cmd, void *arg);
This routine gets called by compel_rpc_call() and compel_rpc_call_sync()
parasite_cleanup(void);
This gets called on parasite unload by compel_cure()

Compiling and packing

Compile the source of your parasite code with compel flags:

$ gcc -c foo1.c -o foo1.o $(compel cflags)

Don't forget to put compel/include/uapi/ directory into include paths.

Then link the parasite binary. Include all the .o files needed and compel plugins std and fds by using compel linker script.

$ ld foo1.o foo2.o compel/plugins/std.built-in.o compel/plugins/fds.built-ind.o -T compel/arch/$ARCH/scripts/compel-pack.lds.S -o parasite.po 

The .po blob can now be loaded as parasite.

Loading blob

Using CLI

This functionality is in plans and not implemented yet.

Using libcompel.a library

In libcompel.a there's currently only one way to load the blob into victim task, it's called 'c-header'. So first you should make a header out of you .po file

compel hgen -f parasite.po -v parasite_relocs -p parasite_sym -s parasite_blob -r parasite_nr_gotpcrel -u compel/include/uapi/ -o parasite.h

After this the parasite.h file should be included into the infecting program and compiled with it.

Running parasite code

So, in order to infect a task with parasite one must.

  • Stop the task with compel_stop_task(int pid) call and keep the return value if it's positive (it contains the task state)
  • Prepare the infection handler with compel_prepare(int pid) call. The return value is an opaque pointer to struct parasite_ctl()
  • Run the remote code
    • Just execute a system call with compel_syscall(ctl, int syscall_nr, long *ret, int arg ... (6 of them))
    • Infect victim with parasite blob with compel_infect(ctl, nr_thread, size_of_args_area)
  • Cure the victim with compel_cure(ctl) and stop using the ctl pointer as it's freed by the call
  • Resume the task with compel_resume_task(pid)

See also