View | Details | Raw Unified | Return to bug 2158 | Differences between
and this patch

Collapse All | Expand All

(-)serverloop.c (-77 / +27 lines)
Lines 84-95 extern int use_privsep; Link Here
84
84
85
static int no_more_sessions = 0; /* Disallow further sessions. */
85
static int no_more_sessions = 0; /* Disallow further sessions. */
86
86
87
/*
87
/* The child has terminated. */
88
 * This SIGCHLD kludge is used to detect when the child exits.  The server
88
static volatile sig_atomic_t child_terminated = 0;
89
 * will exit after that, as soon as forwarded connections have terminated.
90
 */
91
92
static volatile sig_atomic_t child_terminated = 0;	/* The child has terminated. */
93
89
94
/* Cleanup on signals (!use_privsep case only) */
90
/* Cleanup on signals (!use_privsep case only) */
95
static volatile sig_atomic_t received_sigterm = 0;
91
static volatile sig_atomic_t received_sigterm = 0;
Lines 111-169 bind_permitted(int port, uid_t uid) Link Here
111
	return 1;
107
	return 1;
112
}
108
}
113
109
114
/*
115
 * we write to this pipe if a SIGCHLD is caught in order to avoid
116
 * the race between select() and child_terminated
117
 */
118
static int notify_pipe[2];
119
static void
120
notify_setup(void)
121
{
122
	if (pipe(notify_pipe) == -1) {
123
		error("pipe(notify_pipe) failed %s", strerror(errno));
124
	} else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
125
	    (fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) {
126
		error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
127
		close(notify_pipe[0]);
128
		close(notify_pipe[1]);
129
	} else {
130
		set_nonblock(notify_pipe[0]);
131
		set_nonblock(notify_pipe[1]);
132
		return;
133
	}
134
	notify_pipe[0] = -1;	/* read end */
135
	notify_pipe[1] = -1;	/* write end */
136
}
137
static void
138
notify_parent(void)
139
{
140
	if (notify_pipe[1] != -1)
141
		(void)write(notify_pipe[1], "", 1);
142
}
143
static void
144
notify_prepare(fd_set *readset)
145
{
146
	if (notify_pipe[0] != -1)
147
		FD_SET(notify_pipe[0], readset);
148
}
149
static void
150
notify_done(fd_set *readset)
151
{
152
	char c;
153
154
	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
155
		while (read(notify_pipe[0], &c, 1) != -1)
156
			debug2_f("reading");
157
}
158
159
/*ARGSUSED*/
110
/*ARGSUSED*/
160
static void
111
static void
161
sigchld_handler(int sig)
112
sigchld_handler(int sig)
162
{
113
{
163
	int save_errno = errno;
164
	child_terminated = 1;
114
	child_terminated = 1;
165
	notify_parent();
166
	errno = save_errno;
167
}
115
}
168
116
169
/*ARGSUSED*/
117
/*ARGSUSED*/
Lines 207-213 client_alive_check(struct ssh *ssh) Link Here
207
}
155
}
208
156
209
/*
157
/*
210
 * Sleep in select() until we can do something.  This will initialize the
158
 * Sleep in pselect() until we can do something.  This will initialize the
211
 * select masks.  Upon return, the masks will indicate which descriptors
159
 * select masks.  Upon return, the masks will indicate which descriptors
212
 * have data or can accept data.  Optionally, a maximum time can be specified
160
 * have data or can accept data.  Optionally, a maximum time can be specified
213
 * for the duration of the wait (0 = infinite).
161
 * for the duration of the wait (0 = infinite).
Lines 216-224 static void Link Here
216
wait_until_can_do_something(struct ssh *ssh,
164
wait_until_can_do_something(struct ssh *ssh,
217
    int connection_in, int connection_out,
165
    int connection_in, int connection_out,
218
    fd_set **readsetp, fd_set **writesetp, int *maxfdp,
166
    fd_set **readsetp, fd_set **writesetp, int *maxfdp,
219
    u_int *nallocp, u_int64_t max_time_ms)
167
    u_int *nallocp, u_int64_t max_time_ms, sigset_t *sigsetp)
220
{
168
{
221
	struct timeval tv, *tvp;
169
	struct timespec ts, *tsp;
222
	int ret;
170
	int ret;
223
	time_t minwait_secs = 0;
171
	time_t minwait_secs = 0;
224
	int client_alive_scheduled = 0;
172
	int client_alive_scheduled = 0;
Lines 258-264 wait_until_can_do_something(struct ssh * Link Here
258
	if (channel_not_very_much_buffered_data())
206
	if (channel_not_very_much_buffered_data())
259
#endif
207
#endif
260
	FD_SET(connection_in, *readsetp);
208
	FD_SET(connection_in, *readsetp);
261
	notify_prepare(*readsetp);
262
209
263
	/*
210
	/*
264
	 * If we have buffered packet data going to the client, mark that
211
	 * If we have buffered packet data going to the client, mark that
Lines 276-301 wait_until_can_do_something(struct ssh * Link Here
276
			max_time_ms = 100;
223
			max_time_ms = 100;
277
224
278
	if (max_time_ms == 0)
225
	if (max_time_ms == 0)
279
		tvp = NULL;
226
		tsp = NULL;
280
	else {
227
	else {
281
		tv.tv_sec = max_time_ms / 1000;
228
		ts.tv_sec = max_time_ms / 1000;
282
		tv.tv_usec = 1000 * (max_time_ms % 1000);
229
		ts.tv_nsec = 1000000 * (max_time_ms % 1000);
283
		tvp = &tv;
230
		tsp = &ts;
284
	}
231
	}
285
232
286
	/* Wait for something to happen, or the timeout to expire. */
