[ABRT PATCH 1/3] abrt-server: updates/fixes for future rasdaemon needs
by Denys Vlasenko
FILENAME_BACKTRACE and FILENAME_EXECUTABLE make no sense for rasdaemon's
ECC memory errors reporting - we shouldn't require those.
Also, we should allow requests with only "type=..."
but without "analyzer=..." (a step for analyzer -> type transition).
Bug fix: PUT is the _wrong type of request for creation
of new entities_! Added POST as an alias.
Updated abrt-server.txt to show POST and lowercased item names.
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
doc/abrt-server.txt | 20 +++++++++----------
src/daemon/abrt-server.c | 52 ++++++++++++++++++++++++++++++++++--------------
2 files changed, 46 insertions(+), 26 deletions(-)
diff --git a/doc/abrt-server.txt b/doc/abrt-server.txt
index 8e9958b..bf9b40d 100644
--- a/doc/abrt-server.txt
+++ b/doc/abrt-server.txt
@@ -38,22 +38,20 @@ connect to UNIX domain socket /var/run/abrt.socket
Providing data (writting data to the socket):
-------------------------------------------------
--> "PUT / HTTP/1.1\r\n"
+-> "POST / HTTP/1.1\r\n"
-> "\r\n"
--> "PID=number\0"
+-> "type=string\0"
+ string, maximum length 100 bytes
+-> "reason=string\0"
+ string, maximum length 512 bytes
+-> "pid=number\0"
number, 0 - PID_MAX (/proc/sys/kernel/pid_max)
--> "EXECUTABLE=string\0"
+-> "executable=string\0"
string, maximum length ~MAX_PATH
--> "BACKTRACE=string\0"
+-> "backtrace=string\0"
string, maximum length 1 MB
--> "ANALYZER=string\0"
- string, maximum length 100 bytes
--> "BASENAME=string\0"
- string maximum length 100 bytes, no slashes
--> "REASON=string\0"
- string, maximum length 512 bytes
-> (close writing half of the socket)
-<- "HTTP/1.1 200 \r\n"
+<- "HTTP/1.1 201 \r\n"
<- "\r\n"
-------------------------------------------------
diff --git a/src/daemon/abrt-server.c b/src/daemon/abrt-server.c
index 98d6db0..14c2f69 100644
--- a/src/daemon/abrt-server.c
+++ b/src/daemon/abrt-server.c
@@ -89,7 +89,7 @@ static int create_problem_dir(GHashTable *problem_info, unsigned pid)
gchar *dir_basename = g_hash_table_lookup(problem_info, "basename");
if (!dir_basename)
- dir_basename = g_hash_table_lookup(problem_info, FILENAME_ANALYZER);
+ dir_basename = g_hash_table_lookup(problem_info, FILENAME_TYPE);
char *path = xasprintf("%s/%s-%s-%u.new",
g_settings_dump_location,
@@ -232,7 +232,7 @@ static gboolean key_value_ok(gchar *key, gchar *value)
/* check value of 'basename', it has to be valid non-hidden directory
* name */
if (strcmp(key, "basename") == 0
- || strcmp(key, FILENAME_ANALYZER) == 0
+ || strcmp(key, FILENAME_TYPE) == 0
)
{
if (!is_correct_filename(value))
@@ -268,7 +268,11 @@ static void process_message(GHashTable *problem_info, char *message)
else
{
g_hash_table_insert(problem_info, key, xstrdup(value));
- key = NULL; /* prevent freeing later */
+ /* Compat, delete when FILENAME_ANALYZER is replaced by FILENAME_TYPE: */
+ if (strcmp(key, FILENAME_TYPE) == 0)
+ g_hash_table_insert(problem_info, xstrdup(FILENAME_ANALYZER), xstrdup(value));
+ /* Prevent freeing key later: */
+ key = NULL;
}
}
else
@@ -289,11 +293,13 @@ static void die_if_data_is_missing(GHashTable *problem_info)
{
gboolean missing_data = FALSE;
gchar **pstring;
- static const gchar *const needed[] = {FILENAME_ANALYZER,
- FILENAME_BACKTRACE,
- FILENAME_EXECUTABLE,
- FILENAME_REASON,
- NULL};
+ static const gchar *const needed[] = {
+ FILENAME_TYPE,
+ FILENAME_REASON,
+ /* FILENAME_BACKTRACE, - ECC errors have no such elements */
+ /* FILENAME_EXECUTABLE, */
+ NULL
+ };
for (pstring = (gchar**) needed; *pstring; pstring++)
{
@@ -408,8 +414,14 @@ static int perform_http_xact(void)
return delete_path(messagebuf_data);
}
- if (strncmp(messagebuf_data, "PUT ", strlen("PUT ")) != 0)
- {
+ /* We erroneously used "PUT /" to create new problems.
+ * POST is the correct request in this case:
+ * "PUT /" implies creation or replace of resource named "/"!
+ * Delete PUT in 2014.
+ */
+ if (strncmp(messagebuf_data, "PUT ", strlen("PUT ")) != 0
+ && strncmp(messagebuf_data, "POST ", strlen("POST ")) != 0
+ ) {
return 400; /* Bad Request */;
}
@@ -464,11 +476,21 @@ static int perform_http_xact(void)
die_if_data_is_missing(problem_info);
char *executable = g_hash_table_lookup(problem_info, FILENAME_EXECUTABLE);
- char *last_file = concat_path_file(g_settings_dump_location, "last-via-server");
- int repeating_crash = check_recent_crash_file(last_file, executable);
- free(last_file);
- if (repeating_crash) /* Only pretend that we saved it */
- goto out; /* ret is 0: "success" */
+ if (executable)
+ {
+ char *last_file = concat_path_file(g_settings_dump_location, "last-via-server");
+ int repeating_crash = check_recent_crash_file(last_file, executable);
+ free(last_file);
+ if (repeating_crash) /* Only pretend that we saved it */
+ goto out; /* ret is 0: "success" */
+ }
+
+#if 0
+//TODO:
+ /* At least it should generate local problem identifier UUID */
+ problem_data_add_basics(problem_info);
+//...the problem being that problem_info here is not a problem_data_t!
+#endif
ret = create_problem_dir(problem_info, pid);
--
1.8.1.4
11 years
[ABRT PATCH] abrt-server: update for future rasdaemon needs + bugfixes
by Denys Vlasenko
FILENAME_BACKTRACE and FILENAME_EXECUTABLE make no sense for rasdaemon's
ECC memory errors reporting - we shouldn't require those.
Also, we should allow requests with only "type=..."
but without "analyzer=..." (a step for analyzer -> type transition).
While at it, helped abrt-dump-xorg to save "type" item too.
Bug fix: PUT is the _wrong type of request for creation
of new entities_! Added POST as an alias.
Updated abrt-server.txt to show POST and lowercased item names.
Similarly updated python crash reporter module.
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
doc/abrt-server.txt | 20 ++++++-------
src/daemon/abrt-server.c | 52 ++++++++++++++++++++++++----------
src/hooks/abrt_exception_handler.py.in | 13 ++++-----
src/plugins/abrt-dump-xorg.c | 1 +
4 files changed, 53 insertions(+), 33 deletions(-)
diff --git a/doc/abrt-server.txt b/doc/abrt-server.txt
index 8e9958b..bf9b40d 100644
--- a/doc/abrt-server.txt
+++ b/doc/abrt-server.txt
@@ -38,22 +38,20 @@ connect to UNIX domain socket /var/run/abrt.socket
Providing data (writting data to the socket):
-------------------------------------------------
--> "PUT / HTTP/1.1\r\n"
+-> "POST / HTTP/1.1\r\n"
-> "\r\n"
--> "PID=number\0"
+-> "type=string\0"
+ string, maximum length 100 bytes
+-> "reason=string\0"
+ string, maximum length 512 bytes
+-> "pid=number\0"
number, 0 - PID_MAX (/proc/sys/kernel/pid_max)
--> "EXECUTABLE=string\0"
+-> "executable=string\0"
string, maximum length ~MAX_PATH
--> "BACKTRACE=string\0"
+-> "backtrace=string\0"
string, maximum length 1 MB
--> "ANALYZER=string\0"
- string, maximum length 100 bytes
--> "BASENAME=string\0"
- string maximum length 100 bytes, no slashes
--> "REASON=string\0"
- string, maximum length 512 bytes
-> (close writing half of the socket)
-<- "HTTP/1.1 200 \r\n"
+<- "HTTP/1.1 201 \r\n"
<- "\r\n"
-------------------------------------------------
diff --git a/src/daemon/abrt-server.c b/src/daemon/abrt-server.c
index 98d6db0..14c2f69 100644
--- a/src/daemon/abrt-server.c
+++ b/src/daemon/abrt-server.c
@@ -89,7 +89,7 @@ static int create_problem_dir(GHashTable *problem_info, unsigned pid)
gchar *dir_basename = g_hash_table_lookup(problem_info, "basename");
if (!dir_basename)
- dir_basename = g_hash_table_lookup(problem_info, FILENAME_ANALYZER);
+ dir_basename = g_hash_table_lookup(problem_info, FILENAME_TYPE);
char *path = xasprintf("%s/%s-%s-%u.new",
g_settings_dump_location,
@@ -232,7 +232,7 @@ static gboolean key_value_ok(gchar *key, gchar *value)
/* check value of 'basename', it has to be valid non-hidden directory
* name */
if (strcmp(key, "basename") == 0
- || strcmp(key, FILENAME_ANALYZER) == 0
+ || strcmp(key, FILENAME_TYPE) == 0
)
{
if (!is_correct_filename(value))
@@ -268,7 +268,11 @@ static void process_message(GHashTable *problem_info, char *message)
else
{
g_hash_table_insert(problem_info, key, xstrdup(value));
- key = NULL; /* prevent freeing later */
+ /* Compat, delete when FILENAME_ANALYZER is replaced by FILENAME_TYPE: */
+ if (strcmp(key, FILENAME_TYPE) == 0)
+ g_hash_table_insert(problem_info, xstrdup(FILENAME_ANALYZER), xstrdup(value));
+ /* Prevent freeing key later: */
+ key = NULL;
}
}
else
@@ -289,11 +293,13 @@ static void die_if_data_is_missing(GHashTable *problem_info)
{
gboolean missing_data = FALSE;
gchar **pstring;
- static const gchar *const needed[] = {FILENAME_ANALYZER,
- FILENAME_BACKTRACE,
- FILENAME_EXECUTABLE,
- FILENAME_REASON,
- NULL};
+ static const gchar *const needed[] = {
+ FILENAME_TYPE,
+ FILENAME_REASON,
+ /* FILENAME_BACKTRACE, - ECC errors have no such elements */
+ /* FILENAME_EXECUTABLE, */
+ NULL
+ };
for (pstring = (gchar**) needed; *pstring; pstring++)
{
@@ -408,8 +414,14 @@ static int perform_http_xact(void)
return delete_path(messagebuf_data);
}
- if (strncmp(messagebuf_data, "PUT ", strlen("PUT ")) != 0)
- {
+ /* We erroneously used "PUT /" to create new problems.
+ * POST is the correct request in this case:
+ * "PUT /" implies creation or replace of resource named "/"!
+ * Delete PUT in 2014.
+ */
+ if (strncmp(messagebuf_data, "PUT ", strlen("PUT ")) != 0
+ && strncmp(messagebuf_data, "POST ", strlen("POST ")) != 0
+ ) {
return 400; /* Bad Request */;
}
@@ -464,11 +476,21 @@ static int perform_http_xact(void)
die_if_data_is_missing(problem_info);
char *executable = g_hash_table_lookup(problem_info, FILENAME_EXECUTABLE);
- char *last_file = concat_path_file(g_settings_dump_location, "last-via-server");
- int repeating_crash = check_recent_crash_file(last_file, executable);
- free(last_file);
- if (repeating_crash) /* Only pretend that we saved it */
- goto out; /* ret is 0: "success" */
+ if (executable)
+ {
+ char *last_file = concat_path_file(g_settings_dump_location, "last-via-server");
+ int repeating_crash = check_recent_crash_file(last_file, executable);
+ free(last_file);
+ if (repeating_crash) /* Only pretend that we saved it */
+ goto out; /* ret is 0: "success" */
+ }
+
+#if 0
+//TODO:
+ /* At least it should generate local problem identifier UUID */
+ problem_data_add_basics(problem_info);
+//...the problem being that problem_info here is not a problem_data_t!
+#endif
ret = create_problem_dir(problem_info, pid);
diff --git a/src/hooks/abrt_exception_handler.py.in b/src/hooks/abrt_exception_handler.py.in
index 710ebdc..774a586 100644
--- a/src/hooks/abrt_exception_handler.py.in
+++ b/src/hooks/abrt_exception_handler.py.in
@@ -53,16 +53,15 @@ def write_dump(tb_text, tb):
s.settimeout(5)
try:
s.connect(@VAR_RUN@ + "/abrt/abrt.socket")
- s.sendall("PUT / HTTP/1.1\r\n\r\n")
- s.sendall("PID=%s\0" % os.getpid())
- s.sendall("EXECUTABLE=%s\0" % executable)
- s.sendall("ANALYZER=Python\0")
- s.sendall("BASENAME=pyhook\0")
+ s.sendall("POST / HTTP/1.1\r\n\r\n")
+ s.sendall("type=Python\0")
+ s.sendall("pid=%s\0" % os.getpid())
+ s.sendall("executable=%s\0" % executable)
# This handler puts a short(er) crash descr in 1st line of the backtrace.
# Example:
# CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero
- s.sendall("REASON=%s\0" % tb_text.splitlines()[0])
- s.sendall("BACKTRACE=%s\0" % tb_text)
+ s.sendall("reason=%s\0" % tb_text.splitlines()[0])
+ s.sendall("backtrace=%s\0" % tb_text)
if dso_list:
s.sendall("dso_list=%s\0" % "\n".join(dso_list))
diff --git a/src/plugins/abrt-dump-xorg.c b/src/plugins/abrt-dump-xorg.c
index 5e84f81..e3d6b0a 100644
--- a/src/plugins/abrt-dump-xorg.c
+++ b/src/plugins/abrt-dump-xorg.c
@@ -100,6 +100,7 @@ static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *rea
dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
dd_save_text(dd, FILENAME_ANALYZER, "xorg");
+ dd_save_text(dd, FILENAME_TYPE, "xorg");
dd_save_text(dd, FILENAME_REASON, reason);
dd_save_text(dd, FILENAME_BACKTRACE, bt);
/*
--
1.8.1.4
11 years
[RFC ABRT PATCH v2] Add gdb python plugin which analyzes vulnerability
by Denys Vlasenko
This is an RFC, please do not commit.
Usage:
Run abrt-action-analyze-vulnerability in a directory which contains
./coredump file.
If crash looks exploitable, the tool creates ./exploitable file.
Example such a file:
"""
Likely crash reason: Write to an invalid address
Exploitable rating (0-9 scale): 6
"""
This patch adds abrt-action-analyze-vulnerability invocation to
"EVENT=post-create analyzer=CCpp".
TODO:
* improve error detection (e.g. what to do if gdb failed to run?)
* suppress stray gdb output
* set $SIGNO_OF_THE_COREDUMP to work around non-working $_siginfo.si_signo
* decide whether to push for $_signo support in gdb (I have a tested gdb patch)
* instruction analyzer is x86 specific now, make it per-arch
(how to get arch name???)
v2: improved instruction analyzer, added more exploibable cases to detect,
added tests
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
abrt.spec.in | 2 +
src/plugins/Makefile.am | 10 +-
src/plugins/abrt-action-analyze-vulnerability | 9 +
src/plugins/abrt-gdb-exploitable | 502 +++++++++++++++++++++
src/plugins/ccpp_event.conf | 5 +-
tests/abrt-exploitable/.gitignore | 10 +
tests/abrt-exploitable/Makefile | 67 +++
tests/abrt-exploitable/testDivideByZero.c | 10 +
tests/abrt-exploitable/testExecuteInvalid.c | 17 +
.../abrt-exploitable/testFloatingPointException.c | 10 +
tests/abrt-exploitable/testReadNull.c | 12 +
tests/abrt-exploitable/testReadRandom.c | 14 +
tests/abrt-exploitable/testSignalAbort.c | 10 +
tests/abrt-exploitable/testSignalIll.c | 10 +
tests/abrt-exploitable/testStackBufferOverflow.c | 23 +
tests/abrt-exploitable/testStackRecursion.c | 15 +
tests/abrt-exploitable/testWriteRandom.c | 15 +
17 files changed, 738 insertions(+), 3 deletions(-)
create mode 100755 src/plugins/abrt-action-analyze-vulnerability
create mode 100755 src/plugins/abrt-gdb-exploitable
create mode 100644 tests/abrt-exploitable/.gitignore
create mode 100644 tests/abrt-exploitable/Makefile
create mode 100644 tests/abrt-exploitable/testDivideByZero.c
create mode 100644 tests/abrt-exploitable/testExecuteInvalid.c
create mode 100644 tests/abrt-exploitable/testFloatingPointException.c
create mode 100644 tests/abrt-exploitable/testReadNull.c
create mode 100644 tests/abrt-exploitable/testReadRandom.c
create mode 100644 tests/abrt-exploitable/testSignalAbort.c
create mode 100644 tests/abrt-exploitable/testSignalIll.c
create mode 100644 tests/abrt-exploitable/testStackBufferOverflow.c
create mode 100644 tests/abrt-exploitable/testStackRecursion.c
create mode 100644 tests/abrt-exploitable/testWriteRandom.c
diff --git a/abrt.spec.in b/abrt.spec.in
index fec5b56..ce5f944 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -670,6 +670,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_initrddir}/abrt-ccpp
%endif
%{_libexecdir}/abrt-hook-ccpp
+%{_libexecdir}/abrt-gdb-exploitable
# attr(6755) ~= SETUID|SETGID
%attr(6755, abrt, abrt) %{_libexecdir}/abrt-action-install-debuginfo-to-abrt-cache
@@ -677,6 +678,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_bindir}/abrt-action-analyze-c
%{_bindir}/abrt-action-trim-files
%{_bindir}/abrt-action-analyze-core
+%{_bindir}/abrt-action-analyze-vulnerability
%{_bindir}/abrt-action-install-debuginfo
%{_bindir}/abrt-action-generate-backtrace
%{_bindir}/abrt-action-generate-core-backtrace
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 767c045..20e0297 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -3,6 +3,7 @@
bin_SCRIPTS = \
abrt-action-install-debuginfo \
abrt-action-analyze-core \
+ abrt-action-analyze-vulnerability \
abrt-action-analyze-vmcore \
abrt-action-list-dsos \
abrt-action-perform-ccpp-analysis \
@@ -29,9 +30,12 @@ bin_PROGRAMS += \
abrt-bodhi
endif
-libexec_PROGRAMS = abrt-action-install-debuginfo-to-abrt-cache
+libexec_PROGRAMS = \
+ abrt-action-install-debuginfo-to-abrt-cache
-libexec_SCRIPTS = abrt-action-ureport
+libexec_SCRIPTS = \
+ abrt-action-ureport \
+ abrt-gdb-exploitable
#dist_pluginsconf_DATA = Python.conf
@@ -68,6 +72,7 @@ PYTHON_FILES = \
abrt-action-install-debuginfo.in \
abrt-action-list-dsos \
abrt-action-analyze-core \
+ abrt-action-analyze-vulnerability \
abrt-action-analyze-vmcore.in \
abrt-action-perform-ccpp-analysis.in
@@ -84,6 +89,7 @@ EXTRA_DIST = \
abrt-action-analyze-vmcore \
abrt-action-save-kernel-data \
abrt-action-ureport \
+ abrt-gdb-exploitable \
https-utils.h \
post_report.xml.in \
abrt-action-analyze-ccpp-local
diff --git a/src/plugins/abrt-action-analyze-vulnerability b/src/plugins/abrt-action-analyze-vulnerability
new file mode 100755
index 0000000..f2a410e
--- /dev/null
+++ b/src/plugins/abrt-action-analyze-vulnerability
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if type gdb >/dev/null 2>&1; then
+ # gdb is avaliable
+ gdb --batch \
+ -ex 'python execfile("/usr/libexec/abrt-gdb-exploitable")' \
+ -ex 'core-file ./coredump' \
+ -ex 'abrt-exploitable 5 ./exploitable'
+fi
diff --git a/src/plugins/abrt-gdb-exploitable b/src/plugins/abrt-gdb-exploitable
new file mode 100755
index 0000000..4f73e0b
--- /dev/null
+++ b/src/plugins/abrt-gdb-exploitable
@@ -0,0 +1,502 @@
+#!/usr/bin/python
+# This is a GDB plugin.
+# Usage:
+# gdb --batch -ex 'python execfile("THIS_FILE")' -ex run -ex abrt-exploitable PROG
+# or
+# gdb --batch -ex 'python execfile("THIS_FILE")' -ex 'core COREDUMP' -ex abrt-exploitable
+
+import gdb
+import os
+import signal
+
+_writing_instr = {
+ # insn:N, where N:
+ # -1: this insn always writes to memory
+ # -2: writes to memory if any operand is a memory operand
+ # 2: writes to memory if 2nd (or later) operand is a memory operand
+ #
+ # Two-operand insns
+ "add":2,
+ "adc":2,
+ "sub":2,
+ "sbb":2,
+ "and":2,
+ "xor":2,
+ "or":2,
+ "xadd":2,
+ "cmpxchg":2,
+ # One-operand insns. Can use 1 or -2
+ "inc":-2,
+ "dec":-2,
+ "neg":-2,
+ "not":-2,
+ "pop":-2,
+ # "Set byte on condition". One-operand insns.
+ "seta":-2,
+ "setae":-2,
+ "setb":-2,
+ "setbe":-2,
+ "setc":-2,
+ "sete":-2,
+ "setg":-2,
+ "setge":-2,
+ "setl":-2,
+ "setle":-2,
+ "setna":-2,
+ "setnae":-2,
+ "setnb":-2,
+ "setnbe":-2,
+ "setnc":-2,
+ "setne":-2,
+ "setng":-2,
+ "setnge":-2,
+ "setnl":-2,
+ "setnle":-2,
+ "setno":-2,
+ "setnp":-2,
+ "setns":-2,
+ "setnz":-2,
+ "seto":-2,
+ "setp":-2,
+ "setpe":-2,
+ "setpo":-2,
+ "sets":-2,
+ "setz":-2,
+ # Shifts.
+ # sarl $2,(%rcx)
+ # sarl (%rax) - *implicit* operand (shift count) 1.
+ # shld 11,%ecx,(%rdi) - *third* operand is r/m.
+ # Luckily, any memory operand is a destination, can use -2.
+ "shl":-2,
+ "shr":-2,
+ "sal":-2,
+ "sar":-2,
+ "rol":-2,
+ "ror":-2,
+ "rcl":-2,
+ "rcr":-2,
+ "shld":-2,
+ "shrd":-2,
+ # Bit tests. Any memory operand is a destination, can use -2.
+ "bts":-2,
+ "btr":-2,
+ "btc":-2,
+ # One-operand (register pair is another, implicit operand).
+ "cmpxchg8b":-2,
+ "cmpxchg16b":-2,
+
+ # Either mem operand indicates write to mem.
+ "xchg":-2,
+
+ # String store insns.
+ # Look similar to widening signed move "movs[bwl][wlq]",
+ # but aliasing doesn't happen since widening move has two siffixes
+ "movs":-1,
+ "stos":-1,
+ # Widening moves never store to mem.
+ # May look like we need to list them because otherwise they get caught
+ # by "movXXX", but thankfully their 2nd operand is never a memory reference,
+ # which "movXXX" wildcard checks.
+ #"mov[sz][bwl][wlq]":0,
+
+ # One-operand insn.
+ # These are system insns, but they do NOT cause exception in userspace.
+ "smsw":-2,
+ "sgdt":-2,
+ "sidt":-2,
+ "sldt":-2,
+ "str":-2,
+
+ # FPU/SIMD madness follows.
+
+ # FPU store insns. One-operand.
+ "fsts":-2,
+ "fstl":-2,
+ #"fstt" doesn't exist
+ "fstps":-2,
+ "fstpl":-2,
+ "fstpt":-2,
+ # Saving state. One-operand insns.
+ "fstcw":-2,
+ "fnstcw":-2,
+ "fstsw":-2,
+ "fnstsw":-2,
+ "fstenv":-2,
+ "fnstenv":-2,
+ "fsave":-2,
+ "fnsave":-2,
+ "fxsave":-2,
+ "xsave":-2,
+ "xsaveopt":-2,
+ "fsave64":-2,
+ "fnsave64":-2,
+ "fxsave64":-2,
+ "xsave64":-2,
+ "xsaveopt64":-2,
+ "stmxcsr":-2,
+ "vstmxcsr":-2,
+ # SIMD store insns.
+ # Three-operand insns. Any memory operand is a destination.
+ "vcvtps2ph":-2,
+ "extractps":-2,
+ "vextractps":-2,
+ #[v]extractpd does not exist
+ "vextractf128":-2,
+ "vextracti128":-2,
+ "pextr":-2, # covers pextr[bwq]
+ "pextrd":-2,
+ "vpextr":-2,
+ "vpextrd":-2,
+ "vmaskmovpd":-2,
+ "vmaskmovps":-2,
+ "vpmaskmovd":-2,
+ "vpmaskmovq":-2,
+ # These insns have implicit (%edi) dest operand:
+ "maskmovq":-1, # mmx version
+ "maskmovdqu":-1,
+ "vmaskmovdqu":-1,
+
+ # check binutils/gas/testsuite/gas/i386/* for more weird insns
+ # Instruction Set Reference, A-M and N-Z:
+ # http://download.intel.com/products/processor/manual/253666.pdf
+ # http://download.intel.com/products/processor/manual/253667.pdf
+ # SSE4:
+ # http://software.intel.com/sites/default/files/m/0/3/c/d/4/18187-d9156103.pdf
+ # Instruction Set Extensions:
+ # http://download-software.intel.com/sites/default/files/319433-014.pdf
+ # Xeon Phi:
+ # http://download-software.intel.com/sites/default/files/forum/278102/32736...
+
+ #"vmovXXX" - special-cased in the code
+ "mov":2
+
+ # Note: stack-writing instructions are omitted
+}
+
+_pushing_instr = {
+ "push":-1,
+ "pusha":-1,
+ "pushf":-1,
+ "enter":-1,
+ "call":-1,
+ "lcall":-1
+}
+
+_intdiv_instr = {
+ "div":-1,
+ "idiv":-1
+}
+
+_jumping_instr = {
+ "jmp":-1, # indirect jumps/calls with garbage data
+ "call":-1, # call: also possible that stack is exhausted (infinite recursion)
+ "ljmp":-1,
+ "lcall":-1,
+ # Yes, lret/iret isn't used in normal userspace code,
+ # but it does work (compile with "gcc -nostartfiles -nostdlib -m32"):
+ #
+ #_start: .globl _start
+ # pushf
+ # push %cs
+ # push $next
+ # iret # lret or ret would work too
+ #next:
+ # movl $42, %ebx
+ # movl $1, %eax
+ # int $0x80 # exit(42)
+ #
+ "iret":-1,
+ "lret":-1,
+ "ret":-1
+}
+
+_return_instr = {
+ "iret":-1,
+ "lret":-1,
+ "ret":-1 # stack smashed if we crash on this
+}
+
+def _fetch_insn_from_table(ins, table):
+ if not ins:
+ return None
+ if ins in table.keys():
+ return table[ins]
+ # Drop common byte/word/long/quad suffix and try again
+ if ins[-1] in ("b", "w", "l", "q"):
+ ins = ins[:-1]
+ if ins in table.keys():
+ return table[ins]
+ return None
+
+def _instruction_is_writing(self):
+ operand = _fetch_insn_from_table(self.mnemonic, _writing_instr)
+ if not operand:
+ if not self.mnemonic:
+ return False
+ # There are far too many SSE store instructions,
+ # don't want to pollute the table with them.
+ # Special-case the check for MOVxxx
+ # and its SIMD cousins VMOVxxx:
+ if self.mnemonic[:3] != "mov" and self.mnemonic[:4] != "vmov":
+ return False
+ operand = 2
+
+ if operand == -1: # no need to check operands, it's a write
+ return True
+
+ # Memory operands look like this: [%seg:][[-]0xHEXNUM][(%reg[,...])]
+ # Careful with immediate operands which are $0xHEXNUM
+ # and FPU register references which are st(N).
+ if self.operands.startswith("0x") or self.operands.startswith("-0x") or self.operands.startswith("("):
+ mem_op_pos = 0
+ else:
+ mem_op_pos = self.operands.find(",0x")
+ if mem_op_pos < 0:
+ mem_op_pos = self.operands.find(",-0x")
+ if mem_op_pos < 0:
+ mem_op_pos = self.operands.find(":0x")
+ if mem_op_pos < 0:
+ mem_op_pos = self.operands.find(":-0x")
+ if mem_op_pos < 0:
+ mem_op_pos = self.operands.find(",(")
+ if mem_op_pos < 0:
+ mem_op_pos = self.operands.find(":(")
+ if mem_op_pos < 0:
+ return False # no memory operands
+ mem_op_pos += 1
+
+ if operand == -2: # any mem operand indicates write
+ return True
+
+ comma = self.operands.find(",")
+ if mem_op_pos < comma:
+ # "%cs:0x0(%rax,%rax,1),foo" - 1st operand is memory
+ # "%cs:0x0(%rax),foo" - 1st operand is memory
+ memory_operand = 1
+ elif comma < 0:
+ # "%cs:0x0(%rax)" - 1st operand is memory
+ memory_operand = 1
+ else:
+ # mem_op_pos is after comma
+ # "foo,%cs:0x0(%rax,%rax,1)" - 2nd operand is memory
+ # (It also can be a third, fourth etc operand)
+ memory_operand = 2
+
+ if operand == memory_operand:
+ return True
+ return False
+
+def _instruction_is_pushing(self):
+ if _fetch_insn_from_table(self.mnemonic, _pushing_instr):
+ return True
+ return False
+
+def _instruction_is_division(self):
+ if _fetch_insn_from_table(self.mnemonic, _intdiv_instr):
+ return True
+ return False
+
+def _instruction_is_jumping(self):
+ if _fetch_insn_from_table(self.mnemonic, _jumping_instr):
+ return True
+ return False
+
+def _instruction_is_return(self):
+ if _fetch_insn_from_table(self.mnemonic, _return_instr):
+ return True
+ return False
+
+class _Signal_and_Insn:
+ pass
+
+def _get_signal_and_instruction():
+ si = _Signal_and_Insn()
+ si.signo = None
+ try:
+ sig = gdb.parse_and_eval("$_signo") # ("$_siginfo.si_signo")
+ # type(sig) = <type 'gdb.Value'>
+ # sig is 8 (for SIGFPE)
+ si.signo = int(sig)
+ except gdb.error:
+ # Python Exception <class 'gdb.error'> Attempt to extract a component of a value that is not a structure.:
+ # Possible reasons why $_siginfo doesn't exist:
+ # program is still running, program exited normally,
+ # we work with a coredump from an old kernel.
+ #
+ # HACK_ALERT: kernels before 3.?.? do not record siginfo in coredumps,
+ # so $_siginfo isn't present.
+ # Lets see whether we are running from the abrt and it provided us with signal number
+ #
+ try:
+ si.signo = int(os.environ["SIGNO_OF_THE_COREDUMP"])
+ except KeyError:
+ return None
+
+ si.current_instruction = None
+ si.mnemonic = None
+ si.operands = ""
+ try:
+ # just "disassemble $pc" won't work if $pc doesn't point
+ # inside a known function
+ instructions = gdb.execute("disassemble $pc,$pc+32", to_string=True)
+ # type(instructions) = <type 'str'>
+ except gdb.error:
+ # For example, if tracee already exited normally.
+ # Another observed case is if $pc points to unmapped area.
+ # Python Exception <class 'gdb.error'> No registers.:
+ return si
+
+ raw_instructions = instructions
+ #print instructions
+ instructions = []
+ current = None
+ for line in raw_instructions.split("\n"):
+ # line can be:
+ # "Dump of assembler code from 0xAAAA to 0xBBBB:"
+ # "[=>] 0x00000000004004dc[ <+0>]: push %rbp"
+ # (" <+0>" part is present when we run on a live process,
+ # on coredump it is absent)
+ # "End of assembler dump."
+ # "" (empty line)
+ if line.startswith("=>"):
+ line = line[2:]
+ current = len(instructions)
+ line = line.split(":", 1)
+ if len(line) < 2: # no ":"?
+ continue
+ line = line[1] # drop "foo:"
+ line = line.strip() # drop leading/trailing whitespace
+ if line:
+ instructions.append(line)
+ if current == None:
+ # not False! we determined that $pc points to a bad address,
+ # which is an interesting fact.
+ return si
+
+ si.current_instruction = instructions[current]
+ # TODO: too simplistic.
+ # consider this example:
+ # "data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)"
+ t = si.current_instruction.split(None,2)
+ si.mnemonic = t[0]
+ if len(t) > 1:
+ si.operands = t[1]
+ return si
+
+#Our initial set of testing will use the list Apple included in their
+#CrashWrangler announcement:
+#
+#Exploitable if:
+# Crash on write instruction
+# Crash executing invalid address
+# Crash calling an invalid address
+# Crash accessing an uninitialized or freed pointer as indicated by
+# using the MallocScribble environment variable
+# Illegal instruction exception
+# Abort due to -fstack-protector, _FORTIFY_SOURCE, heap corruption
+# detected
+# Stack trace of crashing thread contains certain functions such as
+# malloc, free, szone_error, objc_MsgSend, etc.
+
+def _is_exploitable(self):
+ self.exploitable_rating = 3
+ self.exploitable_desc = ""
+
+ if 0:
+ pass
+ # SIGABRT Abort signal from abort(3)
+ # SIGQUIT Quit from keyboard
+ # SIGXCPU CPU time limit exceeded
+ # SIGXFSZ File size limit exceeded
+ # SIGTRAP Trace/breakpoint trap
+ # SIGSYS Bad argument to routine (SVr4)
+ # SIGFPE Floating point exception
+ # SIGILL Illegal Instruction
+ # SIGSEGV Invalid memory reference
+ # SIGBUS Bus error (bad memory access)
+ elif self.signo == signal.SIGABRT:
+ self.exploitable_rating = 0
+ self.exploitable_desc = "ABRT signal (abort() was called?)"
+ elif self.signo == signal.SIGQUIT:
+ self.exploitable_rating = 0
+ self.exploitable_desc = "QUIT signal (Ctrl-\ pressed?)"
+ elif self.signo == signal.SIGXCPU:
+ self.exploitable_rating = 0
+ self.exploitable_desc = "XCPU signal (over CPU time limit)"
+ elif self.signo == signal.SIGXFSZ:
+ self.exploitable_rating = 0
+ self.exploitable_desc = "XFSZ signal (over file size limit)"
+ elif self.signo == signal.SIGTRAP:
+ self.exploitable_rating = 0
+ self.exploitable_desc = "TRAP signal (can be a bug in a debugger/tracer)"
+ elif self.signo == signal.SIGSYS:
+ self.exploitable_rating = 1
+ self.exploitable_desc = "SYS signal (unknown/masked syscall was called?)"
+
+ elif self.signo == signal.SIGFPE:
+ self.exploitable_rating = 1
+ self.exploitable_desc = "Arithmetic exception occurred"
+ if _instruction_is_division(self):
+ self.exploitable_rating = 0
+ self.exploitable_desc = "Division by zero occurred"
+ elif self.signo == signal.SIGILL:
+ self.exploitable_rating = 5
+ self.exploitable_desc = "Illegal instruction (jump to a random address?)"
+
+ # TODO: check that sig is SIGSEGV/SIGBUS?
+
+ elif _instruction_is_pushing(self):
+ self.exploitable_rating = 4
+ self.exploitable_desc = "Stack overflow"
+ elif _instruction_is_writing(self):
+ self.exploitable_rating = 6
+ self.exploitable_desc = "Write to an invalid address"
+ elif _instruction_is_return(self):
+ self.exploitable_rating = 7
+ self.exploitable_desc = "Subroutine return to an invalid address (corrupted stack?)"
+ # Note: we check "ret" first, _then_ jumps.
+ # Corrupted stack is different from corrupted data.
+ elif _instruction_is_jumping(self):
+ self.exploitable_rating = 6
+ self.exploitable_desc = "Jump to an invalid address"
+ elif not self.current_instruction:
+ self.exploitable_rating = 6
+ self.exploitable_desc = "Jump to an invalid address"
+ elif self.signo == signal.SIGBUS:
+ self.exploitable_rating = 5
+ self.exploitable_desc = "Access past the end of mapped file, invalid address, unaligned access, etc"
+ #elif self.signo = signal.SIGfoo:
+
+class AbrtExploitable(gdb.Command):
+ "Analyze a crash to determine exploitability"
+ def __init__(self):
+ super(AbrtExploitable, self).__init__(
+ "abrt-exploitable",
+ gdb.COMMAND_SUPPORT, # command class
+ gdb.COMPLETE_NONE, # completion method
+ False # => it's not a prefix command
+ )
+
+ # Called when the command is invoked from GDB
+ def invoke(self, args, from_tty):
+ si = _get_signal_and_instruction()
+ #print "w", _instruction_is_writing(self)
+ f = sys.stdout
+ min_rating = 0
+ if args:
+ args = args.split(None, 1)
+ min_rating = int(args[0])
+ if len(args) > 1:
+ f = open(args[1], 'w')
+ if not si:
+ sys.stderr.write("Can't get signal no and do exploitability analysis\n")
+ return
+ _is_exploitable(si)
+ if si.exploitable_desc:
+ if si.exploitable_rating >= min_rating:
+ f.write("Likely crash reason: " + si.exploitable_desc + "\n")
+ f.write("Exploitable rating (0-9 scale): " + str(si.exploitable_rating) + "\n")
+ else:
+ sys.stderr.write("Exploitability analysis on this crash came up empty\n")
+
+AbrtExploitable()
diff --git a/src/plugins/ccpp_event.conf b/src/plugins/ccpp_event.conf
index dfc4908..aa8cdb3 100644
--- a/src/plugins/ccpp_event.conf
+++ b/src/plugins/ccpp_event.conf
@@ -15,10 +15,13 @@ EVENT=post-create analyzer=CCpp
exit 1
fi
# Try generating backtrace, if it fails we can still use
- # the UUID generated by abrt-action-analyze-c
+ # the hash generated by abrt-action-analyze-c
##satyr migration:
#satyr abrt-create-core-stacktrace "$DUMP_DIR"
abrt-action-generate-core-backtrace
+ # Run GDB plugin to see if crash looks exploitable
+ abrt-action-analyze-vulnerability
+ # Generate hash
abrt-action-analyze-c &&
abrt-action-list-dsos -m maps -o dso_list &&
(
diff --git a/tests/abrt-exploitable/.gitignore b/tests/abrt-exploitable/.gitignore
new file mode 100644
index 0000000..b0c3b29
--- /dev/null
+++ b/tests/abrt-exploitable/.gitignore
@@ -0,0 +1,10 @@
+testDivideByZero
+testExecuteInvalid
+testFloatingPointException
+testReadNull
+testReadRandom
+testSignalAbort
+testSignalIll
+testStackBufferOverflow
+testStackRecursion
+testWriteRandom
diff --git a/tests/abrt-exploitable/Makefile b/tests/abrt-exploitable/Makefile
new file mode 100644
index 0000000..fe4078d
--- /dev/null
+++ b/tests/abrt-exploitable/Makefile
@@ -0,0 +1,67 @@
+# Copyright (C) 2010, 2011 Red Hat, Inc.
+#
+# This file is part of ABRT.
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+CFLAGS=-g
+
+TESTS=\
+ testDivideByZero\
+ testReadNull\
+ testStackRecursion\
+ testReadRandom\
+ testSignalAbort\
+ testSignalIll\
+ testWriteRandom\
+ testExecuteInvalid\
+ testStackBufferOverflow\
+ testFloatingPointException\
+
+all: $(TESTS)
+
+clean:
+ rm -f $(TESTS)
+
+testlive:
+ for t in $(TESTS); do \
+ echo "====="; \
+ echo "Test: $$t"; \
+ gdb --batch \
+ -ex 'python execfile("../../src/plugins/abrt-gdb-exploitable")' \
+ -ex 'run' \
+ -ex 'disas $$pc-16,$$pc+16' \
+ -ex 'abrt-exploitable' \
+ -ex 'cont' \
+ -ex 'quit' \
+ ./$$t; \
+ done 2>&1 | tee testlive.log
+
+testcore:
+ rm ./core* 2>/dev/null; \
+ ulimit -c unlimited; \
+ for t in $(TESTS); do \
+ echo "====="; \
+ echo "Test: $$t"; \
+ ./$$t && { echo "No crash???"; continue; }; \
+ mv core* core || { echo "No corefile???"; continue; }; \
+ gdb --batch \
+ -ex 'python execfile("../../src/plugins/abrt-gdb-exploitable")' \
+ -ex 'core ./core' \
+ -ex 'disas $$pc-16,$$pc+16' \
+ -ex 'abrt-exploitable' \
+ -ex 'quit' \
+ ; \
+ rm ./core; \
+ done 2>&1 | tee testcore.log
diff --git a/tests/abrt-exploitable/testDivideByZero.c b/tests/abrt-exploitable/testDivideByZero.c
new file mode 100644
index 0000000..06d1551
--- /dev/null
+++ b/tests/abrt-exploitable/testDivideByZero.c
@@ -0,0 +1,10 @@
+/*
+ * Test a divide by zero error
+ * This error is not exploitable
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ printf("%d\n", 7/0);
+}
diff --git a/tests/abrt-exploitable/testExecuteInvalid.c b/tests/abrt-exploitable/testExecuteInvalid.c
new file mode 100644
index 0000000..86ce515
--- /dev/null
+++ b/tests/abrt-exploitable/testExecuteInvalid.c
@@ -0,0 +1,17 @@
+/*
+ * Test a crash attempting to execute an invalid address
+ * This error is exploitable
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+int (*function_pointer)();
+
+int main(int argc, char *argv[]) {
+ char *a;
+ a = malloc(1024);
+ a = (size_t)a * 1024; // This should put us well outside the valid memory range
+ function_pointer = a;
+ function_pointer();
+}
diff --git a/tests/abrt-exploitable/testFloatingPointException.c b/tests/abrt-exploitable/testFloatingPointException.c
new file mode 100644
index 0000000..53e8762
--- /dev/null
+++ b/tests/abrt-exploitable/testFloatingPointException.c
@@ -0,0 +1,10 @@
+/*
+ * Test the illegal instruction signal
+ * This error is exploitable
+ */
+
+#include <signal.h>
+
+int main(int argc, char *argv[]) {
+ raise(SIGFPE);
+}
diff --git a/tests/abrt-exploitable/testReadNull.c b/tests/abrt-exploitable/testReadNull.c
new file mode 100644
index 0000000..548cf73
--- /dev/null
+++ b/tests/abrt-exploitable/testReadNull.c
@@ -0,0 +1,12 @@
+/*
+ * Test a NULL read
+ * This error is not exploitable
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ char *a;
+ a = 0x0;
+ puts(a);
+}
diff --git a/tests/abrt-exploitable/testReadRandom.c b/tests/abrt-exploitable/testReadRandom.c
new file mode 100644
index 0000000..8493078
--- /dev/null
+++ b/tests/abrt-exploitable/testReadRandom.c
@@ -0,0 +1,14 @@
+/*
+ * Test a crash attempting to read invalid memory
+ * This error is not exploitable
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ char *a;
+ a = malloc(1024);
+ a = (size_t)a * 1024; // This should put us well outside the valid memory range
+ printf("%s\n", a);
+}
diff --git a/tests/abrt-exploitable/testSignalAbort.c b/tests/abrt-exploitable/testSignalAbort.c
new file mode 100644
index 0000000..fc41227
--- /dev/null
+++ b/tests/abrt-exploitable/testSignalAbort.c
@@ -0,0 +1,10 @@
+/*
+ * Test the abort signal
+ * This error is not exploitable
+ */
+
+#include <signal.h>
+
+int main(int argc, char *argv[]) {
+ raise(SIGABRT);
+}
diff --git a/tests/abrt-exploitable/testSignalIll.c b/tests/abrt-exploitable/testSignalIll.c
new file mode 100644
index 0000000..7783263
--- /dev/null
+++ b/tests/abrt-exploitable/testSignalIll.c
@@ -0,0 +1,10 @@
+/*
+ * Test the illegal instruction signal
+ * This error is exploitable
+ */
+
+#include <signal.h>
+
+int main(int argc, char *argv[]) {
+ raise(SIGILL);
+}
diff --git a/tests/abrt-exploitable/testStackBufferOverflow.c b/tests/abrt-exploitable/testStackBufferOverflow.c
new file mode 100644
index 0000000..fcbd95f
--- /dev/null
+++ b/tests/abrt-exploitable/testStackBufferOverflow.c
@@ -0,0 +1,23 @@
+/*
+ * Test a stack buffer overflow
+ * This test could be exploitable (it needs further analysis)
+ */
+
+#include <stdio.h>
+
+int i;
+
+int my_function() {
+ char a[2];
+
+ for (i = 0; i < 1024; i++) {
+ a[i] = 'A';
+ }
+ printf("%s\n", a);
+}
+
+int main(int argc, char *argv[]) {
+ my_function();
+ my_function();
+ return 0;
+}
diff --git a/tests/abrt-exploitable/testStackRecursion.c b/tests/abrt-exploitable/testStackRecursion.c
new file mode 100644
index 0000000..dddf583
--- /dev/null
+++ b/tests/abrt-exploitable/testStackRecursion.c
@@ -0,0 +1,15 @@
+/*
+ * Test a crash from stack recursion
+ * This error is not exploitable
+ */
+
+#include <stdio.h>
+
+void my_function() {
+ char a[1024];
+ my_function();
+}
+
+int main(int argc, char *argv[]) {
+ my_function();
+}
diff --git a/tests/abrt-exploitable/testWriteRandom.c b/tests/abrt-exploitable/testWriteRandom.c
new file mode 100644
index 0000000..812f94c
--- /dev/null
+++ b/tests/abrt-exploitable/testWriteRandom.c
@@ -0,0 +1,15 @@
+/*
+ * Test a crash attempting to write invalid memory
+ * This error is exploitable
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[]) {
+ char *a;
+ char b[] = "pwnt";
+ a = malloc(1024);
+ a = (size_t)a * 1024; // This should put us well outside the valid memory range
+ strcpy(a, b);
+}
--
1.8.1.4
11 years
[SATYR PATCH 0/6] Type-agnostic distance computation
by Martin Milata
This patchset adds two functions, sr_distance and sr_threads_compare, which
allow you to compare two or multiple threads respectively. The threads can be
of any type supported by satyr as long as all threads are of the same type.
The python bindings are not yet updated to accept any thread type -- I'd like
to work on [0] first and then modify the python bindings in one go.
Please note that the patches depend on 'source-reorganization' branch sent
earlier and won't apply without it. The code is also available at [1].
[0] https://github.com/abrt/satyr/issues/66
[1] https://github.com/abrt/satyr/commits/gh63-agnostic-distance
Martin Milata (6):
Fix comment in thread.h
Add sr_frame_cmp and sr_frame_cmp_distance
Make thread distance type-agnostic
distance: normalize levenshtein distance
Port tests to type-agnostic distance functions
Type-agnostic distance matrices
include/Makefile.am | 1 -
include/distance.h | 121 ++++++++++----
include/frame.h | 14 ++
include/metrics.h | 219 --------------------------
include/thread.h | 7 +-
lib/Makefile.am | 1 -
lib/cluster.c | 2 +-
lib/core_frame.c | 4 +
lib/core_thread.c | 2 +-
lib/distance.c | 406 ++++++++++++++++++++++-------------------------
lib/gdb_frame.c | 8 +
lib/gdb_thread.c | 2 +-
lib/generic_frame.c | 18 +++
lib/generic_frame.h | 3 +
lib/generic_thread.h | 4 +-
lib/java_frame.c | 2 +
lib/java_thread.c | 2 +-
lib/koops_frame.c | 2 +
lib/koops_stacktrace.c | 2 +-
lib/metrics.c | 409 ------------------------------------------------
lib/python_frame.c | 2 +
lib/python_stacktrace.c | 2 +-
python/py_metrics.c | 14 +-
satyr.c | 1 -
tests/cluster.at | 3 +-
tests/metrics.at | 54 +++----
tests/normalize.at | 1 -
27 files changed, 383 insertions(+), 923 deletions(-)
delete mode 100644 include/metrics.h
delete mode 100644 lib/metrics.c
--
1.7.11.7
11 years
[SATYR PATCH 0/2] Source code reorganization
by Martin Milata
Following two patches are fairly large due to the code being moved around. It
has been also pushed to github branch 'source-reorganization' [1] for easier
review (e.g. github can show file renames in the first patch).
[1] https://github.com/abrt/satyr/commits/source-reorganization
Martin Milata (2):
Move public headers into separate directory
Move "method tables" to files where the methods are defined
Makefile.am | 4 +-
configure.ac | 1 +
include/Makefile.am | 52 +++++
include/abrt.h | 61 ++++++
include/core/fingerprint.h | 53 +++++
include/core/frame.h | 213 +++++++++++++++++++
include/core/stacktrace.h | 147 +++++++++++++
include/core/thread.h | 141 +++++++++++++
include/core/unwind.h | 38 ++++
include/deb.h | 46 +++++
include/distance.h | 122 +++++++++++
include/frame.h | 64 ++++++
include/gdb/frame.h | 468 ++++++++++++++++++++++++++++++++++++++++++
include/gdb/sharedlib.h | 134 ++++++++++++
include/gdb/stacktrace.h | 318 ++++++++++++++++++++++++++++
include/gdb/thread.h | 263 ++++++++++++++++++++++++
include/java/frame.h | 263 ++++++++++++++++++++++++
include/java/stacktrace.h | 146 +++++++++++++
include/java/thread.h | 231 +++++++++++++++++++++
include/json.h | 131 ++++++++++++
include/koops/frame.h | 233 +++++++++++++++++++++
include/koops/stacktrace.h | 176 ++++++++++++++++
include/location.h | 161 +++++++++++++++
include/metrics.h | 219 ++++++++++++++++++++
include/normalize.h | 86 ++++++++
include/operating_system.h | 60 ++++++
include/python/frame.h | 188 +++++++++++++++++
include/python/stacktrace.h | 119 +++++++++++
include/report.h | 70 +++++++
include/report_type.h | 44 ++++
include/rpm.h | 220 ++++++++++++++++++++
include/stacktrace.h | 87 ++++++++
include/strbuf.h | 159 ++++++++++++++
include/thread.h | 73 +++++++
include/utils.h | 381 ++++++++++++++++++++++++++++++++++
lib/Makefile.am | 53 +----
lib/abrt.c | 12 +-
lib/abrt.h | 61 ------
lib/core_fingerprint.c | 8 +-
lib/core_fingerprint.h | 53 -----
lib/core_frame.c | 16 +-
lib/core_frame.h | 213 -------------------
lib/core_stacktrace.c | 31 ++-
lib/core_stacktrace.h | 147 -------------
lib/core_thread.c | 21 +-
lib/core_thread.h | 141 -------------
lib/core_unwind.c | 2 +-
lib/core_unwind.h | 38 ----
lib/core_unwind_elfutils.c | 6 +-
lib/core_unwind_libunwind.c | 6 +-
lib/deb.h | 46 -----
lib/distance.c | 20 +-
lib/distance.h | 122 -----------
lib/frame.c | 90 --------
lib/frame.h | 64 ------
lib/gdb_frame.c | 16 +-
lib/gdb_frame.h | 468 ------------------------------------------
lib/gdb_sharedlib.c | 2 +-
lib/gdb_sharedlib.h | 134 ------------
lib/gdb_stacktrace.c | 33 ++-
lib/gdb_stacktrace.h | 318 ----------------------------
lib/gdb_thread.c | 24 ++-
lib/gdb_thread.h | 263 ------------------------
lib/generic_frame.c | 45 ++++
lib/generic_frame.h | 33 +++
lib/generic_stacktrace.c | 124 +++++++++++
lib/generic_stacktrace.h | 57 +++++
lib/generic_thread.c | 90 ++++++++
lib/generic_thread.h | 51 +++++
lib/internal_utils.h | 33 +++
lib/java_frame.c | 16 +-
lib/java_frame.h | 263 ------------------------
lib/java_stacktrace.c | 24 ++-
lib/java_stacktrace.h | 146 -------------
lib/java_thread.c | 21 +-
lib/java_thread.h | 231 ---------------------
lib/json.h | 131 ------------
lib/koops_frame.c | 16 +-
lib/koops_frame.h | 233 ---------------------
lib/koops_stacktrace.c | 32 ++-
lib/koops_stacktrace.h | 176 ----------------
lib/location.h | 161 ---------------
lib/metrics.c | 4 +-
lib/metrics.h | 219 --------------------
lib/normalize.c | 10 +-
lib/normalize.h | 86 --------
lib/operating_system.h | 60 ------
lib/python_frame.c | 16 +-
lib/python_frame.h | 188 -----------------
lib/python_stacktrace.c | 32 ++-
lib/python_stacktrace.h | 119 -----------
lib/report.c | 8 +-
lib/report.h | 70 -------
lib/report_type.h | 44 ----
lib/rpm.h | 220 --------------------
lib/stacktrace.c | 210 -------------------
lib/stacktrace.h | 87 --------
lib/strbuf.h | 159 --------------
lib/thread.c | 155 --------------
lib/thread.h | 73 -------
lib/utils.h | 392 -----------------------------------
python/Makefile.am | 3 +-
python/py_cluster.c | 4 +-
python/py_common.c | 2 +-
python/py_gdb_frame.c | 8 +-
python/py_gdb_sharedlib.c | 4 +-
python/py_gdb_stacktrace.c | 12 +-
python/py_gdb_thread.c | 8 +-
python/py_java_frame.c | 8 +-
python/py_java_stacktrace.c | 12 +-
python/py_java_thread.c | 10 +-
python/py_koops_frame.c | 8 +-
python/py_koops_stacktrace.c | 12 +-
python/py_metrics.c | 4 +-
python/py_module.c | 2 +-
python/py_python_frame.c | 8 +-
python/py_python_stacktrace.c | 14 +-
satyr.c | 24 +--
tests/abrt.at | 4 +-
tests/atlocal.in | 2 +-
tests/cluster.at | 8 +-
tests/core_frame.at | 14 +-
tests/core_stacktrace.at | 18 +-
tests/core_thread.at | 14 +-
tests/gdb_frame.at | 40 ++--
tests/gdb_sharedlib.at | 14 +-
tests/gdb_stacktrace.at | 42 ++--
tests/gdb_thread.at | 38 ++--
tests/java_frame.at | 34 +--
tests/java_stacktrace.at | 34 +--
tests/java_testcases.c | 8 +-
tests/java_thread.at | 50 ++---
tests/koops_frame.at | 12 +-
tests/koops_stacktrace.at | 18 +-
tests/metrics.at | 10 +-
tests/normalize.at | 18 +-
tests/operating_system.at | 4 +-
tests/rpm.at | 12 +-
tests/strbuf.at | 4 +-
tests/utils.at | 44 ++--
140 files changed, 6214 insertions(+), 5986 deletions(-)
create mode 100644 include/Makefile.am
create mode 100644 include/abrt.h
create mode 100644 include/core/fingerprint.h
create mode 100644 include/core/frame.h
create mode 100644 include/core/stacktrace.h
create mode 100644 include/core/thread.h
create mode 100644 include/core/unwind.h
create mode 100644 include/deb.h
create mode 100644 include/distance.h
create mode 100644 include/frame.h
create mode 100644 include/gdb/frame.h
create mode 100644 include/gdb/sharedlib.h
create mode 100644 include/gdb/stacktrace.h
create mode 100644 include/gdb/thread.h
create mode 100644 include/java/frame.h
create mode 100644 include/java/stacktrace.h
create mode 100644 include/java/thread.h
create mode 100644 include/json.h
create mode 100644 include/koops/frame.h
create mode 100644 include/koops/stacktrace.h
create mode 100644 include/location.h
create mode 100644 include/metrics.h
create mode 100644 include/normalize.h
create mode 100644 include/operating_system.h
create mode 100644 include/python/frame.h
create mode 100644 include/python/stacktrace.h
create mode 100644 include/report.h
create mode 100644 include/report_type.h
create mode 100644 include/rpm.h
create mode 100644 include/stacktrace.h
create mode 100644 include/strbuf.h
create mode 100644 include/thread.h
create mode 100644 include/utils.h
delete mode 100644 lib/abrt.h
delete mode 100644 lib/core_fingerprint.h
delete mode 100644 lib/core_frame.h
delete mode 100644 lib/core_stacktrace.h
delete mode 100644 lib/core_thread.h
delete mode 100644 lib/core_unwind.h
delete mode 100644 lib/deb.h
delete mode 100644 lib/distance.h
delete mode 100644 lib/frame.c
delete mode 100644 lib/frame.h
delete mode 100644 lib/gdb_frame.h
delete mode 100644 lib/gdb_sharedlib.h
delete mode 100644 lib/gdb_stacktrace.h
delete mode 100644 lib/gdb_thread.h
create mode 100644 lib/generic_frame.c
create mode 100644 lib/generic_frame.h
create mode 100644 lib/generic_stacktrace.c
create mode 100644 lib/generic_stacktrace.h
create mode 100644 lib/generic_thread.c
create mode 100644 lib/generic_thread.h
create mode 100644 lib/internal_utils.h
delete mode 100644 lib/java_frame.h
delete mode 100644 lib/java_stacktrace.h
delete mode 100644 lib/java_thread.h
delete mode 100644 lib/json.h
delete mode 100644 lib/koops_frame.h
delete mode 100644 lib/koops_stacktrace.h
delete mode 100644 lib/location.h
delete mode 100644 lib/metrics.h
delete mode 100644 lib/normalize.h
delete mode 100644 lib/operating_system.h
delete mode 100644 lib/python_frame.h
delete mode 100644 lib/python_stacktrace.h
delete mode 100644 lib/report.h
delete mode 100644 lib/report_type.h
delete mode 100644 lib/rpm.h
delete mode 100644 lib/stacktrace.c
delete mode 100644 lib/stacktrace.h
delete mode 100644 lib/strbuf.h
delete mode 100644 lib/thread.c
delete mode 100644 lib/thread.h
delete mode 100644 lib/utils.h
--
1.7.11.7
11 years
[RHEL^ ABRT PATCH] abrt-dump-oops: limit amount of created dirs, add cooldown sleep if exceeded. rhbz#952773
by Denys Vlasenko
This is a partial backport of 6fc121f145354dd95bb588eb685f1593f5156ca0.
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
src/plugins/abrt-dump-oops.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c
index 85ca2c0..0dbe7fe 100644
--- a/src/plugins/abrt-dump-oops.c
+++ b/src/plugins/abrt-dump-oops.c
@@ -21,6 +21,11 @@
#include <sys/inotify.h>
#include "libabrt.h"
+/* How many problem dirs to create at most?
+ * Also causes cooldown sleep if exceeded -
+ * useful when called from a log watcher.
+ */
+#define MAX_DUMPED_DD_COUNT 5
static bool world_readable_dump = false;
static const char *debug_dumps_dir = ".";
@@ -110,8 +115,8 @@ static int scan_syslog_file(GList **oops_list, int fd, struct stat *statbuf, int
/* returns number of errors */
static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
{
- unsigned countdown = 16; /* do not report hundreds of oopses */
- unsigned idx = 0; //oops_cnt;
+ unsigned countdown = MAX_DUMPED_DD_COUNT + 1; /* do not report hundreds of oopses */
+ unsigned idx = 0;
VERB1 log("Saving %u oopses as dump dirs", oops_cnt >= countdown ? countdown-1 : oops_cnt);
@@ -207,6 +212,14 @@ static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
free(cmdline_str);
+ /* This delays log rescan
+ * and possibly prevents dreaded "abrt storm".
+ */
+ if (oops_cnt > MAX_DUMPED_DD_COUNT)
+ {
+ sleep(oops_cnt - MAX_DUMPED_DD_COUNT);
+ }
+
return errors;
}
--
1.8.1.4
11 years
[ABRT PATCH] spec: require tar closes #635
by Jiri Moskovcak
Signed-off-by: Jiri Moskovcak <jmoskovc(a)redhat.com>
---
abrt.spec.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/abrt.spec.in b/abrt.spec.in
index c0f8452..5dd8eb6 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -142,6 +142,7 @@ Summary: %{name}'s retrace client
Group: System Environment/Libraries
Requires: %{name} = %{version}-%{release}
Requires: xz
+Requires: tar
%description retrace-client
This package contains the client application for Retrace server
--
1.8.2.1
11 years
[ABRT PATCH] spec: tui should require abrt closes #633
by Jiri Moskovcak
Signed-off-by: Jiri Moskovcak <jmoskovc(a)redhat.com>
---
abrt.spec.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/abrt.spec.in b/abrt.spec.in
index fec5b56..c0f8452 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -219,6 +219,7 @@ uncaught exception in python programs.
%package tui
Summary: %{name}'s command line interface
Group: User Interface/Desktops
+Requires: %{name} = %{version}-%{release}
Requires: libreport-cli
Requires: abrt-libs = %{version}-%{release}
--
1.8.2.1
11 years
[RHEL6 LIBREPORT PATCH] Fix bugs discoverent by Coverity. rhbz#905051
by Denys Vlasenko
This is a partial backport of 93c6e6f9298928dcb140797d9fe8ff9038790423.
Most bugs are either outright bogus (rhbz_array_size is never <0)
or won't happen in practice (fstat won't fail on a file we just created
ourselves). Nevertheless, one bug is real:
if (flags & LIBREPORT_NOWAIT)...
is WRONG, because LIBREPORT_NOWAIT constant is in fact 0!
We must check for that bit this way:
if (!(flags & LIBREPORT_WAIT))...
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
src/cli/cli-report.c | 9 ++++-----
src/gui-wizard-gtk/wizard.c | 18 ++++++++++--------
src/lib/dump_dir.c | 14 ++++++++++++--
src/lib/report.c | 2 +-
src/plugins/reporter-bugzilla.c | 4 ++--
src/plugins/rhbz.c | 12 ++++++------
src/plugins/rhbz.h | 2 +-
7 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
index 1e13a38..0e36150 100644
--- a/src/cli/cli-report.c
+++ b/src/cli/cli-report.c
@@ -333,11 +333,10 @@ static int run_report_editor(problem_data_t *problem_data)
return 2;
}
- fseek(fp, 0, SEEK_END);
- unsigned long size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- char *text = (char*)xmalloc(size + 1);
+ off_t size = fstat_st_size_or_die(fileno(fp));
+ if (size > INT_MAX/4)
+ size = INT_MAX/4; /* paranoia */
+ char *text = xmalloc(size + 1);
if (fread(text, 1, size, fp) != size)
{
error_msg("Can't read '%s'", filename);
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 57365bd..4820546 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -1092,14 +1092,16 @@ static void append_item_to_ls_details(gpointer name, gpointer value, gpointer da
{
struct stat statbuf;
statbuf.st_size = 0;
- stat(item->content, &statbuf);
- stats->filesize += statbuf.st_size;
- char *msg = xasprintf(_("(binary file, %llu bytes)"), (long long)statbuf.st_size);
- gtk_list_store_set(g_ls_details, &iter,
- DETAIL_COLUMN_NAME, (char *)name,
- DETAIL_COLUMN_VALUE, msg,
- -1);
- free(msg);
+ if (stat(item->content, &statbuf) == 0)
+ {
+ stats->filesize += statbuf.st_size;
+ char *msg = xasprintf(_("(binary file, %llu bytes)"), (long long)statbuf.st_size);
+ gtk_list_store_set(g_ls_details, &iter,
+ DETAIL_COLUMN_NAME, (char *)name,
+ DETAIL_COLUMN_VALUE, msg,
+ -1);
+ free(msg);
+ }
}
int cur_value;
diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c
index f2e7376..e1af555 100644
--- a/src/lib/dump_dir.c
+++ b/src/lib/dump_dir.c
@@ -287,7 +287,8 @@ struct dump_dir *dd_opendir(const char *dir, int flags)
dir = dd->dd_dirname = rm_trailing_slashes(dir);
struct stat stat_buf;
- stat(dir, &stat_buf);
+ if (stat(dir, &stat_buf) != 0)
+ goto cant_access;
/* & 0666 should remove the executable bit */
dd->mode = (stat_buf.st_mode & 0666);
@@ -331,7 +332,10 @@ struct dump_dir *dd_opendir(const char *dir, int flags)
else
{
if (!(flags & DD_FAIL_QUIETLY_EACCES))
+ {
+ cant_access:
perror_msg("Can't access '%s'", dir);
+ }
}
dd_close(dd);
return NULL;
@@ -549,7 +553,13 @@ void dd_sanitize_mode_and_owner(struct dump_dir *dd)
if (lstat(full_path, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
{
if ((statbuf.st_mode & 0777) != dd->mode)
- chmod(full_path, dd->mode);
+ {
+ if (chmod(full_path, dd->mode) != 0)
+ {
+ perror_msg("Can't change '%s' mode to 0%o", full_path,
+ (unsigned)dd->mode);
+ }
+ }
if (statbuf.st_uid != dd->dd_uid || statbuf.st_gid != dd->dd_gid)
{
if (lchown(full_path, dd->dd_uid, dd->dd_gid) != 0)
diff --git a/src/lib/report.c b/src/lib/report.c
index 9e1d601..7b7deab 100644
--- a/src/lib/report.c
+++ b/src/lib/report.c
@@ -175,7 +175,7 @@ int report_problem_in_memory(problem_data_t *pd, int flags)
dd_close(dd);
VERB2 log("Temp problem dir: '%s'", dir_name);
- if (flags & LIBREPORT_NOWAIT)
+ if (!(flags & LIBREPORT_WAIT))
flags |= LIBREPORT_DEL_DIR;
result = report_problem_in_dir(dir_name, flags);
diff --git a/src/plugins/reporter-bugzilla.c b/src/plugins/reporter-bugzilla.c
index 7bde348..9374505 100644
--- a/src/plugins/reporter-bugzilla.c
+++ b/src/plugins/reporter-bugzilla.c
@@ -165,7 +165,7 @@ int main(int argc, char **argv)
xmlrpc_value *all_bugs = rhbz_get_member("bugs", result);
xmlrpc_DECREF(result);
- int all_bugs_size = rhbz_array_size(all_bugs);
+ unsigned all_bugs_size = rhbz_array_size(all_bugs);
if (all_bugs_size > 0)
{
int bug_id = rhbz_bug_id(all_bugs);
@@ -302,7 +302,7 @@ int main(int argc, char **argv)
if (!all_bugs)
error_msg_and_die(_("Missing mandatory member 'bugs'"));
- int all_bugs_size = rhbz_array_size(all_bugs);
+ unsigned all_bugs_size = rhbz_array_size(all_bugs);
// When someone clones bug it has same duphash, so we can find more than 1.
// Need to be checked if component is same.
VERB3 log("Bugzilla has %i reports with same duphash '%s'",
diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c
index 359c15a..300c5c8 100644
--- a/src/plugins/rhbz.c
+++ b/src/plugins/rhbz.c
@@ -154,11 +154,11 @@ static GList *parse_comments(xmlrpc_value *result_xml)
if (!comments_memb)
return NULL;
- int comments_memb_size = rhbz_array_size(comments_memb);
+ unsigned comments_memb_size = rhbz_array_size(comments_memb);
xmlrpc_env env;
xmlrpc_env_init(&env);
- for (int i = 0; i < comments_memb_size; ++i)
+ for (unsigned i = 0; i < comments_memb_size; ++i)
{
xmlrpc_value* item = NULL;
xmlrpc_array_read_item(&env, comments_memb, i, &item);
@@ -312,14 +312,14 @@ xmlrpc_value *rhbz_get_member(const char *member, xmlrpc_value *xml)
* value. So it is usually not worth checking *envP.
* die or return size of array
*/
-int rhbz_array_size(xmlrpc_value *xml)
+unsigned rhbz_array_size(xmlrpc_value *xml)
{
func_entry();
xmlrpc_env env;
xmlrpc_env_init(&env);
- int size = xmlrpc_array_size(&env, xml);
+ unsigned size = xmlrpc_array_size(&env, xml);
if (env.fault_occurred)
abrt_xmlrpc_die(&env);
@@ -419,12 +419,12 @@ GList *rhbz_bug_cc(xmlrpc_value* result_xml)
if (!cc_member)
return NULL;
- int array_size = rhbz_array_size(cc_member);
+ unsigned array_size = rhbz_array_size(cc_member);
VERB3 log("count members on cc %i", array_size);
GList *cc_list = NULL;
- for (int i = 0; i < array_size; ++i)
+ for (unsigned i = 0; i < array_size; ++i)
{
xmlrpc_value* item = NULL;
xmlrpc_array_read_item(&env, cc_member, i, &item);
diff --git a/src/plugins/rhbz.h b/src/plugins/rhbz.h
index 10c37bc..585b23e 100644
--- a/src/plugins/rhbz.h
+++ b/src/plugins/rhbz.h
@@ -93,7 +93,7 @@ xmlrpc_value *rhbz_search_duphash(struct abrt_xmlrpc *ax, const char *component,
xmlrpc_value *rhbz_get_member(const char *member, xmlrpc_value *xml);
-int rhbz_array_size(xmlrpc_value *xml);
+unsigned rhbz_array_size(xmlrpc_value *xml);
int rhbz_bug_id(xmlrpc_value *xml);
--
1.8.1.4
11 years
[RFC: ABRT PATCH] Add gdb python plugin which analyzes vulnerability
by Denys Vlasenko
This is an RFC, please do not commit.
Usage:
Run abrt-action-analyze-vulnerability in a directory which contains
./coredump file.
If crash looks exploitable, the tool creates ./exploitable file.
Example such a file:
"""
Program tried to write to an invalid address
Exploitable rating (1-10 scale):
6
"""
This patch adds abrt-action-analyze-vulnerability invocation to
"EVENT=post-create analyzer=CCpp".
TODO:
* decide what to do if we _dont_ see particularly suspicious stuff -
do nothing? Or still create a file?
* improve error detection (e.g. what to do if gdb failed to run?)
* suppress stray gdb output
* set $SIGNO_OF_THE_COREDUMP to work around non-working $_siginfo.si_signo
* decide whether to push for $_signo support in gdb (I have a tested gdb patch)
* instruction analyzer is x86 specific now, make it per-arch
(how to get arch name???)
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
abrt.spec.in | 2 +
src/plugins/Makefile.am | 10 +-
src/plugins/abrt-action-analyze-vulnerability | 9 +
src/plugins/abrt-gdb-exploitable | 268 ++++++++++++++++++++++++++
src/plugins/ccpp_event.conf | 5 +-
5 files changed, 291 insertions(+), 3 deletions(-)
create mode 100755 src/plugins/abrt-action-analyze-vulnerability
create mode 100755 src/plugins/abrt-gdb-exploitable
diff --git a/abrt.spec.in b/abrt.spec.in
index fec5b56..ce5f944 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -670,6 +670,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_initrddir}/abrt-ccpp
%endif
%{_libexecdir}/abrt-hook-ccpp
+%{_libexecdir}/abrt-gdb-exploitable
# attr(6755) ~= SETUID|SETGID
%attr(6755, abrt, abrt) %{_libexecdir}/abrt-action-install-debuginfo-to-abrt-cache
@@ -677,6 +678,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_bindir}/abrt-action-analyze-c
%{_bindir}/abrt-action-trim-files
%{_bindir}/abrt-action-analyze-core
+%{_bindir}/abrt-action-analyze-vulnerability
%{_bindir}/abrt-action-install-debuginfo
%{_bindir}/abrt-action-generate-backtrace
%{_bindir}/abrt-action-generate-core-backtrace
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 767c045..20e0297 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -3,6 +3,7 @@
bin_SCRIPTS = \
abrt-action-install-debuginfo \
abrt-action-analyze-core \
+ abrt-action-analyze-vulnerability \
abrt-action-analyze-vmcore \
abrt-action-list-dsos \
abrt-action-perform-ccpp-analysis \
@@ -29,9 +30,12 @@ bin_PROGRAMS += \
abrt-bodhi
endif
-libexec_PROGRAMS = abrt-action-install-debuginfo-to-abrt-cache
+libexec_PROGRAMS = \
+ abrt-action-install-debuginfo-to-abrt-cache
-libexec_SCRIPTS = abrt-action-ureport
+libexec_SCRIPTS = \
+ abrt-action-ureport \
+ abrt-gdb-exploitable
#dist_pluginsconf_DATA = Python.conf
@@ -68,6 +72,7 @@ PYTHON_FILES = \
abrt-action-install-debuginfo.in \
abrt-action-list-dsos \
abrt-action-analyze-core \
+ abrt-action-analyze-vulnerability \
abrt-action-analyze-vmcore.in \
abrt-action-perform-ccpp-analysis.in
@@ -84,6 +89,7 @@ EXTRA_DIST = \
abrt-action-analyze-vmcore \
abrt-action-save-kernel-data \
abrt-action-ureport \
+ abrt-gdb-exploitable \
https-utils.h \
post_report.xml.in \
abrt-action-analyze-ccpp-local
diff --git a/src/plugins/abrt-action-analyze-vulnerability b/src/plugins/abrt-action-analyze-vulnerability
new file mode 100755
index 0000000..47d2ce4
--- /dev/null
+++ b/src/plugins/abrt-action-analyze-vulnerability
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if type gdb >/dev/null 2>&1; then
+ # gdb is avaliable
+ gdb --batch \
+ -ex 'python execfile("/usr/libexec/abrt-gdb-exploitable")' \
+ -ex 'core-file ./coredump' \
+ -ex 'abrt-exploitable ./exploitable'
+fi
diff --git a/src/plugins/abrt-gdb-exploitable b/src/plugins/abrt-gdb-exploitable
new file mode 100755
index 0000000..116d9db
--- /dev/null
+++ b/src/plugins/abrt-gdb-exploitable
@@ -0,0 +1,268 @@
+#!/usr/bin/python
+# This is a GDB plugin.
+# Usage:
+# gdb --batch -ex "source THIS_FILE" -ex run -ex abrt-exploitable PROG
+# or
+# gdb --batch -ex "source THIS_FILE" -ex "core COREDUMP" -ex abrt-exploitable
+
+import gdb
+import os
+import signal
+
+_writing_instr = {
+ # "insn:which operand to check for mem ref"
+ "add":2,
+ "adc":2,
+ "sub":2,
+ "sbb":2,
+ "and":2,
+ "xor":2,
+ "or":2,
+ "inc":1,
+ "dec":1,
+ "neg":1,
+ "not":1,
+ # sarl $2,(%rcx), BUT:
+ # FIXME: shifts by 1 have one operand!!!- sarb (%rax)
+ "shl":2,
+ "shr":2,
+ "sal":2,
+ "sar":2,
+ "rol":2,
+ "ror":2,
+ "rcl":2,
+ "rcr":2,
+ # shld $0xc6,%ecx,(%rdi)
+ #"shld":3,
+ #"shrd":3,
+ "bts":1,
+ "btr":1,
+ "btc":1,
+ "pop":1,
+
+ "xchg":-2, # either mem operand indicates write to mem
+
+ # FIXME: aliased to widening move "movs[bwl][wlq]" which never stores to mem
+ "movs":-1, # don't check operands, this insn always writes to mem
+ "stos":-1,
+ # these always write to stack:
+ #"push":-1,
+ #"pusha":-1,
+ #"pushf":-1,
+ #"enter":-1,
+
+ "cmpxchg":2,
+ "xadd":2,
+ # with binutils-like disasm, implicit register operands aren't shown
+ "cmpxchg8b":1,
+ "cmpxchg16b":1,
+
+ #"f[x]save":1,
+
+ # check binutils/gas/testsuite/gas/i386/* for more weird insns
+
+ "mov":2
+}
+
+_jumping_instr = {
+ "jmp":-1, # indirect jumps/calls with garbage data
+ "call":-1, # call: also possible that stack is exhausted (infinite recursion)
+ #"push":-1, ?
+ #"pusha":-1,
+ #"enter":-1,
+
+ "ret":-1 # stack smashed
+}
+
+#Our initial set of testing will use the list Apple included in their
+#CrashWrangler announcement:
+#
+#Exploitable if:
+# Crash on write instruction
+#* Crash executing invalid address
+#* Crash calling an invalid address
+# Crash accessing an uninitialized or freed pointer as indicated by
+# using the MallocScribble environment variable
+#* Illegal instruction exception
+# Abort due to -fstack-protector, _FORTIFY_SOURCE, heap corruption
+# detected
+# Stack trace of crashing thread contains certain functions such as
+# malloc, free, szone_error, objc_MsgSend, etc.
+
+def _get_signal_and_instruction(self):
+ self.signo = None
+ try:
+ sig = gdb.parse_and_eval("$_signo") # ("$_siginfo.si_signo")
+ # type(sig) = <type 'gdb.Value'>
+ # sig is 8 (for SIGFPE)
+ self.signo = int(sig)
+ except gdb.error:
+ # Python Exception <class 'gdb.error'> Attempt to extract a component of a value that is not a structure.:
+ # Possible reasons why $_siginfo doesn't exist:
+ # program is still running, program exited normally,
+ # we work with a coredump from an old kernel.
+ #
+ # HACK_ALERT: kernels before 3.?.? do not record siginfo in coredumps,
+ # so $_siginfo isn't present.
+ # Lets see whether we are running from the abrt and it provided us with signal number
+ #
+ try:
+ self.signo = int(os.environ["SIGNO_OF_THE_COREDUMP"])
+ except KeyError:
+ return False
+
+ self.current_instruction = None
+ self.mnemonic = None
+ self.operands = ""
+ try:
+ # just "disassemble $pc" won't work if $pc doesn't point
+ # inside a known function
+ instructions = gdb.execute("disassemble $pc,$pc+32", to_string=True)
+ # type(instructions) = <type 'str'>
+ except gdb.error:
+ # For example, if tracee already exited normally:
+ # Python Exception <class 'gdb.error'> No registers.:
+ return False
+
+ raw_instructions = instructions
+ #print instructions
+ instructions = []
+ current = None
+ for line in raw_instructions.split("\n"):
+ # line can be:
+ # "Dump of assembler code from 0xAAAA to 0xBBBB:"
+ # "[=>] 0x00000000004004dc[ <+0>]: push %rbp"
+ # (" <+0>" part is present when we run on a live process,
+ # on coredump it is absent)
+ # "End of assembler dump."
+ # "" (empty line)
+ if line.startswith("=>"):
+ line = line[2:]
+ current = len(instructions)
+ line = line.split(":", 1)
+ if len(line) < 2: # no ":"?
+ continue
+ line = line[1] # drop "foo:"
+ line = line.strip() # drop leading/trailing whitespace
+ if line:
+ instructions.append(line)
+ if current == None:
+ # not False! we determined that $pc points to a bad address,
+ # which is an interesting fact.
+ return True
+
+ self.current_instruction = instructions[current]
+ # TODO: too simplistic.
+ # consider this example:
+ # "data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)"
+ t = self.current_instruction.split(None,2)
+ self.mnemonic = t[0]
+ if len(t) > 1:
+ self.operands = t[1]
+ return True
+
+def _fetch_insn_from_table(ins, table):
+ if not ins:
+ return None
+ if ins in table.keys():
+ return table[ins]
+ # Drop common byte/word/long/quad suffix and try again
+ if ins[-1] in ("b", "w", "l", "q"):
+ ins = ins[:-1]
+ if ins in table.keys():
+ return table[ins]
+ return None
+
+def _instruction_is_writing(self):
+ operand = _fetch_insn_from_table(self.mnemonic, _writing_instr)
+ if not operand:
+ if not self.mnemonic:
+ return False
+ # There are far too many SSE store instructions,
+ # don't want to pollute the table with them.
+ # Special-case the check for MOVxxx
+ # and its SIMD cousins VMOVxxx:
+ if self.mnemonic[:3] != "mov" and self.mnemonic[:4] != "vmov":
+ return False
+ operand = 2
+
+ if operand == -1: # no need to check operands, it's a write
+ return 1
+
+ paren = self.operands.find("(")
+ if paren < 0:
+ return False # no memory operands
+
+ if operand == -2: # any mem operand indicates write
+ return 1
+
+ comma = self.operands.find(",")
+ if paren < comma:
+ # "%cs:0x0(%rax,%rax,1),foo" - 1st operand is memory
+ # "%cs:0x0(%rax),foo" - 1st operand is memory
+ memory_operand = 1
+ elif comma < 0:
+ # "%cs:0x0(%rax)" - 1st operand is memory
+ memory_operand = 1
+ else:
+ # paren is after comma
+ # "foo,%cs:0x0(%rax,%rax,1)" - 2nd operand is memory
+ # (It also can be a third, fourth etc operand)
+ memory_operand = 2
+
+ if operand != memory_operand:
+ return False
+ return True
+
+def _instruction_is_jump(self):
+ if _fetch_insn_from_table(self.mnemonic, _jumping_instr):
+ return True
+ return False
+
+
+def _is_exploitable(self):
+ self.exploitable_rating = 3
+ self.exploitable_desc = ""
+ if 0:
+ pass
+ elif self.signo == signal.SIGFPE:
+ self.exploitable_rating = 1
+ self.exploitable_desc = "Arithmetic exceptions (such as division by zero) are rarely exploitable"
+ # TODO? look at instruction, if it is a division, lower rating to 0?
+ # Or at least give a better desc ("Division by zero" and "(Other) arithmetic exception" is more informative)
+ elif self.signo == signal.SIGILL:
+ self.exploitable_rating = 5
+ self.exploitable_desc = "SIGILL may be an indication that program jumped to a random address"
+ elif not self.current_instruction: # TODO: and SIGSEGV?
+ self.exploitable_rating = 6
+ self.exploitable_desc = "Program jumped to an invalid address"
+ elif _instruction_is_writing(self):
+ self.exploitable_rating = 6
+ self.exploitable_desc = "Program tried to write to an invalid address"
+ #elif self.signo = signal.SIGfoo:
+
+
+class AbrtExploitable(gdb.Command):
+ "Analyze a crash to determine exploitability"
+ def __init__(self):
+ super(AbrtExploitable, self).__init__(
+ "abrt-exploitable",
+ gdb.COMMAND_SUPPORT, # command class
+ gdb.COMPLETE_NONE, # completion method
+ False # => it's not a prefix command
+ )
+
+ # Called when the command is invoked from GDB
+ def invoke(self, arg, from_tty):
+ if not _get_signal_and_instruction(self):
+ return
+ #print "w", _instruction_is_writing(self)
+ _is_exploitable(self)
+ if self.exploitable_desc and self.exploitable_rating > 3:
+ f = sys.stdout
+ if arg:
+ f = open(arg, 'w')
+ f.write(self.exploitable_desc + "\n")
+ f.write("Exploitable rating (1-10 scale):\n" + str(self.exploitable_rating) + "\n")
+
+AbrtExploitable()
diff --git a/src/plugins/ccpp_event.conf b/src/plugins/ccpp_event.conf
index dfc4908..aa8cdb3 100644
--- a/src/plugins/ccpp_event.conf
+++ b/src/plugins/ccpp_event.conf
@@ -15,10 +15,13 @@ EVENT=post-create analyzer=CCpp
exit 1
fi
# Try generating backtrace, if it fails we can still use
- # the UUID generated by abrt-action-analyze-c
+ # the hash generated by abrt-action-analyze-c
##satyr migration:
#satyr abrt-create-core-stacktrace "$DUMP_DIR"
abrt-action-generate-core-backtrace
+ # Run GDB plugin to see if crash looks exploitable
+ abrt-action-analyze-vulnerability
+ # Generate hash
abrt-action-analyze-c &&
abrt-action-list-dsos -m maps -o dso_list &&
(
--
1.8.1.4
11 years