|
|
a60cd7 |
From 523792cfbbaf3a5e10cdcb46979739b36ac9c4dd Mon Sep 17 00:00:00 2001
|
|
|
a60cd7 |
From: Martin Kutlak <mkutlak@redhat.com>
|
|
|
a60cd7 |
Date: Wed, 26 Sep 2018 13:24:40 +0200
|
|
|
a60cd7 |
Subject: [PATCH] ccpp: fast dumping and abrt core limit
|
|
|
a60cd7 |
|
|
|
a60cd7 |
This commit introduces a new configuration option MaxCoreFileSize. The
|
|
|
a60cd7 |
option will be compared to MaxCrashReportsSize and the minimum will be
|
|
|
a60cd7 |
used as the limit for the size of the core dump file in a dump directory.
|
|
|
a60cd7 |
|
|
|
a60cd7 |
This commit replaces the read once write twice algorithm with a tee + splice
|
|
|
a60cd7 |
algorithm. tee() does zero copy - it should just increment counters -
|
|
|
a60cd7 |
and splice() moves bytes between file descriptors without the need to
|
|
|
a60cd7 |
copy them to user space. Basically the new algorithm is the same but
|
|
|
a60cd7 |
without the need to copy data to user space. However, the original
|
|
|
a60cd7 |
algorithm was testing the buffer for 0s and if the entire buffer was 0,
|
|
|
a60cd7 |
then lseek() was performed instead of write(). The 0 check was there to
|
|
|
a60cd7 |
make the dumping faster and this is no longer needed as the tee +
|
|
|
a60cd7 |
splice is faster than the original read once write twice algorithm.
|
|
|
a60cd7 |
|
|
|
a60cd7 |
Related: rhbz#1613236
|
|
|
a60cd7 |
|
|
|
a60cd7 |
Signed-off-by: Martin Kutlak <mkutlak@redhat.com>
|
|
|
a60cd7 |
---
|
|
|
a60cd7 |
doc/abrt-CCpp.conf.txt | 5 +
|
|
|
a60cd7 |
src/hooks/CCpp.conf | 10 +
|
|
|
a60cd7 |
src/hooks/abrt-hook-ccpp.c | 381 +++++++++++++++++++++++++------------
|
|
|
a60cd7 |
3 files changed, 274 insertions(+), 122 deletions(-)
|
|
|
a60cd7 |
|
|
|
a60cd7 |
diff --git a/doc/abrt-CCpp.conf.txt b/doc/abrt-CCpp.conf.txt
|
|
|
a60cd7 |
index dffa45dc2..2a626ec49 100644
|
|
|
a60cd7 |
--- a/doc/abrt-CCpp.conf.txt
|
|
|
a60cd7 |
+++ b/doc/abrt-CCpp.conf.txt
|
|
|
a60cd7 |
@@ -19,6 +19,11 @@ MakeCompatCore = 'yes' / 'no' ...::
|
|
|
a60cd7 |
instead of the template.
|
|
|
a60cd7 |
For more information about naming core dump files see 'man 5 core'.
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+MaxCoreFileSize = 'a number in MiB' ...::
|
|
|
a60cd7 |
+ This configuration option together with MaxCrashReportsSize set the limit on
|
|
|
a60cd7 |
+ the size of dumped core file. The lower value of the both options is used as
|
|
|
a60cd7 |
+ the effective limit. 0 is evaluated as unlimited for the both options.
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
SaveBinaryImage = 'yes' / 'no' ...::
|
|
|
a60cd7 |
Do you want a copy of crashed binary be saved?
|
|
|
a60cd7 |
Useful, for example, when _deleted binary_ segfaults.
|
|
|
a60cd7 |
diff --git a/src/hooks/CCpp.conf b/src/hooks/CCpp.conf
|
|
|
a60cd7 |
index af31ed53c..48c8c2557 100644
|
|
|
a60cd7 |
--- a/src/hooks/CCpp.conf
|
|
|
a60cd7 |
+++ b/src/hooks/CCpp.conf
|
|
|
a60cd7 |
@@ -9,6 +9,16 @@
|
|
|
a60cd7 |
# For more information about naming core dump files see 'man 5 core'.
|
|
|
a60cd7 |
MakeCompatCore = yes
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+# The option allows you to set limit for the core file size in MiB.
|
|
|
a60cd7 |
+#
|
|
|
a60cd7 |
+# This value is compared to value of the MaxCrashReportSize configuration
|
|
|
a60cd7 |
+# option from (/etc/abrt.conf) and the lower value is used as the limit.
|
|
|
a60cd7 |
+#
|
|
|
a60cd7 |
+# If MaxCoreFileSize is 0 then the value of MaxCrashReportSize is the limit.
|
|
|
a60cd7 |
+# If MaxCrashReportSize is 0 then the value of MaxCoreFileSize is the limit.
|
|
|
a60cd7 |
+# If both values are 0 then the core file size is unlimited.
|
|
|
a60cd7 |
+MaxCoreFileSize = 0
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
# Do you want a copy of crashed binary be saved?
|
|
|
a60cd7 |
# (useful, for example, when _deleted binary_ segfaults)
|
|
|
a60cd7 |
SaveBinaryImage = no
|
|
|
a60cd7 |
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
|
|
|
a60cd7 |
index cb4d1e0ce..ca4b61bf1 100644
|
|
|
a60cd7 |
--- a/src/hooks/abrt-hook-ccpp.c
|
|
|
a60cd7 |
+++ b/src/hooks/abrt-hook-ccpp.c
|
|
|
a60cd7 |
@@ -31,6 +31,8 @@
|
|
|
a60cd7 |
#define DUMP_SUID_UNSAFE 1
|
|
|
a60cd7 |
#define DUMP_SUID_SAFE 2
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+#define KERNEL_PIPE_BUFFER_SIZE 65536
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
static int g_user_core_flags;
|
|
|
a60cd7 |
static int g_need_nonrelative;
|
|
|
a60cd7 |
|
|
|
a60cd7 |
@@ -54,100 +56,6 @@ static char* malloc_readlink(const char *linkname)
|
|
|
a60cd7 |
return NULL;
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
|
|
|
a60cd7 |
-/* Custom version of copyfd_xyz,
|
|
|
a60cd7 |
- * one which is able to write into two descriptors at once.
|
|
|
a60cd7 |
- */
|
|
|
a60cd7 |
-#define CONFIG_FEATURE_COPYBUF_KB 4
|
|
|
a60cd7 |
-static off_t copyfd_sparse(int src_fd, int dst_fd1, int dst_fd2, off_t size2)
|
|
|
a60cd7 |
-{
|
|
|
a60cd7 |
- off_t total = 0;
|
|
|
a60cd7 |
- int last_was_seek = 0;
|
|
|
a60cd7 |
-#if CONFIG_FEATURE_COPYBUF_KB <= 4
|
|
|
a60cd7 |
- char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
|
|
|
a60cd7 |
- enum { buffer_size = sizeof(buffer) };
|
|
|
a60cd7 |
-#else
|
|
|
a60cd7 |
- char *buffer;
|
|
|
a60cd7 |
- int buffer_size;
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
- /* We want page-aligned buffer, just in case kernel is clever
|
|
|
a60cd7 |
- * and can do page-aligned io more efficiently */
|
|
|
a60cd7 |
- buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
|
|
|
a60cd7 |
- PROT_READ | PROT_WRITE,
|
|
|
a60cd7 |
- MAP_PRIVATE | MAP_ANON,
|
|
|
a60cd7 |
- /* ignored: */ -1, 0);
|
|
|
a60cd7 |
- buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
|
|
|
a60cd7 |
- if (buffer == MAP_FAILED) {
|
|
|
a60cd7 |
- buffer = alloca(4 * 1024);
|
|
|
a60cd7 |
- buffer_size = 4 * 1024;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
-#endif
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
- while (1) {
|
|
|
a60cd7 |
- ssize_t rd = safe_read(src_fd, buffer, buffer_size);
|
|
|
a60cd7 |
- if (!rd) { /* eof */
|
|
|
a60cd7 |
- if (last_was_seek) {
|
|
|
a60cd7 |
- if (lseek(dst_fd1, -1, SEEK_CUR) < 0
|
|
|
a60cd7 |
- || safe_write(dst_fd1, "", 1) != 1
|
|
|
a60cd7 |
- || (dst_fd2 >= 0
|
|
|
a60cd7 |
- && (lseek(dst_fd2, -1, SEEK_CUR) < 0
|
|
|
a60cd7 |
- || safe_write(dst_fd2, "", 1) != 1
|
|
|
a60cd7 |
- )
|
|
|
a60cd7 |
- )
|
|
|
a60cd7 |
- ) {
|
|
|
a60cd7 |
- perror_msg("Write error");
|
|
|
a60cd7 |
- total = -1;
|
|
|
a60cd7 |
- goto out;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- /* all done */
|
|
|
a60cd7 |
- goto out;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- if (rd < 0) {
|
|
|
a60cd7 |
- perror_msg("Read error");
|
|
|
a60cd7 |
- total = -1;
|
|
|
a60cd7 |
- goto out;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
- /* checking sparseness */
|
|
|
a60cd7 |
- ssize_t cnt = rd;
|
|
|
a60cd7 |
- while (--cnt >= 0) {
|
|
|
a60cd7 |
- if (buffer[cnt] != 0) {
|
|
|
a60cd7 |
- /* not sparse */
|
|
|
a60cd7 |
- errno = 0;
|
|
|
a60cd7 |
- ssize_t wr1 = full_write(dst_fd1, buffer, rd);
|
|
|
a60cd7 |
- ssize_t wr2 = (dst_fd2 >= 0 ? full_write(dst_fd2, buffer, rd) : rd);
|
|
|
a60cd7 |
- if (wr1 < rd || wr2 < rd) {
|
|
|
a60cd7 |
- perror_msg("Write error");
|
|
|
a60cd7 |
- total = -1;
|
|
|
a60cd7 |
- goto out;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- last_was_seek = 0;
|
|
|
a60cd7 |
- goto adv;
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- /* sparse */
|
|
|
a60cd7 |
- xlseek(dst_fd1, rd, SEEK_CUR);
|
|
|
a60cd7 |
- if (dst_fd2 >= 0)
|
|
|
a60cd7 |
- xlseek(dst_fd2, rd, SEEK_CUR);
|
|
|
a60cd7 |
- last_was_seek = 1;
|
|
|
a60cd7 |
- adv:
|
|
|
a60cd7 |
- total += rd;
|
|
|
a60cd7 |
- size2 -= rd;
|
|
|
a60cd7 |
- if (size2 < 0)
|
|
|
a60cd7 |
- dst_fd2 = -1;
|
|
|
a60cd7 |
-// truncate to 0 or even delete the second file?
|
|
|
a60cd7 |
-// No, kernel does not delete nor truncate core files.
|
|
|
a60cd7 |
- }
|
|
|
a60cd7 |
- out:
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
-#if CONFIG_FEATURE_COPYBUF_KB > 4
|
|
|
a60cd7 |
- if (buffer_size != 4 * 1024)
|
|
|
a60cd7 |
- munmap(buffer, buffer_size);
|
|
|
a60cd7 |
-#endif
|
|
|
a60cd7 |
- return total;
|
|
|
a60cd7 |
-}
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
/* Global data */
|
|
|
a60cd7 |
static char *user_pwd;
|
|
|
a60cd7 |
static DIR *proc_cwd;
|
|
|
a60cd7 |
@@ -609,13 +517,42 @@ static void create_core_backtrace(pid_t tid, const char *executable, int signal_
|
|
|
a60cd7 |
#endif /* ENABLE_DUMP_TIME_UNWIND */
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+static ssize_t splice_entire_per_partes(int in_fd, int out_fd, size_t size_limit)
|
|
|
a60cd7 |
+{
|
|
|
a60cd7 |
+ size_t bytes = 0;
|
|
|
a60cd7 |
+ size_t soft_limit = KERNEL_PIPE_BUFFER_SIZE;
|
|
|
a60cd7 |
+ while (bytes < size_limit)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ const size_t hard_limit = size_limit - bytes;
|
|
|
a60cd7 |
+ if (hard_limit < soft_limit)
|
|
|
a60cd7 |
+ soft_limit = hard_limit;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ const ssize_t copied = splice(in_fd, NULL, out_fd, NULL, soft_limit, SPLICE_F_MOVE | SPLICE_F_MORE);
|
|
|
a60cd7 |
+ if (copied < 0)
|
|
|
a60cd7 |
+ return copied;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ bytes += copied;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ /* Check EOF. */
|
|
|
a60cd7 |
+ if (copied == 0)
|
|
|
a60cd7 |
+ break;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ return bytes;
|
|
|
a60cd7 |
+}
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
static int create_user_core(int user_core_fd, pid_t pid, off_t ulimit_c)
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
int err = 1;
|
|
|
a60cd7 |
if (user_core_fd >= 0)
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
- off_t core_size = copyfd_size(STDIN_FILENO, user_core_fd, ulimit_c, COPYFD_SPARSE);
|
|
|
a60cd7 |
- if (close_user_core(user_core_fd, core_size) != 0)
|
|
|
a60cd7 |
+ errno = 0;
|
|
|
a60cd7 |
+ ssize_t core_size = splice_entire_per_partes(STDIN_FILENO, user_core_fd, ulimit_c);
|
|
|
a60cd7 |
+ if (core_size < 0)
|
|
|
a60cd7 |
+ perror_msg("Failed to create user core '%s' in '%s'", core_basename, user_pwd);
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (close_user_core(user_core_fd, core_size) != 0 || core_size < 0)
|
|
|
a60cd7 |
goto finito;
|
|
|
a60cd7 |
|
|
|
a60cd7 |
err = 0;
|
|
|
a60cd7 |
@@ -732,6 +669,165 @@ static void error_msg_ignore_crash(const char *pid_str, const char *process_str,
|
|
|
a60cd7 |
return;
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+static ssize_t splice_full(int in_fd, int out_fd, size_t size)
|
|
|
a60cd7 |
+{
|
|
|
a60cd7 |
+ ssize_t total = 0;
|
|
|
a60cd7 |
+ while (size != 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ const ssize_t b = splice(in_fd, NULL, out_fd, NULL, size, 0);
|
|
|
a60cd7 |
+ if (b < 0)
|
|
|
a60cd7 |
+ return b;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (b == 0)
|
|
|
a60cd7 |
+ break;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ total += b;
|
|
|
a60cd7 |
+ size -= b;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ return total;
|
|
|
a60cd7 |
+}
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+static size_t xsplice_full(int in_fd, int out_fd, size_t size)
|
|
|
a60cd7 |
+{
|
|
|
a60cd7 |
+ const ssize_t r = splice_full(in_fd, out_fd, size);
|
|
|
a60cd7 |
+ if (r < 0)
|
|
|
a60cd7 |
+ perror_msg_and_die("Failed to write core dump to file");
|
|
|
a60cd7 |
+ return (size_t)r;
|
|
|
a60cd7 |
+}
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+static void pipe_close(int *pfds)
|
|
|
a60cd7 |
+{
|
|
|
a60cd7 |
+ close(pfds[0]);
|
|
|
a60cd7 |
+ close(pfds[1]);
|
|
|
a60cd7 |
+ pfds[0] = pfds[1] = -1;
|
|
|
a60cd7 |
+}
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+enum dump_core_files_ret_flags {
|
|
|
a60cd7 |
+ DUMP_ABRT_CORE_FAILED = 0x0001,
|
|
|
a60cd7 |
+ DUMP_USER_CORE_FAILED = 0x0100,
|
|
|
a60cd7 |
+};
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+/* Optimized creation of two core files - ABRT and CWD
|
|
|
a60cd7 |
+ *
|
|
|
a60cd7 |
+ * The simplest optimization is to avoid the need to copy data to user space.
|
|
|
a60cd7 |
+ * In that case we cannot read data once and write them twice as we do with
|
|
|
a60cd7 |
+ * read/write approach because there is no syscall forwarding data from a
|
|
|
a60cd7 |
+ * single source fd to several destination fds (one might claim that there is
|
|
|
a60cd7 |
+ * tee() function but such a solution is suboptimal from our perspective).
|
|
|
a60cd7 |
+ *
|
|
|
a60cd7 |
+ * So the function first create ABRT core file and then creates user core file.
|
|
|
a60cd7 |
+ * If ABRT limit made the ABRT core to be smaller than allowed user core size,
|
|
|
a60cd7 |
+ * then the function reads more data from STDIN and appends them to the user
|
|
|
a60cd7 |
+ * core file.
|
|
|
a60cd7 |
+ *
|
|
|
a60cd7 |
+ * We must not read from the user core fd because that operation might be
|
|
|
a60cd7 |
+ * refused by OS.
|
|
|
a60cd7 |
+ */
|
|
|
a60cd7 |
+static int dump_two_core_files(int abrt_core_fd, size_t *abrt_limit, int user_core_fd, size_t *user_limit)
|
|
|
a60cd7 |
+{
|
|
|
a60cd7 |
+ /* tee() does not move the in_fd, thus you need to call splice to be
|
|
|
a60cd7 |
+ * get next chunk of data loaded into the in_fd buffer.
|
|
|
a60cd7 |
+ * So, calling tee() without splice() would be looping on the same
|
|
|
a60cd7 |
+ * data. Hence, we must ensure that after tee() we call splice() and
|
|
|
a60cd7 |
+ * that would be problematic if tee core limit is greater than splice
|
|
|
a60cd7 |
+ * core limit. Therefore, we swap the out fds based on their limits.
|
|
|
a60cd7 |
+ */
|
|
|
a60cd7 |
+ int spliced_fd = *abrt_limit > *user_limit ? abrt_core_fd : user_core_fd;
|
|
|
a60cd7 |
+ size_t spliced_core_limit = *abrt_limit > *user_limit ? *abrt_limit : *user_limit;
|
|
|
a60cd7 |
+ int teed_fd = *abrt_limit > *user_limit ? user_core_fd : abrt_core_fd;
|
|
|
a60cd7 |
+ size_t teed_core_limit = *abrt_limit > *user_limit ? *user_limit : *abrt_limit;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ size_t *spliced_core_size = *abrt_limit > *user_limit ? abrt_limit : user_limit;
|
|
|
a60cd7 |
+ size_t *teed_core_size = *abrt_limit > *user_limit ? user_limit : abrt_limit;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ *spliced_core_size = *teed_core_size = 0;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ int cp[2] = { -1, -1 };
|
|
|
a60cd7 |
+ if (pipe(cp) < 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ perror_msg("Failed to create temporary pipe for core file");
|
|
|
a60cd7 |
+ cp[0] = cp[1] = -1;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ /* tee() can copy duplicate up to size of the pipe buffer bytes.
|
|
|
a60cd7 |
+ * It should not be problem to ask for more (in that case, tee would simply
|
|
|
a60cd7 |
+ * duplicate up to the limit bytes) but I would rather not to exceed
|
|
|
a60cd7 |
+ * the pipe buffer limit.
|
|
|
a60cd7 |
+ */
|
|
|
a60cd7 |
+ int copy_buffer_size = fcntl(STDIN_FILENO, F_GETPIPE_SZ);
|
|
|
a60cd7 |
+ if (copy_buffer_size < 0)
|
|
|
a60cd7 |
+ copy_buffer_size = KERNEL_PIPE_BUFFER_SIZE;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ ssize_t to_write = copy_buffer_size;
|
|
|
a60cd7 |
+ for (;;)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ if (cp[1] >= 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ to_write = tee(STDIN_FILENO, cp[1], copy_buffer_size, 0);
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ /* Check EOF. */
|
|
|
a60cd7 |
+ if (to_write == 0)
|
|
|
a60cd7 |
+ break;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (to_write < 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ perror_msg("Cannot duplicate stdin buffer for core file");
|
|
|
a60cd7 |
+ pipe_close(cp);
|
|
|
a60cd7 |
+ to_write = copy_buffer_size;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ size_t to_splice = to_write;
|
|
|
a60cd7 |
+ if (*spliced_core_size + to_splice > spliced_core_limit)
|
|
|
a60cd7 |
+ to_splice = spliced_core_limit - *spliced_core_size;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ const size_t spliced = xsplice_full(STDIN_FILENO, spliced_fd, to_splice);
|
|
|
a60cd7 |
+ *spliced_core_size += spliced;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (cp[0] >= 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ size_t to_tee = to_write;
|
|
|
a60cd7 |
+ if (*teed_core_size + to_tee > teed_core_limit)
|
|
|
a60cd7 |
+ to_tee = teed_core_limit - *teed_core_size;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ const ssize_t teed = splice_full(cp[0], teed_fd, to_tee);
|
|
|
a60cd7 |
+ if (teed < 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ perror_msg("Cannot splice teed data to core file");
|
|
|
a60cd7 |
+ pipe_close(cp);
|
|
|
a60cd7 |
+ to_write = copy_buffer_size;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ *teed_core_size += teed;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (*teed_core_size >= teed_core_limit)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ pipe_close(cp);
|
|
|
a60cd7 |
+ to_write = copy_buffer_size;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ /* Check EOF. */
|
|
|
a60cd7 |
+ if (spliced == 0 || *spliced_core_size >= spliced_core_limit)
|
|
|
a60cd7 |
+ break;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ int r = 0;
|
|
|
a60cd7 |
+ if (cp[0] < 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ if (abrt_limit < user_limit)
|
|
|
a60cd7 |
+ r |= DUMP_ABRT_CORE_FAILED;
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ r |= DUMP_USER_CORE_FAILED;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ pipe_close(cp);
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ return r;
|
|
|
a60cd7 |
+}
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
int main(int argc, char** argv)
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
int err = 1;
|
|
|
a60cd7 |
@@ -755,6 +851,8 @@ int main(int argc, char** argv)
|
|
|
a60cd7 |
bool setting_SaveBinaryImage;
|
|
|
a60cd7 |
bool setting_SaveFullCore;
|
|
|
a60cd7 |
bool setting_CreateCoreBacktrace;
|
|
|
a60cd7 |
+ unsigned int setting_MaxCoreFileSize = g_settings_nMaxCrashReportsSize;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
GList *setting_ignored_paths = NULL;
|
|
|
a60cd7 |
GList *setting_allowed_users = NULL;
|
|
|
a60cd7 |
GList *setting_allowed_groups = NULL;
|
|
|
a60cd7 |
@@ -780,6 +878,18 @@ int main(int argc, char** argv)
|
|
|
a60cd7 |
if (value)
|
|
|
a60cd7 |
setting_allowed_groups = parse_list(value);
|
|
|
a60cd7 |
|
|
|
a60cd7 |
+ value = get_map_string_item_or_NULL(settings, "MaxCoreFileSize");
|
|
|
a60cd7 |
+ if (value)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ char *end;
|
|
|
a60cd7 |
+ errno = 0;
|
|
|
a60cd7 |
+ unsigned long ul = strtoul(value, &end, 10);
|
|
|
a60cd7 |
+ if (errno || end == value || *end != '\0' || ul > UINT_MAX)
|
|
|
a60cd7 |
+ error_msg("The MaxCoreFileSize option in the CCpp.conf file holds an invalid value");
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ setting_MaxCoreFileSize = ul;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
setting_CreateCoreBacktrace = value ? string_to_bool(value) : true;
|
|
|
a60cd7 |
value = get_map_string_item_or_NULL(settings, "VerboseLog");
|
|
|
a60cd7 |
if (value)
|
|
|
a60cd7 |
@@ -1019,8 +1129,8 @@ int main(int argc, char** argv)
|
|
|
a60cd7 |
|
|
|
a60cd7 |
unlink(path);
|
|
|
a60cd7 |
int abrt_core_fd = xopen3(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
|
|
a60cd7 |
- off_t core_size = copyfd_eof(STDIN_FILENO, abrt_core_fd, COPYFD_SPARSE);
|
|
|
a60cd7 |
- if (core_size < 0 || fsync(abrt_core_fd) != 0)
|
|
|
a60cd7 |
+ off_t core_size = splice_entire_per_partes(STDIN_FILENO, abrt_core_fd, SIZE_MAX);
|
|
|
a60cd7 |
+ if (core_size < 0 || fsync(abrt_core_fd) != 0 || close(abrt_core_fd) < 0)
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
unlink(path);
|
|
|
a60cd7 |
/* copyfd_eof logs the error including errno string,
|
|
|
a60cd7 |
@@ -1133,31 +1243,58 @@ int main(int argc, char** argv)
|
|
|
a60cd7 |
close(src_fd_binary);
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
|
|
|
a60cd7 |
- off_t core_size = 0;
|
|
|
a60cd7 |
+ size_t core_size = 0;
|
|
|
a60cd7 |
if (setting_SaveFullCore)
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
- strcpy(path + path_len, "/"FILENAME_COREDUMP);
|
|
|
a60cd7 |
- int abrt_core_fd = create_or_die(path, user_core_fd);
|
|
|
a60cd7 |
-
|
|
|
a60cd7 |
- /* We write both coredumps at once.
|
|
|
a60cd7 |
- * We can't write user coredump first, since it might be truncated
|
|
|
a60cd7 |
- * and thus can't be copied and used as abrt coredump;
|
|
|
a60cd7 |
- * and if we write abrt coredump first and then copy it as user one,
|
|
|
a60cd7 |
- * then we have a race when process exits but coredump does not exist yet:
|
|
|
a60cd7 |
- * $ echo -e '#include<signal.h>\nmain(){raise(SIGSEGV);}' | gcc -o test -x c -
|
|
|
a60cd7 |
- * $ rm -f core*; ulimit -c unlimited; ./test; ls -l core*
|
|
|
a60cd7 |
- * 21631 Segmentation fault (core dumped) ./test
|
|
|
a60cd7 |
- * ls: cannot access core*: No such file or directory <=== BAD
|
|
|
a60cd7 |
- */
|
|
|
a60cd7 |
- core_size = copyfd_sparse(STDIN_FILENO, abrt_core_fd, user_core_fd, ulimit_c);
|
|
|
a60cd7 |
- close_user_core(user_core_fd, core_size);
|
|
|
a60cd7 |
- if (fsync(abrt_core_fd) != 0 || close(abrt_core_fd) != 0 || core_size < 0)
|
|
|
a60cd7 |
+ int abrt_core_fd = dd_open_item(dd, FILENAME_COREDUMP, O_RDWR);
|
|
|
a60cd7 |
+ if (abrt_core_fd < 0)
|
|
|
a60cd7 |
+ { /* Avoid the need to deal with two destinations. */
|
|
|
a60cd7 |
+ perror_msg("Failed to create ABRT core file in '%s'", dd->dd_dirname);
|
|
|
a60cd7 |
+ create_user_core(user_core_fd, pid, ulimit_c);
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
{
|
|
|
a60cd7 |
- unlink(path);
|
|
|
a60cd7 |
- dd_delete(dd);
|
|
|
a60cd7 |
- /* copyfd_sparse logs the error including errno string,
|
|
|
a60cd7 |
- * but it does not log file name */
|
|
|
a60cd7 |
- error_msg_and_die("Error writing '%s'", path);
|
|
|
a60cd7 |
+ size_t abrt_limit = 0;
|
|
|
a60cd7 |
+ if ( (g_settings_nMaxCrashReportsSize != 0 && setting_MaxCoreFileSize == 0)
|
|
|
a60cd7 |
+ || (g_settings_nMaxCrashReportsSize != 0 && g_settings_nMaxCrashReportsSize < setting_MaxCoreFileSize))
|
|
|
a60cd7 |
+ abrt_limit = g_settings_nMaxCrashReportsSize;
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ abrt_limit = setting_MaxCoreFileSize;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (abrt_limit != 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ const size_t abrt_limit_bytes = 1024 * 1024 * abrt_limit;
|
|
|
a60cd7 |
+ /* Overflow protection. */
|
|
|
a60cd7 |
+ if (abrt_limit_bytes > abrt_limit)
|
|
|
a60cd7 |
+ abrt_limit = abrt_limit_bytes;
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ error_msg("ABRT core file size limit (MaxCrashReportsSize|MaxCoreFileSize) does not fit into runtime type. Using maximal possible size.");
|
|
|
a60cd7 |
+ abrt_limit = SIZE_MAX;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ abrt_limit = SIZE_MAX;
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (user_core_fd < 0)
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ const ssize_t r = splice_entire_per_partes(STDIN_FILENO, abrt_core_fd, abrt_limit);
|
|
|
a60cd7 |
+ if (r < 0)
|
|
|
a60cd7 |
+ perror_msg("Failed to write ABRT core file");
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ core_size = r;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+ else
|
|
|
a60cd7 |
+ {
|
|
|
a60cd7 |
+ size_t user_limit = ulimit_c;
|
|
|
a60cd7 |
+ const int r = dump_two_core_files(abrt_core_fd, &abrt_limit, user_core_fd, &user_limit);
|
|
|
a60cd7 |
+ close_user_core(user_core_fd, (r & DUMP_USER_CORE_FAILED) ? -1 : user_limit);
|
|
|
a60cd7 |
+ if (!(r & DUMP_ABRT_CORE_FAILED))
|
|
|
a60cd7 |
+ core_size = abrt_limit;
|
|
|
a60cd7 |
+ }
|
|
|
a60cd7 |
+
|
|
|
a60cd7 |
+ if (fsync(abrt_core_fd) != 0 || close(abrt_core_fd) != 0)
|
|
|
a60cd7 |
+ perror_msg("Failed to close ABRT core file");
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
}
|
|
|
a60cd7 |
else
|
|
|
a60cd7 |
@@ -1223,8 +1360,8 @@ int main(int argc, char** argv)
|
|
|
a60cd7 |
free(newpath);
|
|
|
a60cd7 |
|
|
|
a60cd7 |
if (core_size > 0)
|
|
|
a60cd7 |
- log_notice("Saved core dump of pid %lu (%s) to %s (%llu bytes)",
|
|
|
a60cd7 |
- (long)pid, executable, path, (long long)core_size);
|
|
|
a60cd7 |
+ log_notice("Saved core dump of pid %lu (%s) to %s (%zu bytes)",
|
|
|
a60cd7 |
+ (long)pid, executable, path, core_size);
|
|
|
a60cd7 |
|
|
|
a60cd7 |
notify_new_path(path);
|
|
|
a60cd7 |
|
|
|
a60cd7 |
--
|
|
|
a60cd7 |
2.17.2
|
|
|
a60cd7 |
|