-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvoyeur.h
205 lines (180 loc) · 7.84 KB
/
voyeur.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef LIBVOYEUR_VOYEUR_H
#define LIBVOYEUR_VOYEUR_H
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
//////////////////////////////////////////////////
// Overview of libvoyeur.
//////////////////////////////////////////////////
// Libvoyeur is a library for observing the private activity of a
// child process. It does this by using the dynamic linker to override
// the implementations of standard library functions. When those
// functions are called, libvoyeur generates events, and by
// registering callbacks you can observe those events and take
// whatever action you want.
// The flow of using libvoyeur is simple. Start by creating a context:
//
// > voyeur_context_t ctx = voyeur_context_create();
//
// Then register to observe some events:
//
// > voyeur_observe_exec(ctx,
// > OBSERVE_EXEC_CMD | OBSERVE_EXEC_ENV,
// > my_exec_callback,
// > NULL);
//
// Use voyeur_exec() to start and observe the child process:
//
// > voyeur_exec(ctx, "/usr/bin/program", argv, envp);
//
// Finally, destroy the context:
//
// > voyeur_context_destroy(ctx);
// Users with more complex needs or who intend to provide bindings to
// languages other than C will probably want to use voyeur_prepare()
// and voyeur_start() rather than voyeur_exec(). Their documentation
// is below.
//////////////////////////////////////////////////
// Creating and destroying libvoyeur contexts.
//////////////////////////////////////////////////
typedef void* voyeur_context_t;
// Creates a context used to specify which events you want to observe
// and as an owner for resources allocated by voyeur_prepare().
voyeur_context_t voyeur_context_create();
// Destroys a context. This must always be called after voyeur_start()
// or voyeur_exec() is finished to release the resources libvoyeur has allocated.
// After destroying a context, it is invalid and should not be used again.
void voyeur_context_destroy(voyeur_context_t ctx);
//////////////////////////////////////////////////
// Registering callbacks for particular events.
//////////////////////////////////////////////////
// Observing exec*() calls.
typedef void (*voyeur_exec_callback)(const char* file,
char* const argv[],
char* const envp[],
const char* path,
const char* cwd,
pid_t pid,
pid_t ppid,
void* userdata);
typedef enum {
OBSERVE_EXEC_DEFAULT = 0,
OBSERVE_EXEC_CWD = 1 << 0, // Include 'cwd' (working directory).
OBSERVE_EXEC_ENV = 1 << 1, // Include 'envp' (environment).
OBSERVE_EXEC_PATH = 1 << 2, // Include the value of 'PATH'.
OBSERVE_EXEC_NOACCESS = 1 << 3, // Include exec calls for paths
// that don't exist or aren't executable.
} voyeur_exec_options;
void voyeur_observe_exec(voyeur_context_t ctx,
uint8_t opts,
voyeur_exec_callback callback,
void* userdata);
// Observing when processes exit.
typedef void (*voyeur_exit_callback)(int status,
pid_t pid,
pid_t ppid,
void* userdata);
typedef enum {
OBSERVE_EXIT_DEFAULT = 0,
} voyeur_exit_options;
void voyeur_observe_exit(voyeur_context_t ctx,
uint8_t opts,
voyeur_exit_callback callback,
void* userdata);
// Observing open() calls.
typedef void (*voyeur_open_callback)(const char* path,
int oflag,
mode_t mode,
const char* cwd,
int retval,
pid_t pid,
void* userdata);
typedef enum {
OBSERVE_OPEN_DEFAULT = 0,
OBSERVE_OPEN_CWD = 1 << 0, // Include 'cwd' (working directory).
} voyeur_open_options;
void voyeur_observe_open(voyeur_context_t ctx,
uint8_t opts,
voyeur_open_callback callback,
void* userdata);
// Observing close() calls.
typedef void (*voyeur_close_callback)(int fd,
int retval,
pid_t pid,
void* userdata);
typedef enum {
OBSERVE_CLOSE_DEFAULT = 0,
} voyeur_close_options;
void voyeur_observe_close(voyeur_context_t ctx,
uint8_t opts,
voyeur_close_callback callback,
void* userdata);
//////////////////////////////////////////////////
// Other context configuration options.
//////////////////////////////////////////////////
// Set the path where libvoyeur should look for its resources.
//
// To inject code into child processes, libvoyeur uses a set
// of helper dynamic libraries. By default, libvoyeur assumes
// that those libraries are located in the same directory as
// libvoyeur itself, which is to say in the same directory as
// libvoyeur.so/.dylib if using dynamic linking, or in the same
// directory as the main program if using static linking. If
// this assumption doesn't hold, this function can be used to
// provide the path where libvoyeur should look for these files.
//
// The provided path must have a trailing path separator -
// in other words, it must end with a '/'.
void voyeur_set_resource_path(voyeur_context_t ctx,
const char* path);
//////////////////////////////////////////////////
// Observing processes.
//////////////////////////////////////////////////
// Prepare to observe a child process.
//
// This will acquire resources that libvoyeur needs to do its work and
// create a modified environment, based upon the provided template,
// that should be passed to the child process when it gets exec'd.
// It's the caller's responsibility to free this environment. (Note
// that unlike other resources acquired by libvoyeur, the environment
// is not freed when voyeur_context_destroy() is called.)
//
// This function should be called before forking. After calling
// voyeur_prepare(), it isn't safe to call voyeur_observe_* functions
// on the same context anymore.
//
// Returns NULL on failure.
char** voyeur_prepare(voyeur_context_t ctx, char* const envp[]);
// Start observing a child process.
//
// This will block until the child process completes, at which time
// it will return its exit status. While the child process is running,
// the callbacks you've registered with the voyeur_observe_* functions
// will be called.
//
// Call this after forking, in the parent process. After
// voyeur_start() returns, you should use voyeur_context_destroy()
// to release the resources libvoyeur has acquired.
int voyeur_start(voyeur_context_t ctx, pid_t child_pid);
// Create and observe a new child process.
//
// voyeur_exec() is a convenience function that behaves just as if
// you had made this sequence of calls:
//
// > voyeur_envp = voyeur_prepare(ctx, envp);
// > posix_spawn(&pid, path, NULL, NULL, argv, voyeur_envp);
// > voyeur_start(ctx, pid);
// > free(voyeur_envp);
//
// Like voyeur_start(), it returns the exit status of the child. After
// voyeur_exec() returns, you should use voyeur_context_destroy() to
// release the resources libvoyeur has acquired.
//
// voyeur_exec() may fail, in which case it will return -1. If you need
// to distinguish between a child process exit status of -1 and a failure
// inside libvoyeur, use voyeur_prepare() and voyeur_start().
int voyeur_exec(voyeur_context_t ctx,
const char* path,
char* const argv[],
char* const envp[]);
#endif