Mailing List Archive

Exim and SELinux
In a message for which marc.theaimsgroup.com ate the Message-ID, Russell
wrote:
> For the most desirable support of Exim we need some minor changes to the way
> it works. I have spoken to the author about this and he has a positive
> attitude towards this, all that is necessary is for me (or someone else) to
> write some patches, test them, and send them to him.
>
> Once we get Exim working the way we desire doing the policy will be easy.
>
> What we want is to have different parts of Exim running in different domains.
> Exim is comprised of a single program that performs multiple tasks, but it
> re-exec's itself for each task. I think that the best way to do this is to
> have (for non-SE systems) multiple hard links to the main executable and have
> it use different names for each exec call. This just takes up a few extra
> directory entries on a non-SE system and has no noticeable overhead.

AFAICT there's only really two at the moment -- there's the unprivileged
mode where we only really need access to the spool directory, and the
mode we use for delivery, where we need to be able to write to users'
files. At http://david.woodhou.se/exim-4.50-selinux.patch there's a
patch which attempts to do this. If there are more personalities which I
should have distinguished between, we can fix that. Do we need a
separate binary to have privileges to listen on port 25?

> For a SE system we could have small wrapper programs (a few K in size - they
> would provide little overhead) that just exec the main executable. So when a
> new Exim task is launched it would exec the appropriate name which would
> trigger a domain transition, that new domain would then execute the main
> program to do the work.

For the moment I just hard-linked it. There's an patched version of the
current Fedora RPM called exim-4.50-2.selinux.{src,ppc,i386}.rpm in the
same location as above.

> This way Exim itself need know nothing about SE Linux, but we can get all the
> functionality we want.
>
> I believe that this would probably be acceptable to the author. In a month or
> so I may have time to code this. If someone else makes an appropriate patch
> to Exim I'll write the SE Linux policy immediately.

Let me know if you need anything more.

--
dwmw2
Re: Exim and SELinux [ In reply to ]
On Wed, 2005-02-23 at 17:21 +0000, David Woodhouse wrote:
>AFAICT there's only really two at the moment -- there's the unprivileged
>mode where we only really need access to the spool directory, and the
>mode we use for delivery, where we need to be able to write to users'
>files. At http://david.woodhou.se/exim-4.50-selinux.patch there's a
>patch which attempts to do this. If there are more personalities which I
>should have distinguished between, we can fix that. Do we need a
>separate binary to have privileges to listen on port 25?

The same patch would probably allow us to run /usr/sbin/exim without the
setuid root -- it could be setugid exim.exim, and the privileged Exim
binary could be setuid root but executable only by the Exim group.

I'm including it inline now that Evolution will actually let me do so
without crashing...

It would be nice if we could reduce the use of the privileged binary. At
the moment we use it for all deliveries from the queue. A quick hack
would be to try a delivery without privs, and restart that delivery from
scratch with the privileged binary if we need to -- but I'm not sure I
like that much.

--- exim-4.50/src/transport.c~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/transport.c 2005-02-23 16:30:18.000000000 +0000
@@ -1558,7 +1558,7 @@ if ((pid = fork()) == 0)
/* Set up the calling arguments; use the standard function for the basics,
but we have a number of extras that may be added. */

- argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
+ argv = child_exec_exim(CEE_RETURN_ARGV, FALSE, TRUE, &i, FALSE, 0);

if (smtp_authenticated) argv[i++] = US"-MCA";

--- exim-4.50/src/child.c~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/child.c 2005-02-23 16:27:54.000000000 +0000
@@ -69,8 +69,8 @@ Returns: if CEE_RETURN_ARGV is g
*/

