Skip to content

Commit

Permalink
compel: Big rework of compel and tests
Browse files Browse the repository at this point in the history
This patch includes a lot of stuff and is effectively 'initial
commit #2'. So, we have here

1. licensing
2. readme
3. tests
4. rework of args passing
5. fds and shmem plugins
6. cleanups and dead code removals
7. CLI tuning
8. docs fixup according to the above

Signed-off-by: Pavel Emelyanov <[email protected]>
  • Loading branch information
xemul committed Feb 27, 2014
1 parent aff4834 commit 73f158e
Show file tree
Hide file tree
Showing 60 changed files with 1,385 additions and 748 deletions.
15 changes: 15 additions & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
This software is licenced under the GNU GENERAL PUBLIC LICENCE Version 2.
The plugins code located in plugins/ directoly is licensed under the GNU
LESSER GENERAL PUBLIC LICENCE Version 2.1.

In other words -- programs linked with libcompel.so should be under some
GPL-compatible license, but the code that is about to be linked with the
plugins and then injected into victim may be under any license.

Contributing Authors agree that their code is submitted under the licence
appropriate for its location within the source tree (GPL except for LGPL
in plugins/) and agree that any future patches, provided they are accepted
into the project, may change the licence of their code from GPL to LGPL by
moving pieces of it into plugins/ or LGPL to GPL by moving pieces of it
out of plugins/

Note that the only valid version of the GPL is THIS particular version
of the license (ie v2, not v2.2 or v3.x or whatever), unless explicitly
otherwise stated.
Expand Down
39 changes: 8 additions & 31 deletions Documentation/compel-plugins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,7 @@ and exports the following routines.
std.h
^^^^^

*int std_get_ctl_socket*(void)::
Returns control socket which might be used to exchange data between plugins
and libcompel itself.

*void *std_get_prologue_init_args_addr*(void)::
Returns address of initial arguments area used by prologue code.
This is cumulative file for all the standard stuff (see below).

string.h
^^^^^^^^
Expand Down Expand Up @@ -60,8 +55,8 @@ string.h
syscall.h
^^^^^^^^^

There are a number of syscalls the plugin provides. See detailed list in
the header file itself.
This one includes all the system calls, that your blob may call.
Syscalls are names sys_<name> and match Linux kernel prototype.

fds
~~~
Expand All @@ -71,29 +66,11 @@ This plugin stands for file descriptor exchange over unix socket.
fds.h
^^^^^

*int send_fds*(*int* 'sock', *struct sockaddr_un* \*'saddr', *int* 'len', *int* \*'fds', *int* 'nr_fds', *bool* 'with_flags')::
Send 'nr_fds' amount of file descriptors pointed by 'fds' via socked 'sock'
to 'saddr' destination (the length of address is specified by 'len'). The
flag 'with_flags' tells the routine to fetch file flags for every descriptor
before sending them out.

*int recv_fds*(*int* 'sock', *int* \*'fds', *int* 'nr_fds', *struct fd_opts* *'opts')::
Receive file descriptors from socket 'sock' sent by *send_fds*. The structure 'fd_opts'
is filled by *send_fds* routine if 'with_flags' option was specifed. Internally *send_fds*
uses *fcntl*() syscall with *F_GETFD*, *F_GETOWN_EX*, *F_GETOWNER_UIDS* flags to fetch them.

---------------------------------------------------------------------
struct fd_opts {
char flags;
struct {
u32 uid;
u32 euid;
u32 signum;
u32 pid_type;
u32 pid;
} fown;
};
---------------------------------------------------------------------
*int fds_send_one*(*int* \*'fd')::
Sends 'fd' file descriptor to master process.

*int fds_recv_one*()::
Receive file descriptor from master process.

AUTHOR
------
Expand Down
19 changes: 10 additions & 9 deletions Documentation/compel.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SYNOPSIS
--------
*compel* 'command' ['options']

