summaryrefslogtreecommitdiffstats
path: root/src/audit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audit.c')
-rw-r--r--src/audit.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/audit.c b/src/audit.c
new file mode 100644
index 0000000..d50a01f
--- /dev/null
+++ b/src/audit.c
@@ -0,0 +1,287 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ The latrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <link.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <bits/wordsize.h>
+#include <gnu/lib-names.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+
+extern struct lt_config_audit cfg;
+
+static __thread int pipe_fd = 0;
+static __thread int flow_below_stack = 0;
+
+
+static int check_names(char *name, char **ptr)
+{
+ char *n;
+
+ for(n = *ptr; n; n = *(++ptr)) {
+ if (strstr(name, n)) {
+ PRINT_VERBOSE(cfg.sh.verbose, 2,
+ "return %d for name %s\n", 1, name);
+ return 1;
+ }
+ }
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "return %d for name %s\n",
+ 0, name);
+ return 0;
+}
+
+static int check_flow_below(const char *symname, int in)
+{
+ int ret = flow_below_stack;
+
+ if (check_names((char*) symname, cfg.flow_below))
+ in ? ret = ++flow_below_stack : flow_below_stack--;
+
+ return ret;
+}
+
+static int sym_entry(const char *symname, char *lib_from, char *lib_to,
+ La_regs *regs)
+{
+ int argret;
+ char *argbuf = "", *argdbuf = "";
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "%s@%s\n", symname, lib_to);
+
+ if (cfg.flow_below_cnt && !check_flow_below(symname, 1))
+ return 0;
+
+ argret = cfg.sh.args_enabled ?
+ lt_args_sym_entry(&cfg.sh, (char*) symname, regs, &argbuf, &argdbuf) : -1;
+
+ if (cfg.sh.pipe) {
+ char buf[FIFO_MSG_MAXLEN];
+ int len;
+
+ if (!pipe_fd)
+ pipe_fd = lt_fifo_create(&cfg, cfg.dir);
+
+ len = lt_fifo_msym_get(&cfg, buf, FIFO_MSG_TYPE_ENTRY,
+ (char*) symname, lib_to, argbuf, argdbuf);
+
+ return lt_fifo_send(&cfg, pipe_fd, buf, len);
+ }
+
+ cfg.sh.indent_depth++;
+
+ lt_out_entry(&cfg.sh, symname, lib_to,
+ argbuf, argdbuf);
+
+ if (!argret) {
+ free(argbuf);
+ if (cfg.sh.args_detailed && (*argdbuf))
+ free(argdbuf);
+ }
+
+ return 0;
+}
+
+static int sym_exit(const char *symname, char *lib_from, char *lib_to,
+ const La_regs *inregs, La_retval *outregs)
+{
+ int argret;
+ char *argbuf = "", *argdbuf = "";
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "%s@%s\n", symname, lib_to);
+
+ if (cfg.flow_below_cnt && !check_flow_below(symname, 0))
+ return 0;
+
+ argret = cfg.sh.args_enabled ?
+ lt_args_sym_exit(&cfg.sh, (char*) symname,
+ (La_regs*) inregs, outregs, &argbuf, &argdbuf) : -1;
+
+ if (cfg.sh.pipe) {
+ char buf[FIFO_MSG_MAXLEN];
+ int len;
+
+ len = lt_fifo_msym_get(&cfg, buf, FIFO_MSG_TYPE_EXIT,
+ (char*) symname, lib_to, argbuf, argdbuf);
+
+ return lt_fifo_send(&cfg, pipe_fd, buf, len);
+ }
+
+ lt_out_exit(&cfg.sh, symname, lib_from,
+ argbuf, argdbuf);
+
+ cfg.sh.indent_depth--;
+
+ if (!argret) {
+ free(argbuf);
+
+ if (cfg.sh.args_detailed && (*argdbuf))
+ free(argdbuf);
+ }
+
+ return 0;
+}
+
+static int check_pid()
+{
+ pid_t pid = getpid();
+
+ PRINT_VERBOSE(cfg.sh.verbose, 1, "tid = %d, cfg tid = %d\n",
+ pid, cfg.sh.pid);
+
+ if (pid != cfg.sh.pid)
+ return -1;
+
+ return 0;
+}
+
+#define CHECK_PID(ret) \
+do { \
+ if (cfg.sh.not_follow_fork && \
+ check_pid()) \
+ return ret; \
+} while(0)
+
+unsigned int la_version(unsigned int v)
+{
+ return v;
+}
+
+unsigned int la_objopen(struct link_map *l, Lmid_t a, uintptr_t *cookie)
+{
+ char *name = l->l_name;
+
+ if (!cfg.init_ok)
+ return 0;
+
+ if (!name)
+ return 0;
+
+ /* executable itself */
+ if (!(*name))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ /* audit all as default */
+ if ((!cfg.libs_to_cnt) &&
+ (!cfg.libs_from_cnt) &&
+ (!cfg.libs_both_cnt))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ if (check_names(name, cfg.libs_to))
+ return LA_FLG_BINDTO;
+
+ if (check_names(name, cfg.libs_from))
+ return LA_FLG_BINDFROM;
+
+ if (check_names(name, cfg.libs_both))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ /* wrong library name specified ? */
+ return 0;
+}
+
+static unsigned int la_symbind(const char *symname)
+{
+ unsigned int flags = 0;
+
+ if (cfg.symbols_cnt) {
+ flags = LA_SYMB_NOPLTENTER;
+ if (check_names((char*) symname, cfg.symbols))
+ flags = 0;
+ }
+
+ return flags;
+}
+
+void la_activity(uintptr_t *cookie, unsigned int act)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+}
+
+char* la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ if (flag == LA_SER_ORIG)
+ return (char*) name;
+
+ return lt_objsearch(&cfg, name, cookie, flag);
+}
+
+void la_preinit(uintptr_t *__cookie)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+}
+
+unsigned int la_objclose(uintptr_t *__cookie)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+ return 0;
+}
+
+uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ *flags = la_symbind(symname);
+ return sym->st_value;
+}
+
+uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ *flags = la_symbind(symname);
+ return sym->st_value;
+}
+
+ElfW(Addr)
+pltenter(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, La_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ struct link_map *lr = (struct link_map*) *refcook;
+ struct link_map *ld = (struct link_map*) *defcook;
+
+ CHECK_PID(sym->st_value);
+
+ sym_entry(symname, lr ? lr->l_name : NULL, ld ? ld->l_name : NULL, regs);
+ *framesizep = cfg.sh.framesize;
+ return sym->st_value;
+}
+
+unsigned int pltexit(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs,
+ const char *symname)
+{
+ struct link_map *lr = (struct link_map*) *refcook;
+ struct link_map *ld = (struct link_map*) *defcook;
+
+ CHECK_PID(0);
+
+ sym_exit(symname, lr ? lr->l_name : NULL, ld ? ld->l_name : NULL, inregs, outregs);
+ return 0;
+}