changeset 722:0438621d25ff HEAD

Added virtual memory size limits to processes. Default values are pretty high, this is mostly because I want it to prevent accidental infinite loops eating memory or some integer overflows, not to actually restrict anything.
author Timo Sirainen <tss@iki.fi>
date Sun, 01 Dec 2002 15:48:50 +0200
parents b01cd1b30764
children 2fc7cb5197b4
files configure.in dovecot-example.conf src/lib/Makefile.am src/lib/restrict-process-size.c src/lib/restrict-process-size.h src/master/auth-process.c src/master/imap-process.c src/master/login-process.c src/master/settings.c src/master/settings.h
diffstat 10 files changed, 108 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Sun Dec 01 15:10:15 2002 +0200
+++ b/configure.in	Sun Dec 01 15:48:50 2002 +0200
@@ -13,8 +13,8 @@
 AC_ARG_PROGRAM
 AM_PROG_LIBTOOL
 
-AC_CHECK_HEADERS(string.h stdlib.h stdint.h unistd.h dirent.h)
-AC_CHECK_HEADERS(sys/uio.h sys/sysmacros.h iconv.h linux/mman.h)
+AC_CHECK_HEADERS(string.h stdlib.h stdint.h unistd.h dirent.h iconv.h)
+AC_CHECK_HEADERS(sys/uio.h sys/sysmacros.h sys/resource.h linux/mman.h)
 
 # check posix headers
 AC_CHECK_HEADERS(sys/time.h)
@@ -161,7 +161,7 @@
 
 dnl * after -lsocket and -lnsl tests, inet_aton() may be in them
 AC_CHECK_FUNCS(fcntl flock inet_aton sigaction getpagesize madvise setreuid)
-AC_CHECK_FUNCS(strcasecmp stricmp vsnprintf memmove vsyslog writev)
+AC_CHECK_FUNCS(strcasecmp stricmp vsnprintf memmove vsyslog writev setrlimit)
 
 dnl * poll/select?
 
--- a/dovecot-example.conf	Sun Dec 01 15:10:15 2002 +0200
+++ b/dovecot-example.conf	Sun Dec 01 15:48:50 2002 +0200
@@ -61,6 +61,10 @@
 # User to use for imap-login process
 #login_user = imapd
 
+# Set max. process size in megabytes. If you don't use
+# login_process_per_connection you might need to grow this.
+#login_process_size = 16
+
 # Directory where imap-auth places authentication UNIX sockets which login
 # needs to be able to connect to. The sockets are created when running as
 # root, so you don't need to give imap-auth any access for it.
@@ -101,6 +105,10 @@
 # Executable location
 #imap_executable = /usr/libexec/dovecot/imap
 
+# Set max. process size in megabytes. Most of the memory goes to mmap()ing
+# files, so it shouldn't harm much even if this limit is set pretty high.
+#imap_process_size = 256
+
 # Maximum number of running imap processes. When this limit is reached,
 # new users aren't allowed to log in.
 #max_imap_processes = 1024
@@ -256,6 +264,9 @@
 # Executable location
 #auth_executable = /usr/libexec/dovecot/imap-auth
 
+# Set max. process size in megabytes.
+#auth_process_size = 256
+
 # User to use for the process. Only shadow and pam authentication requires
 # roots, so use something else if possible.
 auth_user = root
--- a/src/lib/Makefile.am	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/lib/Makefile.am	Sun Dec 01 15:48:50 2002 +0200
@@ -37,6 +37,7 @@
 	primes.c \
 	randgen.c \
 	restrict-access.c \
+	restrict-process-size.c \
 	sendfile-util.c \
 	strfuncs.c \
 	temp-string.c \
@@ -77,6 +78,7 @@
 	primes.h \
 	randgen.h \
 	restrict-access.h \
+	restrict-process-size.h \
 	sendfile-util.h \
 	strfuncs.h \
 	temp-string.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/restrict-process-size.c	Sun Dec 01 15:48:50 2002 +0200