233
	/* Wait for something to happen, or the timeout to expire. */
287
	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
234
	ret = pselect((*maxfdp)+1, *readsetp, *writesetp, NULL, tsp, sigsetp);
288
235
289
	if (ret == -1) {
236
	if (ret == -1) {
290
		memset(*readsetp, 0, *nallocp);
237
		memset(*readsetp, 0, *nallocp);
291
		memset(*writesetp, 0, *nallocp);
238
		memset(*writesetp, 0, *nallocp);
292
		if (errno != EINTR)
239
		if (errno != EINTR)
293
			error("select: %.100s", strerror(errno));
240
			error("pselect: %.100s", strerror(errno));
294
	} else if (client_alive_scheduled) {
241
	} else if (client_alive_scheduled) {
295
		time_t now = monotime();
242
		time_t now = monotime();
296
243
297
		/*
244
		/*
298
		 * If the select timed out, or returned for some other reason
245
		 * If the pselect timed out, or returned for some other reason
299
		 * but we haven't heard from the client in time, send keepalive.
246
		 * but we haven't heard from the client in time, send keepalive.
300
		 */
247
		 */
301
		if (ret == 0 || (last_client_time != 0 && last_client_time +
248
		if (ret == 0 || (last_client_time != 0 && last_client_time +
Lines 306-313 wait_until_can_do_something(struct ssh * Link Here
306
			last_client_time = now;
253
			last_client_time = now;
307
		}
254
		}
308
	}
255
	}
309
310
	notify_done(*readsetp);
311
}
256
}
312
257
313
/*
258
/*
Lines 365-381 process_buffered_input_packets(struct ss Link Here
365
	ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, NULL);
310
	ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, NULL);
366
}
311
}
367
312
313
/*
314
 * Reap child processes.  Because we block SIGCHLD except in pselect(),
315
 * this should not be subject to races.
316
 */
368
static void
317
static void
369
collect_children(struct ssh *ssh)
318
collect_children(struct ssh *ssh)
370
{
319
{
371
	pid_t pid;
320
	pid_t pid;
372
	sigset_t oset, nset;
373
	int status;
321
	int status;
374
322
375
	/* block SIGCHLD while we check for dead children */
376
	sigemptyset(&nset);
377
	sigaddset(&nset, SIGCHLD);
378
	sigprocmask(SIG_BLOCK, &nset, &oset);
379
	if (child_terminated) {
323
	if (child_terminated) {
380
		debug("Received SIGCHLD.");
324
		debug("Received SIGCHLD.");
381
		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
325
		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
Lines 384-390 collect_children(struct ssh *ssh) Link Here
384
				session_close_by_pid(ssh, pid, status);
328
				session_close_by_pid(ssh, pid, status);
385
		child_terminated = 0;
329
		child_terminated = 0;
386
	}
330
	}
387
	sigprocmask(SIG_SETMASK, &oset, NULL);
388
}
331
}
389
332
390
void
333
void
Lines 392-404 server_loop2(struct ssh *ssh, Authctxt * Link Here
392
{
335
{
393
	fd_set *readset = NULL, *writeset = NULL;
336
	fd_set *readset = NULL, *writeset = NULL;
394
	int max_fd;
337
	int max_fd;
338
	sigset_t osigset, nsigset;
395
	u_int nalloc = 0, connection_in, connection_out;
339
	u_int nalloc = 0, connection_in, connection_out;
396
	u_int64_t rekey_timeout_ms = 0;
340
	u_int64_t rekey_timeout_ms = 0;
397
341
398
	debug("Entering interactive session for SSH2.");
342
	debug("Entering interactive session for SSH2.");
399
343
344
	/* Block CHLD/INT/TERM/QUIT except in pselect to prevent races. */
345
	sigemptyset(&nsigset);
346
	sigaddset(&nsigset, SIGCHLD);
347
	sigaddset(&nsigset, SIGINT);
348
	sigaddset(&nsigset, SIGTERM);
349
	sigaddset(&nsigset, SIGQUIT);
350
	sigprocmask(SIG_BLOCK, &nsigset, &osigset);
400
	ssh_signal(SIGCHLD, sigchld_handler);
351
	ssh_signal(SIGCHLD, sigchld_handler);
401
	child_terminated = 0;
352
	child_terminated = 0;
353
402
	connection_in = ssh_packet_get_connection_in(ssh);
354
	connection_in = ssh_packet_get_connection_in(ssh);
403
	connection_out = ssh_packet_get_connection_out(ssh);
355
	connection_out = ssh_packet_get_connection_out(ssh);
404
356
Lines 408-417 server_loop2(struct ssh *ssh, Authctxt * Link Here
408
		ssh_signal(SIGQUIT, sigterm_handler);
360
		ssh_signal(SIGQUIT, sigterm_handler);
409
	}
361
	}
410
362
411
	notify_setup();
412
413
	max_fd = MAXIMUM(connection_in, connection_out);
363
	max_fd = MAXIMUM(connection_in, connection_out);
414
	max_fd = MAXIMUM(max_fd, notify_pipe[0]);
415
364
416
	server_init_dispatch(ssh);
365
	server_init_dispatch(ssh);
417
366
Lines 430-436 server_loop2(struct ssh *ssh, Authctxt * Link Here
430
		}
379
		}
431
380
432
		wait_until_can_do_something(ssh, connection_in, connection_out,
381
		wait_until_can_do_something(ssh, connection_in, connection_out,
433
		    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
382
		    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms,
383
		    &osigset);
434
384
435
		if (received_sigterm) {
385
		if (received_sigterm) {
436
			logit("Exiting on signal %d", (int)received_sigterm);
386
			logit("Exiting on signal %d", (int)received_sigterm);
(-)sshd.c (-4 / +14 lines)
Lines 1077-1083 server_listen(void) Link Here
1077
 * from this function are in a forked subprocess.
1077
 * from this function are in a forked subprocess.
1078
 */
1078
 */
1079
static void
1079
static void
1080
server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
1080
server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
1081
    sigset_t *sigmaskp)
1081
{
1082
{
1082
	fd_set *fdset;
1083
	fd_set *fdset;
1083
	int i, j, ret, maxfd;
1084
	int i, j, ret, maxfd;
Lines 1131-1139 server_accept_loop(int *sock_in, int *so Link Here
1131
				FD_SET(startup_pipes[i], fdset);
1132
				FD_SET(startup_pipes[i], fdset);
1132
1133
1133
		/* Wait in select until there is a connection. */
1134
		/* Wait in select until there is a connection. */
1134
		ret = select(maxfd+1, fdset, NULL, NULL, NULL);
1135
		ret = pselect(maxfd+1, fdset, NULL, NULL, NULL, sigmaskp);
1135
		if (ret == -1 && errno != EINTR)
1136
		if (ret == -1 && errno != EINTR)
1136
			error("select: %.100s", strerror(errno));
1137
			error("pselect: %.100s", strerror(errno));
1137
		if (received_sigterm) {
1138
		if (received_sigterm) {
1138
			logit("Received signal %d; terminating.",
1139
			logit("Received signal %d; terminating.",
1139
			    (int) received_sigterm);
1140
			    (int) received_sigterm);
Lines 1440-1445 main(int ac, char **av) Link Here
1440
	int keytype;
1441
	int keytype;
1441
	Authctxt *authctxt;
1442
	Authctxt *authctxt;
1442
	struct connection_info *connection_info = NULL;
1443
	struct connection_info *connection_info = NULL;
1444
	sigset_t nsigset, osigset;
1443
1445
1444
	/* Save argv. */
1446
	/* Save argv. */
1445
	saved_argv = av;
1447
	saved_argv = av;
Lines 1897-1902 main(int ac, char **av) Link Here
1897
	} else {
1899
	} else {
1898
		server_listen();
1900
		server_listen();
1899
1901
1902
		/* Block signals except when in pselect to prevent races. */
1903
		sigemptyset(&nsigset);
1904
		sigaddset(&nsigset, SIGCHLD);
1905
		sigaddset(&nsigset, SIGHUP);
1906
		sigaddset(&nsigset, SIGTERM);
1907
		sigaddset(&nsigset, SIGQUIT);
1908
		sigprocmask(SIG_BLOCK, &nsigset, &osigset);	
1900
		ssh_signal(SIGHUP, sighup_handler);
1909
		ssh_signal(SIGHUP, sighup_handler);
1901
		ssh_signal(SIGCHLD, main_sigchld_handler);
1910
		ssh_signal(SIGCHLD, main_sigchld_handler);
1902
		ssh_signal(SIGTERM, sigterm_handler);
1911
		ssh_signal(SIGTERM, sigterm_handler);
Lines 1920-1929 main(int ac, char **av) Link Here
1920
1929
1921
		/* Accept a connection and return in a forked child */
1930
		/* Accept a connection and return in a forked child */
1922
		server_accept_loop(&sock_in, &sock_out,
1931
		server_accept_loop(&sock_in, &sock_out,
1923
		    &newsock, config_s);
1932
		    &newsock, config_s, &osigset);
1924
	}
1933
	}
1925
1934
1926
	/* This is the child processing a new connection. */
1935
	/* This is the child processing a new connection. */
1936
	sigprocmask(SIG_SETMASK, &osigset, NULL);
1927
	setproctitle("%s", "[accepted]");
1937
	setproctitle("%s", "[accepted]");
1928
1938
1929
	/*
1939
	/*

Return to bug 2158