Gitweb:
https://git.exim.org/exim.git/commitdiff/d56e798eb66ac044ff22f0daa2185549f5d49632
Commit: d56e798eb66ac044ff22f0daa2185549f5d49632
Parent: 3109898a5e815a04f505c73b67493ef15d9f0665
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Mon May 10 22:47:01 2021 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Mon Jun 28 00:30:02 2021 +0100
first go. crashes in 0003
---
src/src/exim.c | 29 +++++++++++----
src/src/functions.h | 1 +
src/src/readconf.c | 104 +++++++++++++++++++++++++---------------------------
src/src/store.c | 41 ++++++++++++++++++---
src/src/store.h | 4 +-
5 files changed, 111 insertions(+), 68 deletions(-)
diff --git a/src/src/exim.c b/src/src/exim.c
index 6a9a147..eb1d834 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -3688,7 +3688,7 @@ else
{
struct rlimit rlp;
- #ifdef RLIMIT_NOFILE
+#ifdef RLIMIT_NOFILE
if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
{
log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s",
@@ -3711,9 +3711,9 @@ else
strerror(errno));
}
}
- #endif
+#endif
- #ifdef RLIMIT_NPROC
+#ifdef RLIMIT_NPROC
if (getrlimit(RLIMIT_NPROC, &rlp) < 0)
{
log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s",
@@ -3721,20 +3721,20 @@ else
rlp.rlim_cur = rlp.rlim_max = 0;
}
- #ifdef RLIM_INFINITY
+# ifdef RLIM_INFINITY
if (rlp.rlim_cur != RLIM_INFINITY && rlp.rlim_cur < 1000)
{
rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY;
- #else
+# else
if (rlp.rlim_cur < 1000)
{
rlp.rlim_cur = rlp.rlim_max = 1000;
- #endif
+# endif
if (setrlimit(RLIMIT_NPROC, &rlp) < 0)
log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s",
strerror(errno));
}
- #endif
+#endif
}
/* Exim is normally entered as root (but some special configurations are
@@ -3857,6 +3857,7 @@ is equivalent to the ability to modify a setuid binary!
This needs to happen before we read the main configuration. */
init_lookup_list();
+/*XXX this excrescence could move to the testsuite standard config setup file */
#ifdef SUPPORT_I18N
if (f.running_in_test_harness) smtputf8_advertise_hosts = NULL;
#endif
@@ -3895,19 +3896,21 @@ issues (currently about tls_advertise_hosts and keep_environment not being
defined) */
{
+ int old_pool = store_pool;
#ifdef MEASURE_TIMING
struct timeval t0, diff;
(void)gettimeofday(&t0, NULL);
#endif
+ store_pool = POOL_CONFIG;
readconf_main(checking || list_options);
+ store_pool = old_pool;
#ifdef MEASURE_TIMING
report_time_since(&t0, US"readconf_main (delta)");
#endif
}
-
/* Now in directory "/" */
if (cleanup_environment() == FALSE)
@@ -4494,7 +4497,13 @@ if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD)
event_action gets expanded */
if (msg_action == MSG_REMOVE)
+ {
+ int old_pool = store_pool;
+ store_pool = POOL_CONFIG;
readconf_rest();
+ store_pool = old_pool;
+ store_writeprotect(POOL_CONFIG);
+ }
if (!one_msg_action)
{
@@ -4519,12 +4528,16 @@ Now, since the intro of the ${acl } expansion, ACL definitions may be
needed in transports so we lost the optimisation. */
{
+ int old_pool = store_pool;
#ifdef MEASURE_TIMING
struct timeval t0, diff;
(void)gettimeofday(&t0, NULL);
#endif
+ store_pool = POOL_CONFIG;
readconf_rest();
+ store_pool = old_pool;
+ store_writeprotect(POOL_CONFIG);
#ifdef MEASURE_TIMING
report_time_since(&t0, US"readconf_rest (delta)");
diff --git a/src/src/functions.h b/src/src/functions.h
index e349721..38c8e40 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -527,6 +527,7 @@ extern int stdin_ungetc(int);
extern void store_exit(void);
extern void store_init(void);
+extern void store_writeprotect(int);
extern gstring *string_append(gstring *, int, ...) WARN_UNUSED_RESULT;
extern gstring *string_append_listele(gstring *, uschar, const uschar *) WARN_UNUSED_RESULT;
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 34ebf87..4602dd2 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -3142,55 +3142,54 @@ while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
/* Cut out all the fancy processing unless specifically wanted */
- #if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
+#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
uschar *suffix = filename + Ustrlen(filename);
/* Try for the node-specific file if a node name exists */
- #ifdef CONFIGURE_FILE_USE_NODE
+# ifdef CONFIGURE_FILE_USE_NODE
struct utsname uts;
if (uname(&uts) >= 0)
{
- #ifdef CONFIGURE_FILE_USE_EUID
+# ifdef CONFIGURE_FILE_USE_EUID
sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
- config_file = Ufopen(filename, "rb");
- if (config_file == NULL)
- #endif /* CONFIGURE_FILE_USE_EUID */
+ if (!(config_file = Ufopen(filename, "rb")))
+# endif /* CONFIGURE_FILE_USE_EUID */
{
sprintf(CS suffix, ".%.256s", uts.nodename);
config_file = Ufopen(filename, "rb");
}
}
- #endif /* CONFIGURE_FILE_USE_NODE */
+# endif /* CONFIGURE_FILE_USE_NODE */
/* Otherwise, try the generic name, possibly with the euid added */
- #ifdef CONFIGURE_FILE_USE_EUID
- if (config_file == NULL)
+# ifdef CONFIGURE_FILE_USE_EUID
+ if (!config_file)
{
sprintf(CS suffix, ".%ld", (long int)original_euid);
config_file = Ufopen(filename, "rb");
}
- #endif /* CONFIGURE_FILE_USE_EUID */
+# endif /* CONFIGURE_FILE_USE_EUID */
/* Finally, try the unadorned name */
- if (config_file == NULL)
+ if (!config_file)
{
*suffix = 0;
config_file = Ufopen(filename, "rb");
}
- #else /* if neither defined */
+#else /* if neither defined */
/* This is the common case when the fancy processing is not included. */
config_file = Ufopen(filename, "rb");
- #endif
+#endif
/* If the file does not exist, continue to try any others. For any other
error, break out (and die). */
- if (config_file != NULL || errno != ENOENT) break;
+ if (config_file || errno != ENOENT) break;
}
/* On success, save the name for verification; config_filename is used when
@@ -3213,39 +3212,37 @@ if (config_file)
config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
else
{
- /* relative configuration file name: working dir + / + basename(filename) */
+ /* relative configuration file name: working dir + / + basename(filename) */
- uschar buf[PATH_MAX];
- gstring * g;
+ uschar buf[PATH_MAX];
+ gstring * g;
- if (os_getcwd(buf, PATH_MAX) == NULL)
- {
- perror("exim: getcwd");
- exit(EXIT_FAILURE);
- }
- g = string_cat(NULL, buf);
+ if (os_getcwd(buf, PATH_MAX) == NULL)
+ {
+ perror("exim: getcwd");
+ exit(EXIT_FAILURE);
+ }
+ g = string_cat(NULL, buf);
- /* If the dir does not end with a "/", append one */
- if (g->s[g->ptr-1] != '/')
- g = string_catn(g, US"/", 1);
+ /* If the dir does not end with a "/", append one */
+ if (g->s[g->ptr-1] != '/')
+ g = string_catn(g, US"/", 1);
- /* If the config file contains a "/", extract the directory part */
- if (last_slash)
- g = string_catn(g, filename, last_slash - filename);
+ /* If the config file contains a "/", extract the directory part */
+ if (last_slash)
+ g = string_catn(g, filename, last_slash - filename);
- config_main_directory = string_from_gstring(g);
+ config_main_directory = string_from_gstring(g);
}
config_directory = config_main_directory;
}
else
- {
if (!filename)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
"%s", config_main_filelist);
else
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
string_open_failed("configuration file %s", filename));
- }
/* Now, once we found and opened our configuration file, we change the directory
to a safe place. Later we change to $spool_directory. */
@@ -3265,19 +3262,19 @@ if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
big_buffer);
- if ((statbuf.st_uid != root_uid /* owner not root */
- #ifdef CONFIGURE_OWNER
- && statbuf.st_uid != config_uid /* owner not the special one */
- #endif
- ) || /* or */
- (statbuf.st_gid != root_gid /* group not root & */
- #ifdef CONFIGURE_GROUP
- && statbuf.st_gid != config_gid /* group not the special one */
- #endif
- && (statbuf.st_mode & 020) != 0) || /* group writeable */
- /* or */
- ((statbuf.st_mode & 2) != 0)) /* world writeable */
-
+ if ( statbuf.st_uid != root_uid /* owner not root */
+#ifdef CONFIGURE_OWNER
+ && statbuf.st_uid != config_uid /* owner not the special one */
+#endif
+ || /* or */
+ statbuf.st_gid != root_gid /* group not root & */
+#ifdef CONFIGURE_GROUP
+ && statbuf.st_gid != config_gid /* group not the special one */
+#endif
+ && (statbuf.st_mode & 020) != 0 /* group writeable */
+ || /* or */
+ (statbuf.st_mode & 2) != 0 /* world writeable */
+ )
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
"wrong owner, group, or mode", big_buffer);
@@ -3324,11 +3321,11 @@ while ((s = get_config_line()))
read_named_list(&hostlist_anchor, &hostlist_count,
MAX_NAMED_LIST, t+8, US"host list", hide);
- else if (Ustrncmp(t, US"addresslist", 11) == 0)
+ else if (Ustrncmp(t, "addresslist", 11) == 0)
read_named_list(&addresslist_anchor, &addresslist_count,
MAX_NAMED_LIST, t+11, US"address list", hide);
- else if (Ustrncmp(t, US"localpartlist", 13) == 0)
+ else if (Ustrncmp(t, "localpartlist", 13) == 0)
read_named_list(&localpartlist_anchor, &localpartlist_count,
MAX_NAMED_LIST, t+13, US"local part list", hide);
@@ -3347,7 +3344,7 @@ if (local_sender_retain && local_from_check)
/* If the timezone string is empty, set it to NULL, implying no TZ variable
wanted. */
-if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL;
+if (timezone_string && !*timezone_string) timezone_string = NULL;
/* The max retry interval must not be greater than 24 hours. */
@@ -3492,7 +3489,7 @@ if (syslog_facility_str)
/* Expand pid_file_path */
-if (*pid_file_path != 0)
+if (*pid_file_path)
{
if (!(s = expand_string(pid_file_path)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
@@ -3502,7 +3499,7 @@ if (*pid_file_path != 0)
/* Set default value of process_log_path */
-if (!process_log_path || *process_log_path =='\0')
+if (!process_log_path || !*process_log_path)
process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
@@ -3554,7 +3551,7 @@ if (errors_reply_to)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"error in errors_reply_to (%s): %s", errors_reply_to, errmess);
- if (domain == 0)
+ if (!domain)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"errors_reply_to (%s) does not contain a domain", errors_reply_to);
}
@@ -3562,8 +3559,7 @@ if (errors_reply_to)
/* If smtp_accept_queue or smtp_accept_max_per_host is set, then
smtp_accept_max must also be set. */
-if (smtp_accept_max == 0 &&
- (smtp_accept_queue > 0 || smtp_accept_max_per_host != NULL))
+if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"smtp_accept_max must be set if smtp_accept_queue or "
"smtp_accept_max_per_host is set");
@@ -3584,7 +3580,7 @@ if (host_number_string)
host_number_string, expand_string_message);
n = Ustrtol(s, &end, 0);
while (isspace(*end)) end++;
- if (*end != 0)
+ if (*end)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"localhost_number value is not a number: %s", s);
if (n > LOCALHOST_MAX)
diff --git a/src/src/store.c b/src/src/store.c
index 2a32e9b..ad4da3c 100644
--- a/src/src/store.c
+++ b/src/src/store.c
@@ -41,6 +41,9 @@ The following different types of store are recognized:
a single message transaction but needed for longer than the use of the main
pool permits. Currently this means only receive-time DKIM information.
+- There is a dedicated pool for configuration data read from the config file(s).
+ Once complete, it is made readonly.
+
. Orthogonal to the three pool types, there are two classes of memory: untainted
and tainted. The latter is used for values derived from untrusted input, and
the string-expansion mechanism refuses to operate on such values (obviously,
@@ -165,21 +168,24 @@ static int max_nonpool_malloc; /* max value for nonpool_malloc */
static const uschar * pooluse[NPOOLS] = {
[POOL_MAIN] = US"main",
[POOL_PERM] = US"perm",
+[POOL_CONFIG] = US"config",
[POOL_SEARCH] = US"search",
[POOL_MESSAGE] = US"message",
[POOL_TAINT_MAIN] = US"main",
[POOL_TAINT_PERM] = US"perm",
-[POOL_TAINT_SEARCH] = US"search",
+[POOL_TAINT_CONFIG] = US"config",
[POOL_TAINT_SEARCH] = US"search",
[POOL_TAINT_MESSAGE] = US"message",
};
static const uschar * poolclass[NPOOLS] = {
[POOL_MAIN] = US"untainted",
[POOL_PERM] = US"untainted",
+[POOL_CONFIG] = US"untainted",
[POOL_SEARCH] = US"untainted",
[POOL_MESSAGE] = US"untainted",
[POOL_TAINT_MAIN] = US"tainted",
[POOL_TAINT_PERM] = US"tainted",
+[POOL_TAINT_CONFIG] = US"tainted",
[POOL_TAINT_SEARCH] = US"tainted",
[POOL_TAINT_MESSAGE] = US"tainted",
};
@@ -245,6 +251,22 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n",
+/******************************************************************************/
+void
+store_writeprotect(int pool)
+{
+for (storeblock * b = chainbase[pool]; b; b = b->next)
+ {
+#ifndef COMPILE_UTILITY
+ if (mprotect(b, ALIGNED_SIZEOF_STOREBLOCK + b->length, PROT_READ) != 0)
+ DEBUG(D_any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno))
+#endif
+ ;
+ }
+}
+
+/******************************************************************************/
+
/*************************************************
* Get a block from the current pool *
*************************************************/
@@ -324,7 +346,13 @@ if (size > yield_length[pool])
if (++nblocks[pool] > maxblocks[pool])
maxblocks[pool] = nblocks[pool];
- newblock = internal_store_malloc(mlength, func, linenumber);
+ if (pool == POOL_CONFIG)
+ {
+ long pgsize = sysconf(_SC_PAGESIZE);
+ posix_memalign((void **)&newblock, pgsize, (mlength + pgsize - 1) & ~(pgsize - 1));
+ }
+ else
+ newblock = internal_store_malloc(mlength, func, linenumber);
newblock->next = NULL;
newblock->length = length;
#ifndef RESTRICTED_MEMORY
@@ -483,7 +511,8 @@ not call with a pointer returned by store_get(). Both the untainted and tainted
pools corresposding to store_pool are reset.
Arguments:
- r place to back up to
+ ptr place to back up to
+ pool pool holding the pointer
func function from which called
linenumber line number in source file
@@ -561,7 +590,8 @@ if ( yield_length[pool] < STOREPOOL_MIN_SIZE
}
bb = b->next;
-b->next = NULL;
+if (pool != POOL_CONFIG)
+ b->next = NULL;
while ((b = bb))
{
@@ -576,7 +606,8 @@ while ((b = bb))
nbytes[pool] -= siz;
pool_malloc -= siz;
nblocks[pool]--;
- internal_store_free(b, func, linenumber);
+ if (pool != POOL_CONFIG)
+ internal_store_free(b, func, linenumber);
#ifndef RESTRICTED_MEMORY
if (store_block_order[pool] > 13) store_block_order[pool]--;
diff --git a/src/src/store.h b/src/src/store.h
index 92deabf..58561ac 100644
--- a/src/src/store.h
+++ b/src/src/store.h
@@ -13,9 +13,10 @@
/* Define symbols for identifying the store pools. */
-#define NPOOLS 8
+#define NPOOLS 10
enum { POOL_MAIN,
POOL_PERM,
+ POOL_CONFIG,
POOL_SEARCH,
POOL_MESSAGE,
@@ -23,6 +24,7 @@ enum { POOL_MAIN,
POOL_TAINT_MAIN = POOL_TAINT_BASE,
POOL_TAINT_PERM,
+ POOL_TAINT_CONFIG,
POOL_TAINT_SEARCH,
POOL_TAINT_MESSAGE };