summaryrefslogtreecommitdiffstats
path: root/src/Hooks/CCpp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Hooks/CCpp.cpp')
-rw-r--r--src/Hooks/CCpp.cpp322
1 files changed, 109 insertions, 213 deletions
diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp
index fd789cf..3a13358 100644
--- a/src/Hooks/CCpp.cpp
+++ b/src/Hooks/CCpp.cpp
@@ -18,25 +18,14 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
-/* Make all file ops "large" and make off_t 64-bit.
- * No need to use O_LARGEFILE anywhere
- */
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-
#include "abrtlib.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include <syslog.h>
#define FILENAME_EXECUTABLE "executable"
-#define FILENAME_CMDLINE "cmdline"
#define FILENAME_COREDUMP "coredump"
-#define VAR_RUN_PID_FILE VAR_RUN"/abrt.pid"
-
using namespace std;
static char* malloc_readlink(const char *linkname)
@@ -69,157 +58,42 @@ static char* get_cwd(pid_t pid)
return malloc_readlink(buf);
}
-static char *append_escaped(char *start, const char *s)
-{
- char hex_char_buf[] = "\\x00";
-
- *start++ = ' ';
- char *dst = start;
- const unsigned char *p = (unsigned char *)s;
-
- while (1)
- {
- const unsigned char *old_p = p;
- while (*p > ' ' && *p <= 0x7e && *p != '\"' && *p != '\'' && *p != '\\')
- p++;
- if (dst == start)
- {
- if (p != (unsigned char *)s && *p == '\0')
- {
- /* entire word does not need escaping and quoting */
- strcpy(dst, s);
- dst += strlen(s);
- return dst;
- }
- *dst++ = '\'';
- }
-
- strncpy(dst, s, (p - old_p));
- dst += (p - old_p);
-
- if (*p == '\0')
- {
- *dst++ = '\'';
- *dst = '\0';
- return dst;
- }
- const char *a;
- switch (*p)
- {
- case '\r': a = "\\r"; break;
- case '\n': a = "\\n"; break;
- case '\t': a = "\\t"; break;
- case '\'': a = "\\\'"; break;
- case '\"': a = "\\\""; break;
- case '\\': a = "\\\\"; break;
- case ' ': a = " "; break;
- default:
- hex_char_buf[2] = "0123456789abcdef"[*p >> 4];
- hex_char_buf[3] = "0123456789abcdef"[*p & 0xf];
- a = hex_char_buf;
- }
- strcpy(dst, a);
- dst += strlen(a);
- p++;
- }
-}
-
-// taken from kernel
-#define COMMAND_LINE_SIZE 2048
-static char* get_cmdline(pid_t pid)
-{
- char path[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
- char cmdline[COMMAND_LINE_SIZE];
- char escaped_cmdline[COMMAND_LINE_SIZE*4 + 4];
-
- escaped_cmdline[1] = '\0';
- sprintf(path, "/proc/%u/cmdline", (int)pid);
- int fd = open(path, O_RDONLY);
- if (fd >= 0)
- {
- int len = read(fd, cmdline, sizeof(cmdline) - 1);
- close(fd);
-
- if (len > 0)
- {
- cmdline[len] = '\0';
- char *src = cmdline;
- char *dst = escaped_cmdline;
- while ((src - cmdline) < len)
- {
- dst = append_escaped(dst, src);
- src += strlen(src) + 1;
- }
- }
- }
-
- return xstrdup(escaped_cmdline + 1); /* +1 skips extraneous leading space */
-}
-
-static int daemon_is_ok()
-{
- int fd = open(VAR_RUN_PID_FILE, O_RDONLY);
- if (fd < 0)
- {
- return 0;
- }
-
- char pid[sizeof(pid_t)*3 + 2];
- int len = read(fd, pid, sizeof(pid)-1);
- close(fd);
- if (len <= 0)
- return 0;
-
- pid[len] = '\0';
- *strchrnul(pid, '\n') = '\0';
- /* paranoia: we don't want to check /proc//stat or /proc///stat */
- if (pid[0] == '\0' || pid[0] == '/')
- return 0;
-
- /* TODO: maybe readlink and check that it is "xxx/abrt"? */
- char path[sizeof("/proc/%s/stat") + sizeof(pid)];
- sprintf(path, "/proc/%s/stat", pid);
- struct stat sb;
- if (stat(path, &sb) == -1)
- {
- return 0;
- }
-
- return 1;
-}
-
int main(int argc, char** argv)
{
int fd;
struct stat sb;
const char* program_name = argv[0];
- if (argc < 4)
+ if (argc < 5)
{
- error_msg_and_die("Usage: %s: <dddir> <pid> <signal> <uid>", program_name);
+ error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name);
}
openlog("abrt", 0, LOG_DAEMON);
logmode = LOGMODE_SYSLOG;
+ errno = 0;
const char* dddir = argv[1];
- pid_t pid = atoi(argv[2]);
+ pid_t pid = xatoi_u(argv[2]);
const char* signal_str = argv[3];
- int signal = atoi(argv[3]);
- uid_t uid = atoi(argv[4]);
-
- if (signal != SIGQUIT
- && signal != SIGILL
- && signal != SIGABRT
- && signal != SIGFPE
- && signal != SIGSEGV
+ int signal_no = xatoi_u(argv[3]);
+ uid_t uid = xatoi_u(argv[4]);
+ off_t ulimit_c = strtoull(argv[5], NULL, 10);
+ off_t core_size = 0;
+
+ if (errno || pid <= 0 || ulimit_c < 0)
+ {
+ error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]);
+ }
+ if (signal_no != SIGQUIT
+ && signal_no != SIGILL
+ && signal_no != SIGABRT
+ && signal_no != SIGFPE
+ && signal_no != SIGSEGV
) {
/* not an error, exit silently */
return 0;
}
- if (pid <= 0 || (int)uid < 0)
- {
- error_msg_and_die("pid '%s' or uid '%s' are bogus", argv[2], argv[4]);
- }
+
char *user_pwd = get_cwd(pid); /* may be NULL on error */
int core_fd = STDIN_FILENO;
@@ -247,6 +121,65 @@ int main(int argc, char** argv)
(int)pid, executable);
}
+ /* Parse abrt.conf and plugins/CCpp.conf */
+ unsigned setting_MaxCrashReportsSize = 0;
+ bool setting_MakeCompatCore = false;
+ bool abrt_conf = true;
+ FILE *fp = fopen(CONF_DIR"/abrt.conf", "r");
+ if (fp)
+ {
+ char line[256];
+ while (1)
+ {
+ if (fgets(line, sizeof(line), fp) == NULL)
+ {
+ /* Next .conf file plz */
+ if (abrt_conf)
+ {
+ abrt_conf = false;
+ fp = fopen(CONF_DIR"/plugins/CCpp.conf", "r");
+ if (fp)
+ continue;
+ }
+ break;
+ }
+
+ unsigned len = strlen(line);
+ if (len > 0 && line[len-1] == '\n')
+ line[--len] = '\0';
+ const char *p = skip_whitespace(line);
+#undef DIRECTIVE
+#define DIRECTIVE "MaxCrashReportsSize"
+ if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
+ {
+ p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
+ if (*p != '=')
+ continue;
+ p = skip_whitespace(p + 1);
+ if (isdigit(*p))
+ /* x1.25: go a bit up, so that usual in-daemon trimming
+ * kicks in first, and we don't "fight" with it. */
+ setting_MaxCrashReportsSize = (unsigned long)xatou(p) * 5 / 4;
+ continue;
+ }
+#undef DIRECTIVE
+#define DIRECTIVE "MakeCompatCore"
+ if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
+ {
+ p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
+ if (*p != '=')
+ continue;
+ p = skip_whitespace(p + 1);
+ setting_MakeCompatCore = string_to_bool(p);
+ continue;
+ }
+#undef DIRECTIVE
+ /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */
+ }
+ fclose(fp);
+ }
+
+
char path[PATH_MAX];
/* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes
@@ -267,7 +200,12 @@ int main(int argc, char** argv)
{
path[sz] = '\0';
if (strcmp(executable, path) == 0)
- error_msg_and_die("not dumping repeating crash in '%s'", executable);
+ {
+ error_msg("not dumping repeating crash in '%s'", executable);
+ if (setting_MakeCompatCore)
+ goto create_user_core;
+ return 1;
+ }
}
lseek(fd, 0, SEEK_SET);
}
@@ -286,20 +224,20 @@ int main(int argc, char** argv)
*/
snprintf(path, sizeof(path), "%s/abrtd-coredump", dddir);
core_fd = xopen3(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- off_t size = copyfd_eof(STDIN_FILENO, core_fd);
- if (size < 0 || close(core_fd) != 0)
+ core_size = copyfd_eof(STDIN_FILENO, core_fd);
+ if (core_size < 0 || close(core_fd) != 0)
{
unlink(path);
/* copyfd_eof logs the error including errno string,
* but it does not log file name */
error_msg_and_die("error saving coredump to %s", path);
}
- log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)size);
+ log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size);
return 0;
}
char* cmdline = get_cmdline(pid); /* never NULL */
- const char *signame = strsignal(atoi(signal_str));
+ const char *signame = strsignal(signal_no);
char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str);
snprintf(path, sizeof(path), "%s/ccpp-%ld-%u", dddir, (long)time(NULL), (int)pid);
@@ -325,8 +263,8 @@ int main(int argc, char** argv)
dd.Close();
perror_msg_and_die("can't open '%s'", path);
}
- off_t size = copyfd_eof(STDIN_FILENO, core_fd);
- if (size < 0 || fsync(core_fd) != 0)
+ core_size = copyfd_eof(STDIN_FILENO, core_fd);
+ if (core_size < 0 || fsync(core_fd) != 0)
{
unlink(path);
dd.Delete();
@@ -337,7 +275,7 @@ int main(int argc, char** argv)
}
lseek(core_fd, 0, SEEK_SET);
/* note: core_fd is still open, we may use it later to copy core to user's dir */
- log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)size);
+ log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size);
free(executable);
free(cmdline);
path[len] = '\0'; /* path now contains directory name */
@@ -350,64 +288,6 @@ int main(int argc, char** argv)
*/
dd.Close();
- /* Parse abrt.conf and plugins/CCpp.conf */
- unsigned setting_MaxCrashReportsSize = 0;
- bool setting_MakeCompatCore = false;
- bool abrt_conf = true;
- FILE *fp = fopen(CONF_DIR"/abrt.conf", "r");
- if (fp)
- {
- char line[256];
- while (1)
- {
- if (fgets(line, sizeof(line), fp) == NULL)
- {
- /* Next .conf file plz */
- if (abrt_conf)
- {
- abrt_conf = false;
- fp = fopen(CONF_DIR"/plugins/CCpp.conf", "r");
- if (fp)
- continue;
- }
- break;
- }
-
- unsigned len = strlen(line);
- if (len > 0 && line[len-1] == '\n')
- line[--len] = '\0';
- const char *p = skip_whitespace(line);
-#undef DIRECTIVE
-#define DIRECTIVE "MaxCrashReportsSize"
- if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
- {
- p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
- if (*p != '=')
- continue;
- p = skip_whitespace(p + 1);
- if (isdigit(*p))
- /* x1.25: go a bit up, so that usual in-daemon trimming
- * kicks in first, and we don't "fight" with it. */
- setting_MaxCrashReportsSize = (unsigned long)atoi(p) * 5 / 4;
- continue;
- }
-#undef DIRECTIVE
-#define DIRECTIVE "MakeCompatCore"
- if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
- {
- p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
- if (*p != '=')
- continue;
- p = skip_whitespace(p + 1);
- setting_MakeCompatCore = string_to_bool(p);
- continue;
- }
-#undef DIRECTIVE
- /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */
- }
- fclose(fp);
- }
-
/* rhbz#539551: "abrt going crazy when crashing process is respawned".
* Do we want to protect against or ameliorate this? How? Ideas:
* (1) nice ourself?
@@ -447,7 +327,12 @@ int main(int argc, char** argv)
error_msg_and_die("%s", e.what());
}
+
create_user_core:
+ /* note: core_size may be == 0 ("unknown") */
+ if (core_size > ulimit_c || ulimit_c == 0)
+ return 0;
+
/* Write a core file for user */
struct passwd* pw = getpwuid(uid);
@@ -520,8 +405,10 @@ int main(int argc, char** argv)
perror_msg_and_die("%s/%s is not a regular file with link count 1", user_pwd, core_basename);
}
+ /* Note: we do not copy more than ulimit_c */
+ off_t size;
if (ftruncate(usercore_fd, 0) != 0
- || copyfd_eof(core_fd, usercore_fd) < 0
+ || (size = copyfd_size(core_fd, usercore_fd, ulimit_c)) < 0
|| close(usercore_fd) != 0
) {
/* perror first, otherwise unlink may trash errno */
@@ -529,7 +416,16 @@ int main(int argc, char** argv)
unlink(core_basename);
return 1;
}
- log("saved core dump of pid %u to %s/%s", (int)pid, user_pwd, core_basename);
+ if (size == ulimit_c && size != core_size)
+ {
+ /* We copied exactly ulimit_c bytes (and it doesn't accidentally match
+ * core_size (imagine exactly 1MB coredump with "ulimit -c 1M" - that'd be ok)),
+ * it means that core is larger than ulimit_c. Abort and delete the dump.
+ */
+ unlink(core_basename);
+ return 1;
+ }
+ log("saved core dump of pid %u to %s/%s (%llu bytes)", (int)pid, user_pwd, core_basename, (long long)size);
return 0;
}