uschar **
-child_exec_exim(int exec_type, BOOL kill_v, int *pcount, BOOL minimal,
- int acount, ...)
+child_exec_exim(int exec_type, BOOL privileged, BOOL kill_v, int *pcount,
+ BOOL minimal, int acount, ...)
{
int first_special = -1;
int n = 0;
@@ -81,7 +81,8 @@ uschar **argv =
/* In all case, the list starts out with the path, any macros, and a changed
config file. */

-argv[n++] = exim_path;
+argv[n++] = privileged?exim_path_privileged:exim_path;
+
if (clmacro_count > 0)
{
memcpy(argv + n, clmacros, clmacro_count * sizeof(uschar *));
@@ -204,11 +205,11 @@ if (pid == 0)
close(pfd[pipe_write]);
if (debug_fd > 0) force_fd(debug_fd, 2);
if (bounce_sender_authentication != NULL)
- child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, 8,
+ child_exec_exim(CEE_EXEC_EXIT, FALSE, FALSE, NULL, FALSE, 8,
US"-t", US"-oem", US"-oi", US"-f", US"<>", US"-oMas",
bounce_sender_authentication, message_id_option);
else
- child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, 6,
+ child_exec_exim(CEE_EXEC_EXIT, FALSE, FALSE, NULL, FALSE, 6,
US"-t", US"-oem", US"-oi", US"-f", US"<>", message_id_option);
/* Control does not return here. */
}
--- exim-4.50/src/globals.h~ 2005-02-22 20:40:26.000000000 +0000
+++ exim-4.50/src/globals.h 2005-02-23 16:18:27.000000000 +0000
@@ -285,6 +285,7 @@ extern int errors_sender_rc; /
extern gid_t exim_gid; /* To be used with exim_uid */
extern BOOL exim_gid_set; /* TRUE if exim_gid set */
extern uschar *exim_path; /* Path to exec exim */
+extern uschar *exim_path_privileged; /* Path to exec exim with elevated privileges */
extern uid_t exim_uid; /* Non-root uid for exim */
extern BOOL exim_uid_set; /* TRUE if exim_uid set */
extern int expand_forbid; /* RDO flags for forbidding things */
--- exim-4.50/src/readconf.c~ 2005-02-22 20:40:26.000000000 +0000
+++ exim-4.50/src/readconf.c 2005-02-23 16:26:10.000000000 +0000
@@ -201,6 +201,7 @@ static optionlist optionlist_config[] =
{ "errors_reply_to", opt_stringptr, &errors_reply_to },
{ "exim_group", opt_gid, &exim_gid },
{ "exim_path", opt_stringptr, &exim_path },
+ { "exim_path_privileged", opt_stringptr, &exim_path_privileged },
{ "exim_user", opt_uid, &exim_uid },
{ "extra_local_interfaces", opt_stringptr, &extra_local_interfaces },
{ "extract_addresses_remove_arguments", opt_bool, &extract_addresses_remove_arguments },
@@ -2898,6 +2899,11 @@ if (smtp_ratelimit_rcpt != NULL)
&smtp_rlr_base, &smtp_rlr_factor, &smtp_rlr_limit);
}

+/* If exim_path_privileged isn't explicitly set, it's the same as exim_path */
+
+if (exim_path_privileged == NULL)
+ exim_path_privileged = exim_path;
+
/* The qualify domains default to the primary host name */

if (qualify_domain_sender == NULL)
--- exim-4.50/src/globals.c~ 2005-02-22 20:40:26.000000000 +0000
+++ exim-4.50/src/globals.c 2005-02-23 16:25:17.000000000 +0000
@@ -491,6 +491,7 @@ gid_t exim_gid = EXIM_GI
BOOL exim_gid_set = TRUE; /* This gid is always set */
uschar *exim_path = US BIN_DIRECTORY "/exim"
"\0<---------------Space to patch exim_path->";
+uschar *exim_path_privileged = NULL;
uid_t exim_uid = EXIM_UID;
BOOL exim_uid_set = TRUE; /* This uid is always set */
int expand_forbid = 0;
--- exim-4.50/src/daemon.c~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/daemon.c 2005-02-23 16:28:21.000000000 +0000
@@ -621,7 +621,7 @@ if (pid == 0)
if (geteuid() != root_uid && !deliver_drop_privilege)
{
signal(SIGALRM, SIG_DFL);
- (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE, 2, US"-Mc",
+ (void)child_exec_exim(CEE_EXEC_PANIC, TRUE, FALSE, NULL, FALSE, 2, US"-Mc",
message_id);
/* Control does not return here. */
}
@@ -1636,7 +1636,7 @@ for (;;)
if (queue_run_local) *p++ = 'l';
*p = 0;

- (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, 1, opt);
+ (void)child_exec_exim(CEE_EXEC_PANIC, TRUE, FALSE, NULL, TRUE, 1, opt);
/* Control never returns here. */
}

--- exim-4.50/src/exim.c~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/exim.c 2005-02-23 16:29:34.000000000 +0000
@@ -4698,7 +4698,7 @@ while (more)

if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged)
{
- (void)child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, 2, US"-Mc",
+ (void)child_exec_exim(CEE_EXEC_EXIT, TRUE, FALSE, NULL, FALSE, 2, US"-Mc",
message_id);
/* Control does not return here. */
}
--- exim-4.50/src/smtp_in.c~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/smtp_in.c 2005-02-23 16:29:54.000000000 +0000
@@ -3423,7 +3423,7 @@ while (done <= 0)
break;
}
etrn_command = US"exim -R";
- argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, NULL, TRUE, 2, US"-R",
+ argv = child_exec_exim(CEE_RETURN_ARGV, FALSE, TRUE, NULL, TRUE, 2, US"-R",
smtp_data);
}

--- exim-4.50/src/functions.h~ 2005-02-17 14:49:11.000000000 +0000
+++ exim-4.50/src/functions.h 2005-02-23 16:33:17.000000000 +0000
@@ -52,7 +52,7 @@ extern int auth_get_no64_data(uschar
extern uschar *auth_xtextencode(uschar *, int);
extern int auth_xtextdecode(uschar *, uschar **);

-extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
+extern uschar **child_exec_exim(int, BOOL, BOOL, int *, BOOL, int, ...);
extern pid_t child_open_uid(uschar **, uschar **, int, uid_t *, gid_t *,
int *, int *, uschar *, BOOL);




--
dwmw2