@@ -0,0 +1,50 @@
+/*
+    Copyright (c) 2002 Timo Sirainen
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    "Software"), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "lib.h"
+#include "restrict-process-size.h"
+
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#  include <sys/resource.h>
+#endif
+
+void restrict_process_size(unsigned int size __attr_unused__)
+{
+#ifdef HAVE_SETRLIMIT
+	struct rlimit rlim;
+
+	rlim.rlim_max = rlim.rlim_cur =
+		size > 0 && size < INT_MAX/1024/1024 ?
+		size*1024*1024 : RLIM_INFINITY;
+	if (setrlimit(RLIMIT_AS, &rlim) < 0)
+		i_fatal("setrlimit(RLIMIT_AS, %u): %m", size);
+#else
+	if (size != 0) {
+		i_warning("Can't restrict process size: "
+			  "setrlimit() not supported by system. "
+			  "Set the limit to 0 to hide this warning.");
+	}
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/restrict-process-size.h	Sun Dec 01 15:48:50 2002 +0200
@@ -0,0 +1,8 @@
+#ifndef __RESTRICT_PROCESS_SIZE_H
+#define __RESTRICT_PROCESS_SIZE_H
+
+/* Restrict max. process size. The size is in megabytes, setting it to
+   (unsigned int)-1 sets it unlimited. */
+void restrict_process_size(unsigned int size);
+
+#endif
--- a/src/master/auth-process.c	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/master/auth-process.c	Sun Dec 01 15:48:50 2002 +0200
@@ -6,6 +6,7 @@
 #include "network.h"
 #include "obuffer.h"
 #include "restrict-access.h"
+#include "restrict-process-size.h"
 #include "auth-process.h"
 
 #include <stdlib.h>
@@ -207,6 +208,9 @@
 
 	i_assert(listen_fd > 2);
 
+	if (net_accept(listen_fd, NULL, NULL) == -2)
+		i_fatal("net_accept(1) failed: %m");
+
 	/* set correct permissions */
 	(void)chown(path, set_login_uid, set_login_gid);
 
@@ -224,8 +228,14 @@
 	if (dup2(null_fd, 2) < 0)
 		i_fatal("login: dup2() failed: %m");
 
+	if (net_accept(listen_fd, NULL, NULL) == -2)
+		i_fatal("net_accept(2) failed: %m");
+
 	clean_child_process();
 
+	if (net_accept(listen_fd, NULL, NULL) == -2)
+		i_fatal("net_accept(3) failed: %m");
+
 	/* move login communication handle to 3. do it last so we can be
 	   sure it's not closed afterwards. */
 	if (listen_fd != 3) {
@@ -239,6 +249,9 @@
 	restrict_access_set_env(config->user, pwd->pw_uid, pwd->pw_gid,
 				config->chroot);
 
+	if (net_accept(3, NULL, NULL) == -2)
+		i_fatal("net_accept(4) failed: %m");
+
 	/* set other environment */
 	env_put(t_strdup_printf("AUTH_PROCESS=%d", (int) getpid()));
 	env_put(t_strconcat("METHODS=", config->methods, NULL));
@@ -246,6 +259,9 @@
 	env_put(t_strconcat("USERINFO=", config->userinfo, NULL));
 	env_put(t_strconcat("USERINFO_ARGS=", config->userinfo_args,
 				    NULL));
+
+	restrict_process_size(config->process_size);
+
 	/* hide the path, it's ugly */
 	argv[0] = strrchr(config->executable, '/');
 	if (argv[0] == NULL) argv[0] = config->executable; else argv[0]++;
--- a/src/master/imap-process.c	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/master/imap-process.c	Sun Dec 01 15:48:50 2002 +0200
@@ -3,6 +3,7 @@
 #include "common.h"
 #include "env-util.h"
 #include "restrict-access.h"
+#include "restrict-process-size.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -151,6 +152,8 @@
 	   clean_child_process() since it clears environment */
 	restrict_access_set_env(user, uid, gid, chroot ? home : NULL);
 
+	restrict_process_size(set_imap_process_size);
+
 	/* hide the path, it's ugly */
 	argv[0] = strrchr(set_imap_executable, '/');
 	if (argv[0] == NULL) argv[0] = set_imap_executable; else argv[0]++;
--- a/src/master/login-process.c	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/master/login-process.c	Sun Dec 01 15:48:50 2002 +0200
@@ -7,6 +7,7 @@
 #include "fdpass.h"
 #include "env-util.h"
 #include "restrict-access.h"
+#include "restrict-process-size.h"
 #include "login-process.h"
 #include "auth-process.h"
 #include "master-interface.h"
@@ -320,6 +321,8 @@
 					set_max_logging_users));
 	}
 
