#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;
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;
#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)
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));
}
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)");
}
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 "