mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Block signals between forking and clearing signal handlers (or calling
event_reinit) - if the child gets a signal and fires the libevent signal handler during this period it could write a signal into the parent's signal pipe. GitHub issue 1001 from Aaron van Geffen.
This commit is contained in:
		@@ -22,6 +22,7 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <paths.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
@@ -62,6 +63,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
 | 
			
		||||
	char			*cmd;
 | 
			
		||||
	int			 old_fd, pipe_fd[2], null_fd;
 | 
			
		||||
	struct format_tree	*ft;
 | 
			
		||||
	sigset_t		 set, oldset;
 | 
			
		||||
 | 
			
		||||
	/* Destroy the old pipe. */
 | 
			
		||||
	old_fd = wp->pipe_fd;
 | 
			
		||||
@@ -102,16 +104,20 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
 | 
			
		||||
	format_free(ft);
 | 
			
		||||
 | 
			
		||||
	/* Fork the child. */
 | 
			
		||||
	sigfillset(&set);
 | 
			
		||||
	sigprocmask(SIG_BLOCK, &set, &oldset);
 | 
			
		||||
	switch (fork()) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		cmdq_error(item, "fork error: %s", strerror(errno));
 | 
			
		||||
 | 
			
		||||
		free(cmd);
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	case 0:
 | 
			
		||||
		/* Child process. */
 | 
			
		||||
		close(pipe_fd[0]);
 | 
			
		||||
		proc_clear_signals(server_proc);
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		close(pipe_fd[0]);
 | 
			
		||||
 | 
			
		||||
		if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
 | 
			
		||||
			_exit(1);
 | 
			
		||||