*compel* run <file> -t <pid>
*compel* run -f <compel-file> -p <pid> [-- <options-for-parasite>]

*compel* pack <file1> [<file2>] [-L<dir>] [-llib1] [-o out]

Expand All @@ -29,10 +29,10 @@ Commands
~~~~~~~~

*run*::
Initiate execution procedure.
Run compiled and packed file in remote process context.

*pack*::
Pack object file into a form suitable for execution.
Pack object file into a compel-file -- the form suitable for remote execution.

*cflags*::
Print the compiler flags needed to compile plugin object files.
Expand All @@ -46,14 +46,15 @@ OPTIONS
Action 'run'
~~~~~~~~~~~~

<file>::
The name of binary blob object to be executed.
*-f*, *--cfile* 'file'::
The name of packed file to be executed.

*-t*, *--tree* 'pid'::
*-p*, *--pid* 'pid'::
Destination task identified by 'pid'.

*-a*, *--plugin-args* 'string'::
A 'string' used to for command line arguments passed to plugins entry point.
<options-for-parasite>::
Options to be passed to parasite code. See compel-plugins document for
details about how to access those from parasite.

Action 'pack'
~~~~~~~~~~~~~
Expand All @@ -62,7 +63,7 @@ Action 'pack'
Add directory 'path' to the list of directories to be searched for
resources (*-l* option and linker scripts).

*l*, *--library* 'name'::
*-l*, *--library* 'name'::
Search the library named 'name' when linking. The following libraries
are always linked in even if not specified in command line: *std*.

Expand Down
57 changes: 13 additions & 44 deletions Documentation/libcompel.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,56 +18,25 @@ INTERFACE
*void libcompel_version*(*unsigned int* \*'major', *unsigned int* \*'minor', *unsigned int* *'sublevel')::
This function returns 'major', 'minor' and 'sublevel' version of the library.

*void *libcompel_exec_start*(*pid_t* 'pid', *argv_desc_t* \*'argv_desc', *int* *'err')::
This function injects an object file described in 'argv_desc' in the process address
space identified by 'pid' and initiate its execution. The file must be previously packed
with help of *compel* tool. Returns pointer to execution context. On error
returns NULL and sets error code to 'err' (if 'err' is not NULL).

'argv_desc' is object file descriptor as
*int libcompel_exec*(*pid_t* 'pid', *char* \*'path', *void* \*'arg_p', *unsigned int* 'arg_s')::
This function runs the compel file 'path' (packed with compel tool) in the
address space of a process 'pid'. The 'arg_p' and 'arg_s' are pointer to
binary data and their size, that will be available in the parasitic code's
main function. The execution of the parasite code starts with the function

-----------------------------------------------------------------
typedef struct argv_desc_s {
char *blob_path; /* path to object file */
char *blob_args; /* arguments string */
} argv_desc_t;
int main(void *arg_p, unsigned int arg_s);
-----------------------------------------------------------------

*int libcompel_exec_end*(*void* *'ptr')::
Waits to finish execution of context pointed by 'ptr'.

*void *libcompel_exec_elf*(*pid_t* 'pid', *argv_desc_t* *'argv_desc')::
This function executes an object file described in 'argv_desc' in the process address
space identified by 'pid'. The file must be previously packed with help of *compel* tool.

*void libcompel_log_set_fd*(*int* 'fd')::
Make library to use 'fd' file descriptor to write debug/error messages to.
By default 'fd' is set to -1 thus all messages are suppressed.

*void libcompel_loglevel_set*(*unsigned int* 'loglevel')::
Set library logging level to 'loglevel'. The value may be one of:
1 - error, 2 - warnings, 3 - informative, 4 - debug.
By default the logging level is set to 2.

*int libcompel_get_ctl_socket*(*void* *'ptr')::
Returns a control socket created in execution context pointed by 'ptr' which
can be used to talk to plugins (plugins have own api to fetch this socket).
The function returns after the parasite code's main finishes.

