Changes

Jump to navigation Jump to search
2,206 bytes added ,  14:43, 29 August 2018
m
Line 1: Line 1: −
Compel temporary GIT repo is at http://github.com/xemul/compel.
+
'''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 [https://github.com/checkpoint-restore/criu/tree/criu-dev/compel the criu-dev branch of CRIU repo, subdirectory compel].
Now compel sits in the main criu repo at https://github.com/xemul/criu/tree/criu-dev/compel.
     −
== 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.
   −
An utility to execute code in foreign process address space. The code should be compiled with compel flags and packed, then it can be executed in other task's context. The parasite code executes in an environment w/o glibc, thus you cannot call the usual stdio/stdlib/etc. functions. Compel provides a set of plugins for your convenience. Plugins get linked to parasite binary on the pack stage (see below).
+
A set of [[compel plugins]] are provided for your convenience. Plugins get linked to the parasite binary during the pack stage.
   −
== How we want it to look like ==
+
== Writing parasite code ==
   −
Execution of the parasite code starts with the function
+
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
   −
int main(void *arg_p, unsigned int arg_s);
+
; <code>parasite_trap_cmd(int cmd, void *arg);</code>
 +
: This routine gets called by <code>compel_run_in_thread()</code>
   −
that should be present in your code. The arg_p and arg_s is the binary argument that will get delivered to parasite code by complel _start() call (see below). Sometimes this binary argument can be treated as CLI arguments argc/argv.
+
; <code>parasite_daemon_cmd(int cmd, void *arg);</code>
 +
: This routine gets called by <code>compel_rpc_call()</code> and <code>compel_rpc_call_sync()</code>. The <code>arg</code> points to the memory with arguments, see the [[#Arguments passing]] section below.
   −
=== Compile the sources and pack the binary ===
+
; <code>parasite_cleanup(void);</code>
 +
: This gets called on parasite unload by <code>compel_cure()</code>
   −
Take a program on C and compile it with compel flags
+
== Compiling and packing ==
   −
$ gcc -c foo.c -o foo.o $(compel cflags) -I
+
Compile the source of your parasite code with compel flags:
   −
To combine the foo.o out of many sources, they should all be linked with compel flags as well
+
<pre>
 +
$ gcc -c foo1.c -o foo1.o $(compel cflags)
 +
</pre>
   −
$ ld foo_1.o foo_2.o -o foo.o $(compel ldflags)
+
Then link the parasite binary. Include all the .o files needed.  
   −
The compel-headers is devel/include/ after make install-devel.
+
<pre>
 +
$ ld $(compel ldflags) foo1.o foo2.o $(compel plugins) -o parasite.po
 +
</pre>
   −
Pack the binary. Packing would link the object file with compel plugins (see below)
+
The .po blob can now be loaded as parasite.
   −
$ compel pack foo.o -o foo.compel.o -L [-l]
+
== Loading blob ==
   −
The compel-libs is devel/lib/compel/ after make install-devel.
+
=== Using CLI ===
   −
The foo.compel.o is ready for remote execution (foo.o was not).
+
This functionality is in plans and not implemented yet.
   −
=== Execute the code remotely ===
+
=== Using libcompel.a library ===
   −
Using CLI like this
+
Currently there is only one way to load the blob into victim task using libcompel.a, called ''c-header'' <ref>This is done for historical reasons. It was the most handy way to load [[parasite code]] by CRIU. In plans we have loading the .po ELF file itself</ref>. First you should make a header out of your .po file with the <code>hgen</code> action of compel tool:
   −
$ compel run -f foo.compel.o -p $pid
+
compel hgen -f parasite.po -o parasite.h
   −
Or, you can link with libcompel.so and use
+
Options meaning is the following:
 +
* <code>-f</code> tells which binary to turn into header
 +
* <code>-o</code> tells where to write the resulting header
   −
libcompel_exec() libcompel_exec_start()/libcompel_exec_end()
+
Once <code>parasite.h</code> file is ready, it should be included into the infecting program source code to be compiled with it.
   −
calls described in include/compel/compel.h header. The test/ directory contains several examples of how to launch parasites.
+
== Running parasite code ==
   −
The library calls require binary argument that will get copied into parasite context and passed to it via arg_p/arg_s pair. When run from CLI the arguments are packed in argc/argv manner.
+
So, in order to infect a task with parasite one must do the following.
   −
=== How to communicate to parasite code ===
+
* Stop the task. This is done by calling <code>compel_stop_task(int pid)</code>. Its return value should be saved in case it's positive (it contains the task state).
 +
* Prepare the infection handler. This is done by calling <code>compel_prepare(int pid)</code>. The return value is an opaque pointer to <code>struct parasite_ctl</code>.
 +
* Run the remote code:
 +
** Execute a system call with <code>compel_syscall(ctl, int syscall_nr, long *ret, int arg ...)</code> (all 6 parameters)
 +
** Infect the victim with the parasite blob by calling <code>compel_infect(ctl, nr_thread, size_of_args_area)</code>
 +
* Cure the victim by calling <code>compel_cure(ctl)</code>. Note that <code>ctl</code> pointer is freed by the call so it should not be used thereafter.
 +
* Resume the task by calling <code>compel_resume_task(pid, orig_state, state)</code> with the saved state value from the first step.
   −
There are several ways for doing this.
+
=== Infecting ===
   −
If you run the parasite binary from CLI, the tail command line arguments are passed into the parasite main() function.
+
Infecting the victim with a parasite blob needs some special treatment.
   −
$ compel run -f foo.compel.o -p 123 -- arg1 arg2 arg3
+
First, the <code>ctl</code> should be configured with the blob information. For that,
 +
you should call <code>''PREFIX''_setup_c_header()</code> function
 +
with <code>ctl</code> as an argument. Here <code>''PREFIX''</code>
 +
is the same as the argument given to <code>-p</code> option
 +
to <code>compel hgen</code>, and if not given, it is derived
 +
from the input file name, dropping the path and the suffix
 +
(in the above example it's <code>parasite</code>).
   −
In the main() common argc and argv are accessed using the
+
Second, when infecting a parasite one should specify the amount of threads it will mess with (1, if only the thread leader will be accessed) and the maximum size of the memory area shared between infecting task and parasite used for arguments/result passing.
   −
argc = std_argc(arg_p); argv = std_argv(arg_p, argc);
+
=== Arguments passing ===
   −
calls. Then use argc and argv as you would use them in normal C program run from shell.
+
To pass arguments between the infecting code and parasite, one may call <code>compel_parasite_args(ctl, type)</code> and get the pointer where it can put data. Subsequent calls to <code>compel_rpc_call[_sync]()</code> will result in this data visible in <code>void *arg</code> address of the <code>parasite_daemon_cmd()</code>.
 
  −
If you run the parasite using library _start/_end calls, you can pass file descriptors to parasite using fds plugin or setup shmem between these two using shmem plugin.
  −
See test/async_fds/ and test/async_shmem/ for code examples.
  −
 
  −
=== Plugins ===
  −
 
  −
; std
  −
: This plugins gets packed with your binary by default and provides standard Linux system calls, strings functions and printf-like priting helper.
  −
 
  −
; fds
  −
: This one allows you to send and receive fds in parasite to/from the master process.
  −
 
  −
; shmem
  −
: This one sets up shared memory between parasite and master.
      +
== See also ==
 +
* [[Compel/Usage_scenarios]]
 +
* [[Compel plugins]]
 +
* Examples of working code available [https://github.com/checkpoint-restore/criu/tree/criu-dev/compel/test on github] <ref>Clone the repo, build the project by running <code>make</code>, then go to <code>compel/test/$test_name</code> directory and run <code>make</code> there. Running <code>spy</code> bynary runs the example. Then -- RTFS or talk to us on [https://lists.openvz.org/mailman/listinfo/criu criu@openvz.org] :)</ref>
 +
* Info about CRIU [[code blobs]] in which the same technology is used
       +
-----
 +
<references/>
 
[[Category:Compel]]
 
[[Category:Compel]]
 +
[[Category:Editor help needed]]
277

edits

Navigation menu