@@ -132,6 +138,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
 | 
			
		||||
		_exit(1);
 | 
			
		||||
	default:
 | 
			
		||||
		/* Parent process. */
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		close(pipe_fd[1]);
 | 
			
		||||
 | 
			
		||||
		wp->pipe_fd = pipe_fd[0];
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								job.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								job.c
									
									
									
									
									
								
							@@ -51,6 +51,7 @@ job_run(const char *cmd, struct session *s, const char *cwd,
 | 
			
		||||
	pid_t		 pid;
 | 
			
		||||
	int		 nullfd, out[2];
 | 
			
		||||
	const char	*home;
 | 
			
		||||
	sigset_t	 set, oldset;
 | 
			
		||||
 | 
			
		||||
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
@@ -61,14 +62,18 @@ job_run(const char *cmd, struct session *s, const char *cwd,
 | 
			
		||||
	 */
 | 
			
		||||
	env = environ_for_session(s, !cfg_finished);
 | 
			
		||||
 | 
			
		||||
	sigfillset(&set);
 | 
			
		||||
	sigprocmask(SIG_BLOCK, &set, &oldset);
 | 
			
		||||
	switch (pid = fork()) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		environ_free(env);
 | 
			
		||||
		close(out[0]);
 | 
			
		||||
		close(out[1]);
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	case 0:		/* child */
 | 
			
		||||
	case 0:
 | 
			
		||||
		proc_clear_signals(server_proc);
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
 | 
			
		||||
		if (cwd == NULL || chdir(cwd) != 0) {
 | 
			
		||||
			if ((home = find_home()) == NULL || chdir(home) != 0)
 | 
			
		||||
@@ -100,7 +105,7 @@ job_run(const char *cmd, struct session *s, const char *cwd,
 | 
			
		||||
		fatal("execl failed");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* parent */
 | 
			
		||||
	sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
	environ_free(env);
 | 
			
		||||
	close(out[1]);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								server.c
									
									
									
									
									
								
							@@ -141,21 +141,24 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
 | 
			
		||||
{
 | 
			
		||||
	int		 pair[2];
 | 
			
		||||
	struct job	*job;
 | 
			
		||||
	sigset_t	 set, oldset;
 | 
			
		||||
 | 
			
		||||
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
 | 
			
		||||
		fatal("socketpair failed");
 | 
			
		||||
 | 
			
		||||
	sigfillset(&set);
 | 
			
		||||
	sigprocmask(SIG_BLOCK, &set, &oldset);
 | 
			
		||||
	switch (fork()) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		fatal("fork failed");
 | 
			
		||||
	case 0:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		close(pair[1]);
 | 
			
		||||
		return (pair[0]);
 | 
			
		||||
	}
 | 
			
		||||
	close(pair[0]);
 | 
			
		||||
 | 
			
		||||
	if (daemon(1, 0) != 0)
 | 
			
		||||
		fatal("daemon failed");
 | 
			
		||||
	proc_clear_signals(client);
 | 
			
		||||
@@ -163,6 +166,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
 | 
			
		||||
		fatalx("event_reinit failed");
 | 
			
		||||
	server_proc = proc_start("server");
 | 
			
		||||
	proc_set_signals(server_proc, server_signal);
 | 
			
		||||
	sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
 | 
			
		||||
	if (log_get_level() > 1)
 | 
			
		||||
		tty_create_log();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								window.c
									
									
									
									
									
								
							@@ -22,6 +22,7 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <fnmatch.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@@ -886,6 +887,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
 | 
			
		||||
	const char	*ptr, *first, *home;
 | 
			
		||||
	struct termios	 tio2;
 | 
			
		||||
	int		 i;
 | 
			
		||||
	sigset_t	 set, oldset;
 | 
			
		||||
 | 
			
		||||
	if (wp->fd != -1) {
 | 
			
		||||
		bufferevent_free(wp->event);
 | 
			
		||||
@@ -915,14 +917,21 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
 | 
			
		||||
	ws.ws_col = screen_size_x(&wp->base);
 | 
			
		||||
	ws.ws_row = screen_size_y(&wp->base);
 | 
			
		||||
 | 
			
		||||
	wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws);
 | 
			
		||||
	switch (wp->pid) {
 | 
			
		||||
	sigfillset(&set);
 | 
			
		||||
	sigprocmask(SIG_BLOCK, &set, &oldset);
 | 
			
		||||
	switch (wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws)) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		wp->fd = -1;
 | 
			
		||||
 | 
			
		||||
		xasprintf(cause, "%s: %s", cmd, strerror(errno));
 | 
			
		||||
		free(cmd);
 | 
			
		||||
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
		return (-1);
 | 
			
		||||
	case 0:
 | 
			
		||||
		proc_clear_signals(server_proc);
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
 | 
			
		||||
		if (chdir(wp->cwd) != 0) {
 | 
			
		||||
			if ((home = find_home()) == NULL || chdir(home) != 0)
 | 
			
		||||
				chdir("/");
 | 
			
		||||
@@ -936,6 +945,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
 | 
			
		||||
		if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
 | 
			
		||||
			fatal("tcgetattr failed");
 | 
			
		||||
 | 
			
		||||
		log_close();
 | 
			
		||||
		closefrom(STDERR_FILENO + 1);
 | 
			
		||||
 | 
			
		||||
		if (path != NULL)
 | 
			
		||||
@@ -943,9 +953,6 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
 | 
			
		||||
		environ_set(env, "TMUX_PANE", "%%%u", wp->id);
 | 
			
		||||
		environ_push(env);
 | 
			
		||||
 | 
			
		||||
		proc_clear_signals(server_proc);
 | 
			
		||||
		log_close();
 | 
			
		||||
 | 
			
		||||
		setenv("SHELL", wp->shell, 1);
 | 
			
		||||
		ptr = strrchr(wp->shell, '/');
 | 
			
		||||
 | 
			
		||||
@@ -978,6 +985,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
 | 
			
		||||
		fatal("execl failed");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sigprocmask(SIG_SETMASK, &oldset, NULL);
 | 
			
		||||
	setblocking(wp->fd, 0);
 | 
			
		||||
 | 
			
		||||
	wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user