proj: Combine test_preload.c and test_wrap.c into intercept.c
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn
|
from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn
|
||||||
import os
|
import os
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
class Handler(StreamRequestHandler):
|
class Handler(StreamRequestHandler):
|
||||||
@@ -13,12 +14,19 @@ class Handler(StreamRequestHandler):
|
|||||||
msg = self.rfile.readline()
|
msg = self.rfile.readline()
|
||||||
if not msg:
|
if not msg:
|
||||||
return
|
return
|
||||||
timestamp, data = msg.split(b' ', 1)
|
timestamp, data = msg.rstrip(b'\n').split(b' ', 1)
|
||||||
if not data.startswith(b'return '):
|
if not data.startswith(b'return ') and not data == b'return':
|
||||||
print(data)
|
call = data.decode('utf-8')
|
||||||
#self.wfile.write(b'ok\n')
|
print(f'[{pid}] {call}')
|
||||||
|
if call.startswith('malloc('):
|
||||||
|
command = 'fail ENOMEM'
|
||||||
|
else:
|
||||||
|
command = 'ok'
|
||||||
|
print(f'[{pid}] -> {command}')
|
||||||
|
self.wfile.write(command.encode('utf-8') + b'\n')
|
||||||
else:
|
else:
|
||||||
print(data)
|
ret = data.decode('utf-8')
|
||||||
|
print(f'[{pid}] -> {ret}')
|
||||||
|
|
||||||
|
|
||||||
class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
|
class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
|
||||||
@@ -26,9 +34,22 @@ class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
|
|||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
os.unlink('/tmp/test')
|
parser = argparse.ArgumentParser()
|
||||||
with ThreadedUnixStreamServer('/tmp/test', Handler) as server:
|
parser.add_argument('socket', metavar='FILE')
|
||||||
server.serve_forever()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with ThreadedUnixStreamServer(args.socket, Handler) as server:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print('\nBye')
|
||||||
|
server.shutdown()
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.unlink(args.socket)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
2
proj/test1/.gitignore
vendored
2
proj/test1/.gitignore
vendored
@@ -1,2 +1,2 @@
|
|||||||
/main
|
/main
|
||||||
/main_wrapped
|
/main_*
|
||||||
|
|||||||
@@ -4,24 +4,27 @@ CFLAGS=-std=c99 -pedantic -Wall -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -
|
|||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
all: default
|
all: default
|
||||||
default: bin main test_preload.so main_wrapped #test_kernel.ko
|
default: bin main intercept.so main_intercept #test_kernel.ko
|
||||||
|
|
||||||
bin:
|
bin:
|
||||||
mkdir -p bin/
|
mkdir -p bin/
|
||||||
|
|
||||||
bin/test_preload.o: src/test_preload.c
|
bin/main.o: src/main.c
|
||||||
$(CC) -fPIC -c -o $@ $^ $(CFLAGS)
|
$(CC) -c -o $@ $^ $(CFLAGS)
|
||||||
|
|
||||||
test_preload.so: bin/test_preload.o
|
bin/intercept_preload.o: src/intercept.c
|
||||||
|
$(CC) -fPIC -c -o $@ $^ $(CFLAGS) -DINTERCEPT_PRELOAD
|
||||||
|
|
||||||
|
intercept.so: bin/intercept_preload.o
|
||||||
$(CC) -shared -o $@ $^ $(CFLAGS) -lc -ldl
|
$(CC) -shared -o $@ $^ $(CFLAGS) -lc -ldl
|
||||||
|
|
||||||
test_kernel.ko: src/test_kernel.c
|
test_kernel.ko: src/test_kernel.c
|
||||||
$(CC) -D__KERNEL__ -DMODULE -I/usr/src/linux/include -o $@ $^
|
$(CC) -D__KERNEL__ -DMODULE -I/usr/src/linux/include -o $@ $^
|
||||||
|
|
||||||
main: src/main.c
|
main: bin/main.o
|
||||||
$(CC) -o $@ $^ $(CFLAGS) -lc
|
$(CC) -o $@ $^ $(CFLAGS) -lc
|
||||||
|
|
||||||
main_wrapped: src/main.c src/test_wrap.c
|
main_intercept: bin/main.o src/intercept.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) -lc -Wl,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=getopt
|
$(CC) -o $@ $^ $(CFLAGS) -lc -Wl,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=getopt
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
343
proj/test1/src/intercept.c
Normal file
343
proj/test1/src/intercept.c
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef INTERCEPT_PRELOAD
|
||||||
|
static void *(*__real_malloc)(size_t);
|
||||||
|
static void *(*__real_calloc)(size_t, size_t);
|
||||||
|
static void *(*__real_realloc)(void *, size_t);
|
||||||
|
static void (*__real_free)(void *);
|
||||||
|
static int (*__real_getopt)(int, char *const [], const char *);
|
||||||
|
#define __load(var, name) \
|
||||||
|
if (((var) = dlsym(RTLD_NEXT, name)) == NULL) { \
|
||||||
|
fprintf(stderr, "intercept: unable to load symbol '%s': %s", name, strerror(errno)); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
#define __sym(name) name
|
||||||
|
#else
|
||||||
|
extern void *__real_malloc(size_t);
|
||||||
|
extern void *__real_calloc(size_t, size_t);
|
||||||
|
extern void *__real_realloc(void *, size_t);
|
||||||
|
extern void __real_free(void *);
|
||||||
|
extern int __real_getopt(int, char *const [], const char *);
|
||||||
|
#define __sym(name) __wrap_ ## name
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mode = 0;
|
||||||
|
static int intercept = 0;
|
||||||
|
|
||||||
|
static size_t msg_str(char *buf, size_t maxlen, const char *str) {
|
||||||
|
size_t offset = snprintf(buf, maxlen, "%p:\"", str);
|
||||||
|
for (char ch; (ch = *str) != 0 && offset <= maxlen - 2; str++) {
|
||||||
|
if (ch == '\\' || ch == '"') {
|
||||||
|
buf[offset++] = '\\';
|
||||||
|
buf[offset++] = ch;
|
||||||
|
} else if (ch == '\t') {
|
||||||
|
buf[offset++] = '\\';
|
||||||
|
buf[offset++] = 't';
|
||||||
|
} else if (ch == '\n') {
|
||||||
|
buf[offset++] = '\\';
|
||||||
|
buf[offset++] = 'n';
|
||||||
|
} else if (ch == '\r') {
|
||||||
|
buf[offset++] = '\\';
|
||||||
|
buf[offset++] = 'r';
|
||||||
|
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
|
||||||
|
offset += snprintf(buf + offset, maxlen - offset, "\\x%02x", ch);
|
||||||
|
} else {
|
||||||
|
buf[offset++] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (offset <= maxlen - 2) {
|
||||||
|
buf[offset++] = '"';
|
||||||
|
buf[offset] = 0;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t msg_array_str(char *buf, size_t maxlen, char *const array[], int n) {
|
||||||
|
size_t offset = snprintf(buf, maxlen, "%p:[", (void *)array);
|
||||||
|
for (int i = 0; i < n && offset <= maxlen - 2; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
buf[offset++] = ',';
|
||||||
|
buf[offset++] = ' ';
|
||||||
|
}
|
||||||
|
offset += msg_str(buf + offset, maxlen - offset, array[i]);
|
||||||
|
}
|
||||||
|
if (offset <= maxlen - 2) {
|
||||||
|
buf[offset++] = ']';
|
||||||
|
buf[offset] = 0;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msg(const char *fmt, ...) {
|
||||||
|
if (!intercept) return;
|
||||||
|
char buf[256], sub_fmt[16];
|
||||||
|
int sub_fmt_p = 0;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
struct timespec spec;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &spec);
|
||||||
|
size_t offset = snprintf(buf, sizeof(buf), "%li.%09li ", spec.tv_sec, spec.tv_nsec);
|
||||||
|
for (char ch, state = 0; (ch = *fmt) != 0 && offset < sizeof(buf); fmt++) {
|
||||||
|
if (state == '%') {
|
||||||
|
if (ch == '%') {
|
||||||
|
buf[offset++] = ch;
|
||||||
|
state = 0;
|
||||||
|
continue;
|
||||||
|
} else if (ch == 'e') {
|
||||||
|
state = 'e';
|
||||||
|
continue;
|
||||||
|
} else if (ch == 'a') {
|
||||||
|
state = 'a';
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sub_fmt_p = 0;
|
||||||
|
state = '_';
|
||||||
|
sub_fmt[sub_fmt_p++] = '%';
|
||||||
|
sub_fmt[sub_fmt_p] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state == '_') {
|
||||||
|
sub_fmt[sub_fmt_p++] = ch;
|
||||||
|
sub_fmt[sub_fmt_p] = 0;
|
||||||
|
if (ch == 's' || ch == 'i' || ch == 'd' || ch == 'o' || ch == 'u' || ch == 'x' || ch == 'X' || ch == 'f' || ch == 'p') {
|
||||||
|
state = 0;
|
||||||
|
offset += snprintf(buf + offset, sizeof(buf) - offset, sub_fmt, va_arg(args, long int));
|
||||||
|
}
|
||||||
|
} else if (state == 'e') {
|
||||||
|
if (ch == 's') {
|
||||||
|
// escaped string
|
||||||
|
offset += msg_str(buf + offset, sizeof(buf) - offset, va_arg(args, const char *));
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
} else if (state == 'a') {
|
||||||
|
if (ch == 's') {
|
||||||
|
// string array
|
||||||
|
char *const *array = va_arg(args, char *const *);
|
||||||
|
const int len = va_arg(args, int);
|
||||||
|
offset += msg_array_str(buf + offset, sizeof(buf) - offset, array, len);
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
} else if (ch == '%') {
|
||||||
|
state = '%';
|
||||||
|
} else {
|
||||||
|
buf[offset++] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (offset <= sizeof(buf) - 2) {
|
||||||
|
buf[offset++] = '\n';
|
||||||
|
buf[offset] = 0;
|
||||||
|
}
|
||||||
|
const size_t size = offset >= sizeof(buf) ? sizeof(buf) - 1 : offset;
|
||||||
|
|
||||||
|
ssize_t ret;
|
||||||
|
for (size_t written = 0; written < size; written += ret) {
|
||||||
|
if ((ret = write(intercept, buf, size)) == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
ret = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rcv(char *buf, const int size) {
|
||||||
|
if (!intercept) return;
|
||||||
|
size_t num = 0;
|
||||||
|
for (ssize_t ret; num == 0 || buf[num - 1] != '\n'; num += ret) {
|
||||||
|
if ((ret = read(intercept, buf, size)) == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
ret = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buf[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[num - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fin(void) {
|
||||||
|
if (intercept && mode > 2)
|
||||||
|
close(intercept);
|
||||||
|
if (mode > 0)
|
||||||
|
fprintf(stderr, "intercept: stopped\n");
|
||||||
|
mode = 0, intercept = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(void) {
|
||||||
|
if (mode) return;
|
||||||
|
#ifdef INTERCEPT_PRELOAD
|
||||||
|
__load(__real_malloc, "malloc");
|
||||||
|
__load(__real_calloc, "calloc");
|
||||||
|
__load(__real_realloc, "realloc");
|
||||||
|
__load(__real_free, "free");
|
||||||
|
__load(__real_getopt, "getopt");
|
||||||
|
#endif
|
||||||
|
atexit(fin);
|
||||||
|
const char *val = getenv("INTERCEPT");
|
||||||
|
if (val && strcmp(val, "stdout") == 0) {
|
||||||
|
mode = 1;
|
||||||
|
fprintf(stderr, "intercept: intercepting function/system calls and logging to stdout\n");
|
||||||
|
intercept = STDOUT_FILENO;
|
||||||
|
} else if (val && strcmp(val, "stderr") == 0) {
|
||||||
|
mode = 2;
|
||||||
|
fprintf(stderr, "intercept: intercepting function/system calls and logging to stderr\n");
|
||||||
|
intercept = STDERR_FILENO;
|
||||||
|
} else if (val && strncmp(val, "file:", 5) == 0) {
|
||||||
|
mode = 3;
|
||||||
|
if ((intercept = open(val + 5, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
|
||||||
|
fprintf(stderr, "intercept: unable to open log file '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
||||||
|
errno = 0;
|
||||||
|
mode = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "intercept: intercepting function/system calls and logging to file\n");
|
||||||
|
} else if (val && strncmp(val, "unix:", 5) == 0) {
|
||||||
|
mode = 4;
|
||||||
|
if ((intercept = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||||
|
fprintf(stderr, "intercept: unable to open unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
||||||
|
errno = 0;
|
||||||
|
mode = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||||
|
strncpy(addr.sun_path, val + 5, sizeof(addr.sun_path));
|
||||||
|
if (connect(intercept, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
|
fprintf(stderr, "intercept: unable to connect to unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
||||||
|
close(intercept);
|
||||||
|
errno = 0;
|
||||||
|
mode = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "intercept: intercepting function/system calls and logging to unix socket\n");
|
||||||
|
msg("PID:%li", getpid());
|
||||||
|
} else if (val && strncmp(val, "tcp://", 6) == 0) {
|
||||||
|
mode = 5;
|
||||||
|
// TODO
|
||||||
|
} else {
|
||||||
|
mode = -1;
|
||||||
|
fprintf(stderr, "intercept: not logging or manipulating function/system calls\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__sym(malloc)(size_t size) {
|
||||||
|
init();
|
||||||
|
msg("malloc(%li)", size);
|
||||||
|
if (mode >= 4) {
|
||||||
|
char buf[256];
|
||||||
|
rcv(buf, sizeof(buf));
|
||||||
|
if (strncmp(buf, "modify ", 7) == 0) {
|
||||||
|
// modify <size>
|
||||||
|
char *end_ptr = NULL;
|
||||||
|
long val = strtol(buf + 7, &end_ptr, 0);
|
||||||
|
if (end_ptr != NULL && end_ptr[0] == 0 && end_ptr != buf + 7) {
|
||||||
|
size = val;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "intercept: malloc: invalid args in modify command: '%s'\n", buf + 7);
|
||||||
|
}
|
||||||
|
} else if (strncmp(buf, "return ", 7) == 0) {
|
||||||
|
// return <ptr>
|
||||||
|
char *end_ptr = NULL;
|
||||||
|
long val = strtol(buf + 7, &end_ptr, 0);
|
||||||
|
if (end_ptr != NULL && end_ptr[0] == 0 && end_ptr != buf + 7) {
|
||||||
|
msg("return %p", val);
|
||||||
|
return (void *)val;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "intercept: malloc: invalid args in return command: '%s'\n", buf + 7);
|
||||||
|
}
|
||||||
|
} else if (strncmp(buf, "fail ", 5) == 0) {
|
||||||
|
// fail <error>
|
||||||
|
if (strcmp(buf + 5, "ENOMEM") == 0) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
} else {
|
||||||
|
errno = 0;
|
||||||
|
fprintf(stderr, "intercept: malloc: invalid error code in fail command: '%s'\n", buf + 5);
|
||||||
|
}
|
||||||
|
msg("return %p", NULL);
|
||||||
|
return NULL;
|
||||||
|
} else if (strcmp(buf, "ok") != 0) {
|
||||||
|
fprintf(stderr, "intercept: malloc: invalid command: '%s'\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void *ret = __real_malloc(size);
|
||||||
|
msg("return %p", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__sym(calloc)(size_t nmemb, size_t size) {
|
||||||
|
init();
|
||||||
|
msg("calloc(%li, %li)", nmemb, size);
|
||||||
|
if (mode >= 4) {
|
||||||
|
char buf[256];
|
||||||
|
rcv(buf, sizeof(buf));
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
void *ret = __real_calloc(nmemb, size);
|
||||||
|
msg("return %p", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__sym(realloc)(void *ptr, size_t size) {
|
||||||
|
init();
|
||||||
|
msg("realloc(%p, %li)", ptr, size);
|
||||||
|
if (mode >= 4) {
|
||||||
|
char buf[256];
|
||||||
|
rcv(buf, sizeof(buf));
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
void *ret = __real_realloc(ptr, size);
|
||||||
|
msg("return %p", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __sym(free)(void *ptr) {
|
||||||
|
init();
|
||||||
|
msg("free(%p)", ptr);
|
||||||
|
if (mode >= 4) {
|
||||||
|
char buf[256];
|
||||||
|
rcv(buf, sizeof(buf));
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
__real_free(ptr);
|
||||||
|
msg("return");
|
||||||
|
}
|
||||||
|
|
||||||
|
int __sym(getopt)(const int argc, char *const argv[], const char *shortopts) {
|
||||||
|
init();
|
||||||
|
msg("getopt(%i, %as, %es)", argc, argv, argc, shortopts);
|
||||||
|
if (mode >= 4) {
|
||||||
|
char buf[256];
|
||||||
|
rcv(buf, sizeof(buf));
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
int ret = __real_getopt(argc, argv, shortopts);
|
||||||
|
msg("return %i", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
@@ -1,225 +0,0 @@
|
|||||||
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
static int mode = 0;
|
|
||||||
static int intercept = 0;
|
|
||||||
static int *(*log)(int fd, const char *fmt, ...);
|
|
||||||
|
|
||||||
static void log_prefix(void) {
|
|
||||||
struct timespec spec;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &spec);
|
|
||||||
log(intercept, "%li.%09li ", spec.tv_sec, spec.tv_nsec);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void log_str(const char *str) {
|
|
||||||
log(intercept, "%p:\"", str);
|
|
||||||
for (char ch; (ch = *str) != 0; str++) {
|
|
||||||
if (ch == '\\' || ch == '"') {
|
|
||||||
log(intercept, "\\%c", ch);
|
|
||||||
} else if (ch == '\t') {
|
|
||||||
log(intercept, "\\t");
|
|
||||||
} else if (ch == '\n') {
|
|
||||||
log(intercept, "\\n");
|
|
||||||
} else if (ch == '\r') {
|
|
||||||
log(intercept, "\\r");
|
|
||||||
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
|
|
||||||
log(intercept, "\\x%02x", ch);
|
|
||||||
} else {
|
|
||||||
log(intercept, "%c", ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log(intercept, "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void log_array_str(char *const array[], int n) {
|
|
||||||
log(intercept, "%p:[", (void *)array);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
if (i > 0) log(intercept, ", ");
|
|
||||||
log_str(array[i]);
|
|
||||||
}
|
|
||||||
log(intercept, "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fin(void) {
|
|
||||||
if (intercept && mode > 2)
|
|
||||||
close(intercept);
|
|
||||||
if (mode > 0)
|
|
||||||
fprintf(stderr, "intercept: stopped\n");
|
|
||||||
mode = 0, intercept = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init(void) {
|
|
||||||
if (mode) return;
|
|
||||||
if ((log = dlsym(RTLD_NEXT, "dprintf")) == NULL) {
|
|
||||||
fprintf(stderr, "intercept: unable to find dlsym dprintf: %s\n", strerror(errno));
|
|
||||||
errno = 0;
|
|
||||||
mode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
atexit(fin);
|
|
||||||
const char *val = getenv("INTERCEPT");
|
|
||||||
if (val && strcmp(val, "stdout") == 0) {
|
|
||||||
mode = 1;
|
|
||||||
fprintf(stderr, "intercept: intercepting function/system calls and logging to stdout\n");
|
|
||||||
intercept = STDOUT_FILENO;
|
|
||||||
} else if (val && strcmp(val, "stderr") == 0) {
|
|
||||||
mode = 2;
|
|
||||||
fprintf(stderr, "intercept: intercepting function/system calls and logging to stderr\n");
|
|
||||||
intercept = STDERR_FILENO;
|
|
||||||
} else if (val && strncmp(val, "file:", 5) == 0) {
|
|
||||||
mode = 3;
|
|
||||||
if ((intercept = open(val + 5, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
|
|
||||||
fprintf(stderr, "intercept: unable to open log file '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
|
||||||
errno = 0;
|
|
||||||
mode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "intercept: intercepting function/system calls and logging to file\n");
|
|
||||||
} else if (val && strncmp(val, "unix:", 5) == 0) {
|
|
||||||
mode = 4;
|
|
||||||
if ((intercept = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
||||||
fprintf(stderr, "intercept: unable to open unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
|
||||||
errno = 0;
|
|
||||||
mode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
|
||||||
strncpy(addr.sun_path, val + 5, sizeof(addr.sun_path));
|
|
||||||
if (connect(intercept, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
|
||||||
fprintf(stderr, "intercept: unable to connect to unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
|
|
||||||
close(intercept);
|
|
||||||
errno = 0;
|
|
||||||
mode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "intercept: intercepting function/system calls and logging to unix socket\n");
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "PID:%li\n", getpid());
|
|
||||||
} else if (val && strncmp(val, "tcp://", 6) == 0) {
|
|
||||||
mode = 5;
|
|
||||||
// TODO
|
|
||||||
} else {
|
|
||||||
mode = -1;
|
|
||||||
fprintf(stderr, "intercept: not logging or manipulating function/system calls\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *(*__real_malloc)(size_t);
|
|
||||||
|
|
||||||
void *__real_malloc(size_t);
|
|
||||||
|
|
||||||
void *malloc(size_t size) {
|
|
||||||
init();
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "malloc(%li)\n", size);
|
|
||||||
}
|
|
||||||
if ((__real_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
|
|
||||||
errno = ENOSYS;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ret = __real_malloc(size);
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "return %p\n", ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *calloc(size_t nmemb, size_t size) {
|
|
||||||
init();
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "calloc(%li, %li)\n", nmemb, size);
|
|
||||||
}
|
|
||||||
void *(*_calloc)(size_t, size_t);
|
|
||||||
if ((_calloc = dlsym(RTLD_NEXT, "calloc")) == NULL) {
|
|
||||||
errno = ENOSYS;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ret = _calloc(nmemb, size);
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "return %p\n", ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *realloc(void *ptr, size_t size) {
|
|
||||||
init();
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "realloc(%p, %li)\n", ptr, size);
|
|
||||||
}
|
|
||||||
void *(*_realloc)(void *, size_t);
|
|
||||||
if ((_realloc = dlsym(RTLD_NEXT, "realloc")) == NULL) {
|
|
||||||
errno = ENOSYS;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ret = _realloc(ptr, size);
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "return %p\n", ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(void *ptr) {
|
|
||||||
init();
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "free(%p)\n", ptr);
|
|
||||||
}
|
|
||||||
void (*_free)(void *);
|
|
||||||
if ((_free = dlsym(RTLD_NEXT, "free")) == NULL) {
|
|
||||||
errno = ENOSYS;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_free(ptr);
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "return void\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int getopt(const int argc, char *const argv[], const char *shortopts) {
|
|
||||||
init();
|
|
||||||
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "getopt(%i, ", argc);
|
|
||||||
log_array_str(argv, argc);
|
|
||||||
log(intercept, ", ");
|
|
||||||
log_str(shortopts);
|
|
||||||
log(intercept, ")\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int (*_getopt)(int, char *const[], const char *);
|
|
||||||
if ((_getopt = dlsym(RTLD_NEXT, "getopt")) == NULL) {
|
|
||||||
errno = ENOSYS;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int ret = _getopt(argc, argv, shortopts);
|
|
||||||
|
|
||||||
if (intercept) {
|
|
||||||
log_prefix();
|
|
||||||
log(intercept, "return %i", ret);
|
|
||||||
if (ret >= 0x20 && ret < 0x7F) {
|
|
||||||
log(intercept, " ('%c')\n", ret);
|
|
||||||
} else {
|
|
||||||
log(intercept, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#define PREFIX "---====[ "
|
|
||||||
|
|
||||||
static void log_str(FILE *out, const char *str) {
|
|
||||||
fprintf(out, "%p:\"", str);
|
|
||||||
for (char ch; (ch = *str) != 0; str++) {
|
|
||||||
if (ch == '\\' || ch == '"') {
|
|
||||||
fputc('\\', out);
|
|
||||||
fputc(ch, out);
|
|
||||||
} else if (ch == '\t') {
|
|
||||||
fputs("\\t", out);
|
|
||||||
} else if (ch == '\n') {
|
|
||||||
fputs("\\n", out);
|
|
||||||
} else if (ch == '\r') {
|
|
||||||
fputs("\\r", out);
|
|
||||||
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
|
|
||||||
fprintf(out, "\\x%02x", ch);
|
|
||||||
} else {
|
|
||||||
fputc(ch, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fputc('"', out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void log_array_str(FILE *out, char *const array[], int n) {
|
|
||||||
fprintf(out, "%p:[", (void *)array);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
if (i > 0) fputs(", ", stderr);
|
|
||||||
log_str(stderr, array[i]);
|
|
||||||
}
|
|
||||||
fputc(']', out);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void *__real_malloc(size_t size);
|
|
||||||
|
|
||||||
void *__wrap_malloc(size_t size) {
|
|
||||||
fprintf(stderr, PREFIX "malloc(%li)\n", size);
|
|
||||||
void *ret = __real_malloc(size);
|
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void *__real_calloc(size_t nmemb, size_t size);
|
|
||||||
|
|
||||||
void *__wrap_calloc(size_t nmemb, size_t size) {
|
|
||||||
fprintf(stderr, PREFIX "calloc(%li, %li)\n", nmemb, size);
|
|
||||||
void *ret = __real_calloc(nmemb, size);
|
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void *__real_realloc(void *ptr, size_t size);
|
|
||||||
|
|
||||||
void *__wrap_realloc(void *ptr, size_t size) {
|
|
||||||
fprintf(stderr, PREFIX "realloc(%p, %li)\n", ptr, size);
|
|
||||||
void *ret = __real_realloc(ptr, size);
|
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void __real_free(void *ptr);
|
|
||||||
|
|
||||||
void __wrap_free(void *ptr) {
|
|
||||||
fprintf(stderr, PREFIX "free(%p)\n", ptr);
|
|
||||||
__real_free(ptr);
|
|
||||||
fprintf(stderr, PREFIX "-> void\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int __real_getopt(int argc, char *const argv[], const char *shortopts);
|
|
||||||
|
|
||||||
int __wrap_getopt(const int argc, char *const argv[], const char *shortopts) {
|
|
||||||
fprintf(stderr, PREFIX "getopt(%i, ", argc);
|
|
||||||
log_array_str(stderr, argv, argc);
|
|
||||||
fputs(", ", stderr);
|
|
||||||
log_str(stderr, shortopts);
|
|
||||||
fputs(")\n", stderr);
|
|
||||||
|
|
||||||
int ret = __real_getopt(argc, argv, shortopts);
|
|
||||||
fprintf(stderr, PREFIX "-> %i", ret);
|
|
||||||
if (ret >= 0x20 && ret < 0x7F) {
|
|
||||||
fprintf(stderr, " ('%c')\n", ret);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user