* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2015 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "exim.h"
Returns: nothing
*/
-static void
+void
force_fd(int oldfd, int newfd)
{
if (oldfd == newfd) return;
int extra = pcount ? *pcount : 0;
uschar **argv;
-argv = store_get((extra + acount + MAX_CLMACROS + 21) * sizeof(char *), FALSE);
+argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), GET_UNTAINTED);
/* In all case, the list starts out with the path, any macros, and a changed
config file. */
-argv[n++] = exim_path;
+argv[n++] = exim_path; /* assume untainted */
if (clmacro_count > 0)
{
memcpy(argv + n, clmacros, clmacro_count * sizeof(uschar *));
n += clmacro_count;
}
if (f.config_changed)
- {
- argv[n++] = US"-C";
- argv[n++] = config_main_filename;
- }
+ { argv[n++] = US"-C"; argv[n++] = config_main_filename; }
/* These values are added only for non-minimal cases. If debug_selector is
precisely D_v, we have to assume this was started by a non-admin user, and
else
{
if (debug_selector != 0)
+ {
argv[n++] = string_sprintf("-d=0x%x", debug_selector);
+ if (debug_fd > 2)
+ {
+ int flags = fcntl(debug_fd, F_GETFD);
+ if (flags != -1) (void)fcntl(debug_fd, F_SETFD, flags & ~FD_CLOEXEC);
+ close(2);
+ dup2(debug_fd, 2);
+ close(debug_fd);
+ }
+ }
+ }
+ if (debug_pretrigger_buf)
+ { argv[n++] = US"-dp"; argv[n++] = string_sprintf("0x%x", debug_pretrigger_bsize); }
+ if (dtrigger_selector != 0)
+ argv[n++] = string_sprintf("-dt=0x%x", dtrigger_selector);
+ DEBUG(D_any)
+ {
+ argv[n++] = US"-MCd";
+ argv[n++] = US process_purpose;
}
- if (!f.testsuite_delays) argv[n++] = US"-odd";
- if (f.dont_deliver) argv[n++] = US"-N";
- if (f.queue_smtp) argv[n++] = US"-odqs";
- if (f.synchronous_delivery) argv[n++] = US"-odi";
+ if (!f.testsuite_delays) argv[n++] = US"-odd";
+ if (f.dont_deliver) argv[n++] = US"-N";
+ if (f.queue_smtp) argv[n++] = US"-odqs";
+ if (f.synchronous_delivery) argv[n++] = US"-odi";
if (connection_max_messages >= 0)
argv[n++] = string_sprintf("-oB%d", connection_max_messages);
if (*queue_name)
- {
- argv[n++] = US"-MCG";
- argv[n++] = queue_name;
- }
+ { argv[n++] = US"-MCG"; argv[n++] = queue_name; }
}
/* Now add in any others that are in the call. Remember which they were,
argv[n] = NULL;
if (exec_type == CEE_RETURN_ARGV)
{
- if (pcount != NULL) *pcount = n;
+ if (pcount) *pcount = n;
return argv;
}
execv(CS argv[0], (char *const *)argv);
log_write(0,
- LOG_MAIN | ((exec_type == CEE_EXEC_EXIT)? LOG_PANIC : LOG_PANIC_DIE),
+ LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
"re-exec of exim (%s) with %s failed: %s", exim_path, argv[first_special],
strerror(errno));
}
}
+testharness_pause_ms(100); /* let child work even longer, for exec */
+
/* Parent process. Save fork() errno and close the reading end of the stdin
pipe. */
int inpfd[2], outpfd[2];
pid_t pid;
+if (is_tainted(argv[0]))
+ {
+ log_write(0, LOG_MAIN | LOG_PANIC, "Attempt to exec tainted path: '%s'", argv[0]);
+ errno = EPERM;
+ return (pid_t)(-1);
+ }
+
/* Create the pipes. */
if (pipe(inpfd) != 0) return (pid_t)(-1);