129 lines
6.1 KiB
Diff
129 lines
6.1 KiB
Diff
|
Bugzilla: bnc#658731
|
|||
|
Author: David Woodhouse
|
|||
|
Date: 2010-12-09 17:22 UTC
|
|||
|
To: exim-dev
|
|||
|
Subject: Re: [exim-dev] [Exim-maintainers] Remote root vulnerability in Exim
|
|||
|
[Resend to exim-dev for comment, since exim-maintainers is quiet]
|
|||
|
|
|||
|
On Thu, 2010-12-09 at 10:18 +0000, David Woodhouse wrote:
|
|||
|
> In the meantime, I'm looking at the second bug; the privilege
|
|||
|
> escalation. I think the best answer to that is to kill the
|
|||
|
> ALT_CONFIG_ROOT_ONLY option completely, and *always* allow the trusted
|
|||
|
> user to use an alternative config but *only* if that config is listed in
|
|||
|
> a file such as /etc/exim/allowed-configs. Does that seem sane?
|
|||
|
|
|||
|
Hm, we already have ALT_CONFIG_PREFIX which *almost* does this. It's
|
|||
|
just that when defined, it refuses to run at all with a config that
|
|||
|
doesn't match the prefix; rather than simply running without privileges.
|
|||
|
|
|||
|
I don't really see the point in refusing to run at all; the user can
|
|||
|
always build their *own* Exim binary and run it without privileges.
|
|||
|
|
|||
|
So I've come up with the patch below. It kills the ALT_CONFIG_ROOT_ONLY
|
|||
|
option, by making it effectively always set and never allowing even the
|
|||
|
trusted Exim user to use arbitrary config files.
|
|||
|
|
|||
|
It repurposes the existing ALT_CONFIG_PREFIX, rather than adding a new
|
|||
|
option and making things more complex. Instead of refusing to run with
|
|||
|
config files that don't match the prefix, Exim will simply run without
|
|||
|
root privileges. And it *will* run with root privileges when invoked
|
|||
|
with the -C option for a file which *does* match the prefix.
|
|||
|
|
|||
|
Important user-visible changes would be:
|
|||
|
|
|||
|
- If you previously had ALT_CONFIG_ROOT_ONLY unset (the default), then
|
|||
|
you must set ALT_CONFIG_PREFIX and use matching files if you want
|
|||
|
to use alternative config files.
|
|||
|
|
|||
|
- If you previously had ALT_CONFIG_PREFIX set, then you should be aware
|
|||
|
that matching config files will now be invoked with root privileges
|
|||
|
regardless of the uid of the invoking user.
|
|||
|
|
|||
|
We could change the latter so that non-root and non-exim users invoking
|
|||
|
config files in ALT_CONFIG_PREFIX are *never* granted root privs, but
|
|||
|
I'm not sure we should. Comments?
|
|||
|
|
|||
|
Index: exim-4.71/src/exim.c
|
|||
|
===================================================================
|
|||
|
--- exim-4.71.orig/src/exim.c
|
|||
|
+++ exim-4.71/src/exim.c
|
|||
|
@@ -3158,12 +3158,9 @@ if (setgroups(0, NULL) != 0)
|
|||
|
}
|
|||
|
|
|||
|
/* If the configuration file name has been altered by an argument on the
|
|||
|
-command line (either a new file name or a macro definition) and the caller is
|
|||
|
-not root or the exim user, or if this is a filter testing run, remove any
|
|||
|
-setuid privilege the program has, and run as the underlying user.
|
|||
|
-
|
|||
|
-If ALT_CONFIG_ROOT_ONLY is defined, the exim user is locked out of this, which
|
|||
|
-severely restricts the use of -C for some purposes.
|
|||
|
+command line (either a new file name not matching ALT_CONFIG_PREFIX or a macro
|
|||
|
+definition) and the caller is not root, or if this is a filter testing run,
|
|||
|
+remove any setuid privilege the program has, and run as the underlying user.
|
|||
|
|
|||
|
Otherwise, set the real ids to the effective values (should be root unless run
|
|||
|
from inetd, which it can either be root or the exim uid, if one is configured).
|
|||
|
@@ -3177,9 +3174,6 @@ configuration file changes and macro def
|
|||
|
if (( /* EITHER */
|
|||
|
(config_changed || macros != NULL) && /* Config changed, and */
|
|||
|
real_uid != root_uid && /* Not root, and */
|
|||
|
- #ifndef ALT_CONFIG_ROOT_ONLY /* (when not locked out) */
|
|||
|
- real_uid != exim_uid && /* Not exim, and */
|
|||
|
- #endif
|
|||
|
!running_in_test_harness /* Not fudged */
|
|||
|
) || /* OR */
|
|||
|
expansion_test /* expansion testing */
|
|||
|
@@ -3367,47 +3361,16 @@ else
|
|||
|
}
|
|||
|
|
|||
|
/* Handle the case when we have removed the setuid privilege because of -C or
|
|||
|
--D. This means that the caller of Exim was not root, and, provided that
|
|||
|
-ALT_CONFIG_ROOT_ONLY is not defined, was not the Exim user that is built into
|
|||
|
-the binary.
|
|||
|
-
|
|||
|
-If ALT_CONFIG_ROOT_ONLY is not defined, there is a problem if it turns out we
|
|||
|
-were running as the exim user defined in the configuration file (different to
|
|||
|
-the one in the binary). The sysadmin may expect this case to retain privilege
|
|||
|
-because "the binary was called by the Exim user", but it hasn't, because of the
|
|||
|
-order in which it handles this stuff. There are two possibilities:
|
|||
|
-
|
|||
|
- (1) If deliver_drop_privilege is set, Exim is not going to re-exec in order
|
|||
|
- to do message deliveries. Thus, the fact that it is running as a
|
|||
|
- non-privileged user is plausible, and might be wanted in some special
|
|||
|
- configurations. However, really_exim will have been set false when
|
|||
|
- privilege was dropped, to stop Exim trying to write to its normal log
|
|||
|
- files. Therefore, re-enable normal log processing, assuming the sysadmin
|
|||
|
- has set up the log directory correctly.
|
|||
|
-
|
|||
|
- (2) If deliver_drop_privilege is not set, the configuration won't work as
|
|||
|
- apparently intended, and so we log a panic message. In order to retain
|
|||
|
- root for -C or -D, the caller must either be root or the Exim user
|
|||
|
- defined in the binary (when deliver_drop_ privilege is false).
|
|||
|
-
|
|||
|
-If ALT_CONFIG_ROOT_ONLY is defined, we don't know whether we were called by the
|
|||
|
-built-in exim user or one defined in the configuration. In either event,
|
|||
|
-re-enable log processing, assuming the sysadmin knows what they are doing. */
|
|||
|
+-D. This means that the caller of Exim was not root.
|
|||
|
+
|
|||
|
+We don't know whether we were called by the built-in exim user or one defined
|
|||
|
+in the configuration. In either event, re-enable log processing, assuming the
|
|||
|
+sysadmin knows what they are doing. */
|
|||
|
|
|||
|
if (removed_privilege && (config_changed || macros != NULL) &&
|
|||
|
real_uid == exim_uid)
|
|||
|
{
|
|||
|
- #ifdef ALT_CONFIG_ROOT_ONLY
|
|||
|
really_exim = TRUE; /* let logging work normally */
|
|||
|
- #else
|
|||
|
-
|
|||
|
- if (deliver_drop_privilege)
|
|||
|
- really_exim = TRUE; /* let logging work normally */
|
|||
|
- else
|
|||
|
- log_write(0, LOG_MAIN|LOG_PANIC,
|
|||
|
- "exim user (uid=%d) is defined only at runtime; privilege lost for %s",
|
|||
|
- (int)exim_uid, config_changed? "-C" : "-D");
|
|||
|
- #endif
|
|||
|
}
|
|||
|
|
|||
|
/* Start up Perl interpreter if Perl support is configured and there is a
|