From 951fcd8e9289b285bf4a2e3f2a0cc2cc49620cd7 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Thu, 22 Oct 2009 13:45:41 +0200 Subject: Initial implementation of abrt-pyhook-helper --- .gitignore | 1 + src/Hooks/Makefile.am | 18 ++++- src/Hooks/abrt-pyhook-helper.cpp | 138 +++++++++++++++++++++++++++++++++ src/Hooks/abrt_exception_handler.py.in | 53 ++++--------- src/Hooks/sitecustomize.py | 12 ++- 5 files changed, 179 insertions(+), 43 deletions(-) create mode 100644 src/Hooks/abrt-pyhook-helper.cpp diff --git a/.gitignore b/.gitignore index f92001af..ce402b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ src/Daemon/abrtd src/Hooks/abrt_exception_handler.py src/Hooks/dumpoops src/Hooks/hookCCpp +src/Hooks/abrt-pyhook-helper stamp-h1 diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index be1b1a2f..4eb25e2d 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -1,5 +1,5 @@ libexec_PROGRAMS = hookCCpp -bin_PROGRAMS = dumpoops +bin_PROGRAMS = dumpoops abrt-pyhook-helper # CCpp hookCCpp_SOURCES = \ @@ -29,6 +29,18 @@ dumpoops_CPPFLAGS = \ dumpoops_LDADD = \ ../../lib/Utils/libABRTUtils.la +# abrt-pyhook-helper +abrt_pyhook_helper_SOURCES = \ + abrt-pyhook-helper.cpp +abrt_pyhook_helper_CPPFLAGS = \ + -I$(srcdir)/../../inc \ + -I$(srcdir)/../../lib/Utils \ + -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ + -DVAR_RUN=\"$(VAR_RUN)\" \ + -D_GNU_SOURCE +abrt_pyhook_helper_LDADD = \ + ../../lib/Utils/libABRTUtils.la + man_MANS = pyhook.conf.5 python_PYTHON = sitecustomize.py abrt_exception_handler.py @@ -45,3 +57,7 @@ abrt_exception_handler.py: # RPM fix: we need to regenerate abrt_exception_handler.py, because it has the default ddir install-data-local: sed s,@DEBUG_DUMP_DIR@,$(DEBUG_DUMPS_DIR),g abrt_exception_handler.py.in > abrt_exception_handler.py + +install-data-hook: + chmod u+s,g+s $(DESTDIR)$(bindir)/abrt-pyhook-helper + diff --git a/src/Hooks/abrt-pyhook-helper.cpp b/src/Hooks/abrt-pyhook-helper.cpp new file mode 100644 index 00000000..4ac6ada6 --- /dev/null +++ b/src/Hooks/abrt-pyhook-helper.cpp @@ -0,0 +1,138 @@ +/* + python-hook-writer.cpp - writes data to the /var/cache/abrt directory + with SUID bit + + Copyright (C) 2009 RedHat inc. + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include "DebugDump.h" +#if HAVE_CONFIG_H +#include +#endif + +const char *argp_program_version = "abrt-pyhook-helper " VERSION; +const char *argp_program_bug_address = ""; + +static char doc[] = "abrt-pyhook-helper -- stores crash data to abrt shared directory"; + +static struct argp_option options[] = { + {"pid" , 'p', "PID" , 0, "PID of process that caused the crash" }, + {"executable", 'e', "PATH" , 0, "absolute path to the program that crashed" }, + {"uuid" , 'u', "UUID" , 0, "hash generated from the backtrace"}, + {"cmdline" , 'c', "TEXT" , 0, "command line of the crashed program"}, + {"loginuid" , 'l', "UID" , 0, "login UID"}, + { 0 } +}; + +struct arguments +{ + char *pid; + char *executable; + char *uuid; + char *cmdline; + char *loginuid; +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = (struct arguments*)state->input; + + switch (key) + { + case 'p': arguments->pid = arg; break; + case 'e': arguments->executable = arg; break; + case 'u': arguments->uuid = arg; break; + case 'c': arguments->cmdline = arg; break; + case 'l': arguments->loginuid = arg; break; + + case ARGP_KEY_ARG: + argp_usage(state); + exit(1); + break; + + case ARGP_KEY_END: + if (!arguments->pid) + { + argp_usage(state); + exit(1); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +/* Our argp parser. */ +static struct argp argp = { options, parse_opt, 0, doc }; + +int main(int argc, char** argv) +{ + struct arguments arguments; + argp_parse (&argp, argc, argv, 0, 0, &arguments); + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/pyhook-%ld-%s", DEBUG_DUMPS_DIR, + (long)time(NULL), arguments.pid); + + CDebugDump dd; + dd.Create(path, geteuid()); + dd.SaveText(FILENAME_ANALYZER, "Python"); + if (arguments.executable) + dd.SaveText(FILENAME_EXECUTABLE, arguments.executable); + if (arguments.cmdline) + dd.SaveText("cmdline", arguments.cmdline); + if (arguments.uuid) + dd.SaveText("uuid", arguments.uuid); + if (arguments.loginuid) + dd.SaveText("uid", arguments.loginuid); + + // Read the backtrace from stdin. + int c; + int capacity = 1024; + char *bt = (char*)malloc(capacity); + char *btptr = bt; + while ((c = getchar()) != EOF) + { + if (c >= 0 && c <= 255) + *btptr++ = (char)c; + if (btptr - bt >= capacity - 1) + { + capacity *= 2; + bt = (char*)realloc(bt, capacity); + if (!bt) + { + printf("Error while allocating memory for backtrace."); + return 1; + } + } + } + *btptr = '\0'; + + dd.SaveText("backtrace", bt); + free(bt); + dd.Close(); + + return 0; +} diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in index 8ac7aa23..362aaf24 100644 --- a/src/Hooks/abrt_exception_handler.py.in +++ b/src/Hooks/abrt_exception_handler.py.in @@ -45,10 +45,10 @@ def exception_function(): import sys import os import syslog +import subprocess # abrt lib for saving debugdumps import ABRTUtils - __DUMPHASH = {} # FIXME: do length limits on obj dumps. def __dump_class(instance, fd, level=0): @@ -105,45 +105,20 @@ def __dump_class(instance, fd, level=0): fd.write("%s%s: %s\n" % (pad, key, value)) def write_dump(pid, tb_uuid, tb): - import time - ttime = int(time.time()) - # localstatedir - dir_name = "@DEBUG_DUMP_DIR@/pyhook-%s-%s" % (ttime, pid) - dd = ABRTUtils.CDebugDump() - try: - #os.mkdir(dir_name) - dd.Create(dir_name, os.getuid()) - except Exception, e: - syslog.syslog("abrt: Cannot create dir %s %s" % (dir_name, e)) - return - # save executable - fexecutable = open("%s/executable" % dir_name, "w") + executable = "Exception raised from python shell" if sys.argv[0]: - fexecutable.write(os.path.abspath(sys.argv[0])) - else: - fexecutable.write("Exception raised from python shell") - fexecutable.close() - # save coredump - coredump = open("%s/backtrace" % dir_name, "w") - coredump.write(tb) - coredump.close() - # save uuid - uuid = open("%s/uuid" % dir_name, "w") - uuid.write(tb_uuid) - uuid.close() - # save cmdline - cmdline = open("%s/cmdline" % dir_name, "w") - cmdline.write(open("/proc/%s/cmdline" % pid).read().replace('\x00',' ')) - cmdline.close() - # save uid - uid = open("%s/uid" % dir_name, "w") - uid.write(open("/proc/%s/loginuid" % pid).readlines()[0]) - uid.close() - # save analyzer - analyzer = open("%s/analyzer" % dir_name, "w") - analyzer.write("Python") - analyzer.close() - dd.Close() + executable = os.path.abspath(sys.argv[0]) + + command = ["abrt-pyhook-helper"] + command.append("--pid=%s" % pid) + command.append("--executable=%s" % executable) + command.append("--uuid=%s" % tb_uuid) + command.append("--cmdline=%s" % open("/proc/%s/cmdline" % pid).read().replace('\x00',' ')) + command.append("--loginuid=%s" % open("/proc/%s/loginuid" % pid).readlines()[0]) + + helper = subprocess.Popen(command, stdin=subprocess.PIPE) + helper.communicate(tb) + helper.wait() def __dump_exception(out, text, tracebk): 'write a traceback to "out"' diff --git a/src/Hooks/sitecustomize.py b/src/Hooks/sitecustomize.py index 56c6669b..32a3747b 100644 --- a/src/Hooks/sitecustomize.py +++ b/src/Hooks/sitecustomize.py @@ -1,14 +1,16 @@ +# ABRT crash hook +# # This special script is placed in # /usr/local/lib/pythonNNN/site-packages/sitecustomize.py # and python interpreter runs it automatically everytime -# some python script is executed +# some python script is executed. config = None conf = {} try: config = open("/etc/abrt/pyhook.conf","r") except: - #silently ignore if file doesn't exist + # Silently ignore if file doesn't exist. pass try: @@ -20,10 +22,14 @@ try: line = config.readline().lower().replace(' ','').strip('\n').split('=') conf[line[0]] = line[1] except: - # ignore silently everything, because we don't want to bother user if this hook doesn't work + # Ignore silently everything, because we don't want to bother user + # if this hook doesn't work. pass if conf.has_key("enabled"): + # Prevent abrt exception handler from running when the abrtd daemon is + # not active. + # abrtd sets the value to "no" when deactivated and vice versa. if conf["enabled"] == "yes": try: from abrt_exception_handler import * -- cgit