*int libcompel_get_rt_blob_desc*(*void* \*'ptr', *blob_rt_desc_t* *'d')::
Fills run time descriptor of executing binary blob 'd' created in context
pointed by 'ptr'.
*parasite_exec_handle_t libcompel_exec_start*(*pid_t* 'pid', *char* \*'path', *void* \*'arg_p', *unsigned int* 'arg_s')::
This function starts the compel file, but returns immediatelly after parasite
starts executing. To wait for it to finish and unload use the next function.

-----------------------------------------------------------------
typedef struct blob_rt_desc_s {
pid_t pid; /* pid of victim process */

unsigned long init_args_at; /* parasite init arguments */
size_t init_args_size; /* their size */

void *remote_map; /* remote address of a parasite */
void *local_map; /* local address of a parasite */
} blob_rt_desc_t;
-----------------------------------------------------------------
*int libcompel_exec_end*(parasite_exec_handle_t h)::
This one waits for parasite termination and unloads it. Return value of the
parasite is reported back.

AUTHOR
------
Expand Down
1 change: 1 addition & 0 deletions Makefile.plugins
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins += shmem
plugins += fds

dep-fds := std
dep-shmem := std

define gen-plugin-rule
ifneq ($(2),)
Expand Down
127 changes: 126 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,132 @@
Compel
======

An utility to execute binary blob in foreign process space.
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.


Get compel ready
=======

Get the sources and run

$ make
$ make install-devel

This will prepare the following

1. compel comman line tool,
2. libcompel.so library (put path to it into LD_LIBRARY_PATH variable,
the compel tool is dynamically linked with it),
3. devel/ directory with headers and libs needed for further work.


Write parasite code
=======

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).

1. std

This plugins gets packed with your binary by default and provides standard
Linux system calls, strings functions and printf-like priting helper.

The std plugin API is in include/compel/plugin-std.h header.

2. fds

This one allows you to send and receive fds in parasite to/from the master
process.

The fds plugin API is in include/compel/plugin-fds.h header.

3. shmem

This one sets up shared memory between parasite and master.

The shmem plugin API is in include/compel/plugin-shmem.h header.

Execution of the parasite code starts with the function

int main(void *arg_p, unsigned int arg_s);

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.


Compile the sources and pack the binary
=======

1. Take a program on C and compile it with compel flags

$ gcc -c foo.c -o foo.o $(compel cflags) -I<compel-headers>

To combine the foo.o out of many sources, they should all be
linked with compel flags as well

$ ld foo_1.o foo_2.o -o foo.o $(compel ldflags)

The compel-headers is devel/include/ after make install-devel.

2. Pack the binary. Packing would link the object file with
compel plugins (see below)

$ compel pack foo.o -o foo.compel.o -L<compel-libs> [-l<lib>]

The compel-libs is devel/lib/compel/ after make install-devel.


The foo.compel.o is ready for remote execution (foo.o was not).


Execute the code remotely
=======

Using CLI like this

$ compel run -f foo.compel.o -p $pid

Or, you can link with libcompel.so and use

libcompel_exec()
libcompel_exec_start()/libcompel_exec_end()

calls described in include/compel/compel.h header. The test/
directory contains several examples of how to launch parasites.

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.


How to communicate to parasite code
=======
There are several ways for doing this.

1. If you run the parasite binary from CLI, the tail command line
arguments are passed into the parasite main() function.

$ compel run -f foo.compel.o -p 123 -- arg1 arg2 arg3

In the main() common argc and argv are accessed using the

argc = std_argc(arg_p);
argv = std_argv(arg_p, argc);

calls. Then use argc and argv as you would use them in normal C
program run from shell.

2. 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.

Warning
=======
Expand Down
3 changes: 0 additions & 3 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
- file descriptors plugin
+ logging plugin
- arguments pointers (need to invent)
- shmem plugin
- plugins list (optional)
Loading

0 comments on commit 73f158e

Please sign in to comment.