* 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. */
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 + 19) * 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. */
process is placed
wd if not NULL, a path to be handed to chdir() in the new process
make_leader if TRUE, make the new process a process group leader
+ purpose for debug: reason for running the task
Returns: the pid of the created process or -1 if anything has gone wrong
*/
pid_t
child_open_uid(const uschar **argv, const uschar **envp, int newumask,
uid_t *newuid, gid_t *newgid, int *infdptr, int *outfdptr, uschar *wd,
- BOOL make_leader)
+ BOOL make_leader, const uschar * purpose)
{
int save_errno;
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);
otherwise. Save the old state for resetting on the wait. */
oldsignal = signal(SIGCHLD, SIG_DFL);
-pid = exim_fork(US"child-open");
+pid = exim_fork(purpose);
/* Handle the child process. First, set the required environment. We must do
this before messing with the pipes, in order to be able to write debugging
outfdptr pointer to int into which the fd of the stdout/stderr of the new
process is placed
make_leader if TRUE, make the new process a process group leader
+ purpose for debug: reason for running the task
Returns: the pid of the created process or -1 if anything has gone wrong
*/
pid_t
-child_open(uschar **argv, uschar **envp, int newumask, int *infdptr,
- int *outfdptr, BOOL make_leader)
+child_open_function(uschar **argv, uschar **envp, int newumask, int *infdptr,
+ int *outfdptr, BOOL make_leader, const uschar * purpose)
{
return child_open_uid(CUSS argv, CUSS envp, newumask, NULL, NULL,
- infdptr, outfdptr, NULL, make_leader);
+ infdptr, outfdptr, NULL, make_leader, purpose);
}