From 105ff10f12dce019ca2a455001239967c2e0e856 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Mon, 8 Dec 2014 16:02:11 +0100
Subject: [PATCH] ccpp-hook: move /proc/[pid]/ utils to libreport
Related to #548
Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
src/hooks/abrt-hook-ccpp.c | 202 +++++++++++++++------------------------------
1 file changed, 66 insertions(+), 136 deletions(-)
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
index f8f97ad..7fd9520 100644
--- a/src/hooks/abrt-hook-ccpp.c
+++ b/src/hooks/abrt-hook-ccpp.c
@@ -36,20 +36,6 @@
*/
#define IGNORE_RESULT(func_call) do { if (func_call) /* nothing */; } while (0)
-static char* malloc_readlink(const char *linkname)
-{
- char buf[PATH_MAX + 1];
- int len;
-
- len = readlink(linkname, buf, sizeof(buf)-1);
- if (len >= 0)
- {
- buf[len] = '\0';
- return xstrdup(buf);
- }
- return NULL;
-}
-
/* Custom version of copyfd_xyz,
* one which is able to write into two descriptors at once.
*/
@@ -171,75 +157,6 @@ static char *core_basename = (char*) "core";
*/
static char *full_core_basename;
-
-static char* get_executable(pid_t pid, int *fd_p)
-{
- char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3];
-
- sprintf(buf, "/proc/%lu/exe", (long)pid);
- if (fd_p)
- *fd_p = open(buf, O_RDONLY); /* might fail and return -1, it's ok */
- char *executable = malloc_readlink(buf);
- if (!executable)
- return NULL;
- /* find and cut off " (deleted)" from the path */
- char *deleted = executable + strlen(executable) - strlen(" (deleted)");
- if (deleted > executable && strcmp(deleted, " (deleted)") == 0)
- {
- *deleted = '\0';
- log_info("File '%s' seems to be deleted", executable);
- }
- /* find and cut off prelink suffixes from the path */
- char *prelink = executable + strlen(executable) - strlen(".#prelink#.XXXXXX");
- if (prelink > executable && strncmp(prelink, ".#prelink#.", strlen(".#prelink#.")) == 0)
- {
- log_info("File '%s' seems to be a prelink temporary file", executable);
- *prelink = '\0';
- }
- return executable;
-}
-
-static char* get_cwd(pid_t pid)
-{
- char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3];
- sprintf(buf, "/proc/%lu/cwd", (long)pid);
- return malloc_readlink(buf);
-}
-
-static char* get_rootdir(pid_t pid)
-{
- char buf[sizeof("/proc/%lu/root") + sizeof(long)*3];
- sprintf(buf, "/proc/%lu/root", (long)pid);
- return malloc_readlink(buf);
-}
-
-static int get_fsuid(char *proc_pid_status)
-{
- int real, euid, saved;
- /* if we fail to parse the uid, then make it root only readable to be safe */
- int fs_uid = 0;
-
- char *line = proc_pid_status; /* never NULL */
- for (;;)
- {
- if (strncmp(line, "Uid", 3) == 0)
- {
- int n = sscanf(line, "Uid:\t%d\t%d\t%d\t%d\n", &real, &euid, &saved, &fs_uid);
- if (n != 4)
- {
- perror_msg_and_die("Can't parse Uid: line");
- }
- break;
- }
- line = strchr(line, '\n');
- if (!line)
- break;
- line++;
- }
-
- return fs_uid;
-}
-
static int dump_suid_policy()
{
/*
@@ -400,42 +317,6 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu
return user_core_fd;
}
-static bool dump_fd_info(const char *dest_filename, char *source_filename, int source_base_ofs)
-{
- FILE *fp = fopen(dest_filename, "w");
- if (!fp)
- return false;
-
- unsigned fd = 0;
- while (fd <= 99999) /* paranoia check */
- {
- sprintf(source_filename + source_base_ofs, "fd/%u", fd);
- char *name = malloc_readlink(source_filename);
- if (!name)
- break;
- fprintf(fp, "%u:%s\n", fd, name);
- free(name);
-
- sprintf(source_filename + source_base_ofs, "fdinfo/%u", fd);
- fd++;
- FILE *in = fopen(source_filename, "r");
- if (!in)
- continue;
- char buf[128];
- while (fgets(buf, sizeof(buf)-1, in))
- {
- /* in case the line is not terminated, terminate it */
- char *eol = strchrnul(buf, '\n');
- eol[0] = '\n';
- eol[1] = '\0';
- fputs(buf, fp);
- }
- fclose(in);
- }
- fclose(fp);
- return true;
-}
-
/* Like xopen, but on error, unlocks and deletes dd and user core */
static int create_or_die(const char *filename, int user_core_fd)
{
@@ -513,6 +394,34 @@ static int test_configuration(bool setting_SaveFullCore, bool setting_CreateCore
return 0;
}
+int save_crashing_binary(pid_t pid, const char *dest_path, uid_t uid, gid_t gid)
+{
+ char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3];
+
+ sprintf(buf, "/proc/%lu/exe", (long)pid);
+ int src_fd_binary = open(buf, O_RDONLY); /* might fail and return -1, it's ok */
+ if (src_fd_binary < 0)
+ {
+ log_notice("Failed to open an image of crashing binary");
+ return 0;
+ }
+
+ int dst_fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_DUMP_DIR_MODE);
+ if (dst_fd < 0)
+ {
+ log_notice("Failed to create file '%s'", dest_path);
+ close(src_fd_binary);
+ return -1;
+ }
+
+ IGNORE_RESULT(fchown(dst_fd, uid, gid));
+
+ off_t sz = copyfd_eof(src_fd_binary, dst_fd, COPYFD_SPARSE);
+ close(src_fd_binary);
+
+ return fsync(dst_fd) != 0 || close(dst_fd) != 0 || sz < 0;
+}
+
int main(int argc, char** argv)
{
/* Kernel starts us with all fd's closed.
@@ -612,8 +521,7 @@ int main(int argc, char** argv)
char path[PATH_MAX];
- int src_fd_binary = -1;
- char *executable = get_executable(pid, setting_SaveBinaryImage ? &src_fd_binary : NULL);
+ char *executable = get_executable(pid);
if (executable && strstr(executable, "/abrt-hook-ccpp"))
{
error_msg_and_die("PID %lu is '%s', not dumping it to avoid recursion",
@@ -628,6 +536,9 @@ int main(int argc, char** argv)
uid_t fsuid = uid;
uid_t tmp_fsuid = get_fsuid(proc_pid_status);
+ if (tmp_fsuid < 0)
+ perror_msg_and_die("Can't parse 'Uid: line' in /proc/%lu/status", (long)pid);
+
int suid_policy = dump_suid_policy();
if (tmp_fsuid != uid)
{
@@ -805,16 +716,16 @@ int main(int argc, char** argv)
dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
- if (src_fd_binary > 0)
+ if (setting_SaveBinaryImage)
{
strcpy(path + path_len, "/"FILENAME_BINARY);
- int dst_fd = create_or_die(path, user_core_fd);
- off_t sz = copyfd_eof(src_fd_binary, dst_fd, COPYFD_SPARSE);
- if (fsync(dst_fd) != 0 || close(dst_fd) != 0 || sz < 0)
+
+ if (save_crashing_binary(pid, path, dd->dd_uid, dd->dd_gid))
{
- dd_delete(dd); error_msg_and_die("Error saving '%s'", path);
+ error_msg("Error saving '%s'", path);
+
+ goto error_exit;
}
- close(src_fd_binary);
}
off_t core_size = 0;
@@ -837,15 +748,12 @@ int main(int argc, char** argv)
if (fsync(abrt_core_fd) != 0 || close(abrt_core_fd) != 0 || core_size < 0)
{
unlink(path);
- dd_delete(dd);
- if (user_core_fd >= 0)
- {
- xchdir(user_pwd);
- unlink(core_basename);
- }
+
/* copyfd_sparse logs the error including errno string,
* but it does not log file name */
- error_msg_and_die("Error writing '%s'", path);
+ error_msg("Error writing '%s'", path);
+
+ goto error_exit;
}
if (user_core_fd >= 0
/* error writing user coredump? */
@@ -865,6 +773,13 @@ int main(int argc, char** argv)
create_user_core(user_core_fd, pid, ulimit_c);
}
+ /* User core is either written or closed */
+ user_core_fd = -1;
+
+ /*
+ * ! No other errors should cause removal of the user core !
+ */
+
/* Save JVM crash log if it exists. (JVM's coredump per se
* is nearly useless for JVM developers)
*/
@@ -891,8 +806,9 @@ int main(int argc, char** argv)
off_t sz = copyfd_eof(src_fd, dst_fd, COPYFD_SPARSE);
if (close(dst_fd) != 0 || sz < 0)
{
- dd_delete(dd);
- error_msg_and_die("Error saving '%s'", path);
+ error_msg("Error saving '%s'", path);
+
+ goto error_exit;
}
close(src_fd);
}
@@ -909,6 +825,8 @@ int main(int argc, char** argv)
* Classic deadlock.
*/
dd_close(dd);
+ dd = NULL;
+
path[path_len] = '\0'; /* path now contains only directory name */
char *newpath = xstrndup(path, path_len - (sizeof(".new")-1));
if (rename(path, newpath) == 0)
@@ -938,4 +856,16 @@ int main(int argc, char** argv)
/* We didn't create abrt dump, but may need to create compat coredump */
return create_user_core(user_core_fd, pid, ulimit_c);
+
+error_exit:
+ if (dd)
+ dd_delete(dd);
+
+ if (user_core_fd >= 0)
+ {
+ xchdir(user_pwd);
+ unlink(core_basename);
+ }
+
+ xfunc_die();
}
--
2.1.0