+	restrict_process_size(set_login_process_size);
+
 	/* hide the path, it's ugly */
 	argv[0] = strrchr(set_login_executable, '/');
 	if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++;
--- a/src/master/settings.c	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/master/settings.c	Sun Dec 01 15:48:50 2002 +0200
@@ -41,6 +41,7 @@
 
 	{ "login_executable",	SET_STR, &set_login_executable },
 	{ "login_user",		SET_STR, &set_login_user },
+	{ "login_process_size",	SET_INT, &set_login_process_size },
 	{ "login_dir",		SET_STR, &set_login_dir },
 	{ "login_chroot",	SET_BOOL,&set_login_chroot },
 	{ "login_process_per_connection",
@@ -50,6 +51,7 @@
 	{ "max_logging_users",	SET_INT, &set_max_logging_users },
 
 	{ "imap_executable",	SET_STR, &set_imap_executable },
+	{ "imap_process_size",	SET_INT, &set_imap_process_size },
 	{ "valid_chroot_dirs",	SET_STR, &set_valid_chroot_dirs },
 	{ "max_imap_processes",	SET_INT, &set_max_imap_processes },
 	{ "verbose_proctitle",	SET_BOOL,&set_verbose_proctitle },
@@ -99,6 +101,7 @@
 
 /* login */
 char *set_login_executable = PKG_LIBEXECDIR"/imap-login";
+unsigned int set_login_process_size = 16;
 char *set_login_user = "imapd";
 char *set_login_dir = PKG_RUNDIR"/login";
 
@@ -113,6 +116,7 @@
 
 /* imap */
 char *set_imap_executable = PKG_LIBEXECDIR"/imap";
+unsigned int set_imap_process_size = 256;
 char *set_valid_chroot_dirs = NULL;
 unsigned int set_max_imap_processes = 1024;
 int set_verbose_proctitle = FALSE;
@@ -330,6 +334,11 @@
 		return NULL;
 	}
 
+	if (strcmp(key, "auth_process_size") == 0) {
+		if (!sscanf(value, "%i", &auth->process_size))
+			return t_strconcat("Invalid number: ", value, NULL);
+		return NULL;
+	}
 
 	return t_strconcat("Unknown setting: ", key, NULL);
 }
--- a/src/master/settings.h	Sun Dec 01 15:10:15 2002 +0200
+++ b/src/master/settings.h	Sun Dec 01 15:48:50 2002 +0200
@@ -21,6 +21,7 @@
 /* login */
 extern char *set_login_executable;
 extern char *set_login_user;
+extern unsigned int set_login_process_size;
 extern char *set_login_dir;
 extern int set_login_chroot;
 extern int set_login_process_per_connection;
@@ -33,6 +34,7 @@
 
 /* imap */
 extern char *set_imap_executable;
+extern unsigned int set_imap_process_size;
 extern char *set_valid_chroot_dirs;
 extern unsigned int set_max_imap_processes;
 extern int set_verbose_proctitle;
@@ -69,6 +71,7 @@
 	char *chroot;
 
 	int count;
+	unsigned int process_size;
 };
 
 extern AuthConfig *auth_processes_config;