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