]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Improve "core not dumped" error messages with Linux
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 1 Mar 2018 16:38:43 +0000 (18:38 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 13 Mar 2018 05:44:48 +0000 (07:44 +0200)
Recommend setting /proc/fs/suid_dumpable to 2 and
/proc/sys/kernel/core_pattern to absolute path, if they already aren't.

src/master/common.h
src/master/main.c
src/master/service-process.c

index 6f228a5f01dc214b3d38941aac224c3c372668fe..36bda94d71643dc5eb999789a86891fdf662464a 100644 (file)
@@ -5,9 +5,14 @@
 #include "master-interface.h"
 #include "master-settings.h"
 
+#define LINUX_PROC_FS_SUID_DUMPABLE "/proc/sys/fs/suid_dumpable"
+#define LINUX_PROC_SYS_KERNEL_CORE_PATTERN "/proc/sys/kernel/core_pattern"
+
 extern uid_t master_uid;
 extern gid_t master_gid;
 extern bool core_dumps_disabled;
+extern bool have_proc_fs_suid_dumpable;
+extern bool have_proc_sys_kernel_core_pattern;
 extern const char *ssl_manual_key_password;
 extern int global_master_dead_pipe_fd[2];
 extern struct service_list *services;
index 6968b02fa0a5a0867c227dcc8bf4a8d908446d8c..a29926fdf8cda6123257cb995a8a4dfe5df5baa5 100644 (file)
@@ -46,6 +46,8 @@ struct master_delayed_error {
 uid_t master_uid;
 gid_t master_gid;
 bool core_dumps_disabled;
+bool have_proc_fs_suid_dumpable;
+bool have_proc_sys_kernel_core_pattern;
 const char *ssl_manual_key_password;
 int global_master_dead_pipe_fd[2];
 struct service_list *services;
@@ -471,6 +473,7 @@ static void main_log_startup(char **protocols)
 #define STARTUP_STRING PACKAGE_NAME" v"DOVECOT_VERSION_FULL" starting up"
        string_t *str = t_str_new(128);
        rlim_t core_limit;
+       struct stat st;
 
        str_append(str, STARTUP_STRING);
        if (protocols[0] == NULL)
@@ -484,6 +487,10 @@ static void main_log_startup(char **protocols)
                core_limit == 0;
        if (core_dumps_disabled)
                str_append(str, " (core dumps disabled)");
+       if (stat(LINUX_PROC_FS_SUID_DUMPABLE, &st) == 0)
+               have_proc_fs_suid_dumpable = TRUE;
+       if (stat(LINUX_PROC_SYS_KERNEL_CORE_PATTERN, &st) == 0)
+               have_proc_sys_kernel_core_pattern = TRUE;
        i_info("%s", str_c(str));
 }
 
index 9fa84490281a53a6c9e6f3bba5a41b0293ce702c..968084bec3908a92886b13d4610dcc52e219664c 100644 (file)
@@ -444,12 +444,57 @@ get_exit_status_message(struct service *service, enum fatal_exit_status status)
        return NULL;
 }
 
+static bool linux_proc_fs_suid_is_dumpable(unsigned int *value_r)
+{
+       int fd = open(LINUX_PROC_FS_SUID_DUMPABLE, O_RDONLY);
+       if (fd == -1) {
+               /* we already checked that it exists - shouldn't get here */
+               i_error("open(%s) failed: %m", LINUX_PROC_FS_SUID_DUMPABLE);
+               have_proc_fs_suid_dumpable = FALSE;
+               return FALSE;
+       }
+       char buf[10];
+       ssize_t ret = read(fd, buf, sizeof(buf)-1);
+       if (ret < 0) {
+               i_error("read(%s) failed: %m", LINUX_PROC_FS_SUID_DUMPABLE);
+               have_proc_fs_suid_dumpable = FALSE;
+               *value_r = 0;
+       } else {
+               buf[ret] = '\0';
+               if (str_to_uint(buf, value_r) < 0)
+                       *value_r = 0;
+       }
+       i_close_fd(&fd);
+       return *value_r != 0;
+}
+
+static bool linux_is_absolute_core_pattern(void)
+{
+       int fd = open(LINUX_PROC_SYS_KERNEL_CORE_PATTERN, O_RDONLY);
+       if (fd == -1) {
+               /* we already checked that it exists - shouldn't get here */
+               i_error("open(%s) failed: %m", LINUX_PROC_SYS_KERNEL_CORE_PATTERN);
+               have_proc_sys_kernel_core_pattern = FALSE;
+               return FALSE;
+       }
+       char buf[10];
+       ssize_t ret = read(fd, buf, sizeof(buf)-1);
+       if (ret < 0) {
+               i_error("read(%s) failed: %m", LINUX_PROC_SYS_KERNEL_CORE_PATTERN);
+               have_proc_sys_kernel_core_pattern = FALSE;
+               buf[0] = '\0';
+       }
+       i_close_fd(&fd);
+       return buf[0] == '/' || buf[0] == '|';
+}
+
 static void
 log_coredump(struct service *service, string_t *str, int status)
 {
 #define CORE_DUMP_URL "https://dovecot.org/bugreport.html#coredumps"
 #ifdef WCOREDUMP
        int signum = WTERMSIG(status);
+       unsigned int dumpable;
 
        if (WCOREDUMP(status) != 0) {
                str_append(str, " (core dumped)");
@@ -466,6 +511,24 @@ log_coredump(struct service *service, string_t *str, int status)
        }
        str_append(str, " (core not dumped - "CORE_DUMP_URL);
 
+       /* If we're running on Linux, the best way to get core dumps is to set
+          fs.suid_dumpable=2 and sys.kernel.core_pattern to be an absolute
+          path. */
+       if (!have_proc_fs_suid_dumpable)
+               ;
+       else if (!linux_proc_fs_suid_is_dumpable(&dumpable)) {
+               str_printfa(str, " - set %s to 2)", LINUX_PROC_FS_SUID_DUMPABLE);
+               return;
+       } else if (dumpable == 2 && have_proc_sys_kernel_core_pattern &&
+                  !linux_is_absolute_core_pattern()) {
+               str_printfa(str, " - set %s to absolute path)",
+                           LINUX_PROC_SYS_KERNEL_CORE_PATTERN);
+               return;
+       } else if (dumpable == 1 || have_proc_sys_kernel_core_pattern) {
+               str_append(str, " - core wasn't writable?)");
+               return;
+       }
+
 #ifndef HAVE_PR_SET_DUMPABLE
        if (!service->set->drop_priv_before_exec && service->uid != 0) {
                str_printfa(str, " - set service %s "