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

Collapse All | Expand All

(-)serverloop.c (-79 / +26 lines)
Lines 84-94 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
/*
88
 * This SIGCHLD kludge is used to detect when the child exits.  The server
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. */
87
static volatile sig_atomic_t child_terminated = 0;	/* The child has terminated. */
93
88
94
/* Cleanup on signals (!use_privsep case only) */
89
/* Cleanup on signals (!use_privsep case only) */
Lines 111-169 bind_permitted(int port, uid_t uid) Link Here
111
	return 1;
106
	return 1;
112
}
107
}
113
108
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*/
109
/*ARGSUSED*/
160
static void
110
static void
161
sigchld_handler(int sig)
111
sigchld_handler(int sig)
162
{
112
{
163
	int save_errno = errno;
164
	child_terminated = 1;
113
	child_terminated = 1;
165
	notify_parent();
166
	errno = save_errno;
167
}
114
}
168
115
169
/*ARGSUSED*/
116
/*ARGSUSED*/
Lines 207-214 client_alive_check(struct ssh *ssh) Link Here
207
}
154
}
208
155
209
/*
156
/*
210
 * Sleep in select() until we can do something.  This will initialize the
157
 * Sleep in pselect() until we can do something.  This will initialize the
211
 * select masks.  Upon return, the masks will indicate which descriptors
158
 * pselect masks.  Upon return, the masks will indicate which descriptors
212
 * have data or can accept data.  Optionally, a maximum time can be specified
159
 * have data or can accept data.  Optionally, a maximum time can be specified
213
 * for the duration of the wait (0 = infinite).
160
 * for the duration of the wait (0 = infinite).
214
 */
161
 */
Lines 216-231 static void Link Here
216
wait_until_can_do_something(struct ssh *ssh,
163
wait_until_can_do_something(struct ssh *ssh,
217
    int connection_in, int connection_out,
164
    int connection_in, int connection_out,
218
    fd_set **readsetp, fd_set **writesetp, int *maxfdp,
165
    fd_set **readsetp, fd_set **writesetp, int *maxfdp,
219
    u_int *nallocp, u_int64_t max_time_ms)
166
    u_int *nallocp, u_int64_t max_time_ms, sigset_t *sigsetp)
220
{
167
{
221
	struct timeval tv, *tvp;
168
	struct timespec ts, *tsp;
222
	int ret;
169
	int ret;
223
	time_t minwait_secs = 0;
170
	time_t minwait_secs = 0;
224
	int client_alive_scheduled = 0;
171
	int client_alive_scheduled = 0;
225
	/* time we last heard from the client OR sent a keepalive */
172
	/* time we last heard from the client OR sent a keepalive */
226
	static time_t last_client_time;
173
	static time_t last_client_time;
227
174
228
	/* Allocate and update select() masks for channel descriptors. */
175
	/* Allocate and update pselect() masks for channel descriptors. */
229
	channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
176
	channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
230
	    nallocp, &minwait_secs);
177
	    nallocp, &minwait_secs);
231
178
Lines 258-264 wait_until_can_do_something(struct ssh * Link Here
258
	if (channel_not_very_much_buffered_data())
205
	if (channel_not_very_much_buffered_data())
259
#endif
206
#endif
260
	FD_SET(connection_in, *readsetp);
207
	FD_SET(connection_in, *readsetp);
261
	notify_prepare(*readsetp);
262
208
263
	/*
209
	/*
264
	 * If we have buffered packet data going to the client, mark that
210
	 * 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;
222
			max_time_ms = 100;
277
223
278
	if (max_time_ms == 0)
224
	if (max_time_ms == 0)
279
		tvp = NULL;
225
		tsp = NULL;
280
	else {
226
	else {
281
		tv.tv_sec = max_time_ms / 1000;
227
		ts.tv_sec = max_time_ms / 1000;
282
		tv.tv_usec = 1000 * (max_time_ms % 1000);
228
		ts.tv_nsec = 1000000 * (max_time_ms % 1000);
283
		tvp = &tv;
229
		tsp = &ts;
284
	}
230
	}
285
231
286
	/* Wait for something to happen, or the timeout to expire. */
232
	/* Wait for something to happen, or the timeout to expire. */
287
	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
233
	ret = pselect((*maxfdp)+1, *readsetp, *writesetp, NULL, tsp, sigsetp);
288
234
289
	if (ret == -1) {
235
	if (ret == -1) {
290
		memset(*readsetp, 0, *nallocp);
236
		memset(*readsetp, 0, *nallocp);
291
		memset(*writesetp, 0, *nallocp);
237
		memset(*writesetp, 0, *nallocp);
292
		if (errno != EINTR)
238
		if (errno != EINTR)
293
			error("select: %.100s", strerror(errno));
239
			error("pselect: %.100s", strerror(errno));
294
	} else if (client_alive_scheduled) {
240
	} else if (client_alive_scheduled) {
295
		time_t now = monotime();
241
		time_t now = monotime();
296
242
297
		/*
243
		/*
298
		 * If the select timed out, or returned for some other reason
244
		 * If the pselect timed out, or returned for some other reason
299
		 * but we haven't heard from the client in time, send keepalive.
245
		 * but we haven't heard from the client in time, send keepalive.
300
		 */
246
		 */
301
		if (ret == 0 || (last_client_time != 0 && last_client_time +
247
		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;
252
			last_client_time = now;
307
		}
253
		}
308
	}
254
	}
309
310
	notify_done(*readsetp);
311
}
255
}
312
256
313
/*
257
/*
Lines 369-381 static void Link Here
369
collect_children(struct ssh *ssh)
313
collect_children(struct ssh *ssh)
370
{
314
{
371
	pid_t pid;
315
	pid_t pid;
372
	sigset_t oset, nset;
373
	int status;
316
	int status;
374
317
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) {
318
	if (child_terminated) {
380
		debug("Received SIGCHLD.");
319
		debug("Received SIGCHLD.");
381
		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
320
		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);
323
				session_close_by_pid(ssh, pid, status);
385
		child_terminated = 0;
324
		child_terminated = 0;
386
	}
325
	}
387
	sigprocmask(SIG_SETMASK, &oset, NULL);
388
}
326
}
389
327
390
void
328
void
Lines 394-404 server_loop2(struct ssh *ssh, Authctxt * Link Here
394
	int max_fd;
332
	int max_fd;
395
	u_int nalloc = 0, connection_in, connection_out;
333
	u_int nalloc = 0, connection_in, connection_out;
396
	u_int64_t rekey_timeout_ms = 0;
334
	u_int64_t rekey_timeout_ms = 0;
335
	sigset_t blocksigset, osigset;
397
336
398
	debug("Entering interactive session for SSH2.");
337
	debug("Entering interactive session for SSH2.");
399
338
339
	sigemptyset(&blocksigset);
340
	sigaddset(&blocksigset, SIGCHLD);
400
	ssh_signal(SIGCHLD, sigchld_handler);
341
	ssh_signal(SIGCHLD, sigchld_handler);
401
	child_terminated = 0;
342
	child_terminated = 0;
343
402
	connection_in = ssh_packet_get_connection_in(ssh);
344
	connection_in = ssh_packet_get_connection_in(ssh);
403
	connection_out = ssh_packet_get_connection_out(ssh);
345
	connection_out = ssh_packet_get_connection_out(ssh);
404
346
Lines 408-417 server_loop2(struct ssh *ssh, Authctxt * Link Here
408
		ssh_signal(SIGQUIT, sigterm_handler);
350
		ssh_signal(SIGQUIT, sigterm_handler);
409
	}
351
	}
410
352
411
	notify_setup();
412
413
	max_fd = MAXIMUM(connection_in, connection_out);
353
	max_fd = MAXIMUM(connection_in, connection_out);
414
	max_fd = MAXIMUM(max_fd, notify_pipe[0]);
415
354
416
	server_init_dispatch(ssh);
355
	server_init_dispatch(ssh);
417
356
Lines 429-436 server_loop2(struct ssh *ssh, Authctxt * Link Here
429
			rekey_timeout_ms = 0;
368
			rekey_timeout_ms = 0;
430
		}
369
		}
431
370
371
		/*
372
		 * Block SIGCHLD while we check for dead children, then pass
373
		 * the old signal mask through to pselect() so that it'll wake
374
		 * up immediately if a child exits after we've called waitpid().
375
		 */
376
		sigprocmask(SIG_BLOCK, &blocksigset, &osigset);
377
		collect_children(ssh);
432
		wait_until_can_do_something(ssh, connection_in, connection_out,
378
		wait_until_can_do_something(ssh, connection_in, connection_out,
433
		    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
379
		    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms,
380
		    &osigset);
381
		sigprocmask(SIG_SETMASK, &osigset, NULL);
434
382
435
		if (received_sigterm) {
383
		if (received_sigterm) {
436
			logit("Exiting on signal %d", (int)received_sigterm);
384
			logit("Exiting on signal %d", (int)received_sigterm);
Lines 438-444 server_loop2(struct ssh *ssh, Authctxt * Link Here
438
			cleanup_exit(255);
386
			cleanup_exit(255);
439
		}
387
		}
440
388
441
		collect_children(ssh);
442
		if (!ssh_packet_is_rekeying(ssh))
389
		if (!ssh_packet_is_rekeying(ssh))
443
			channel_after_select(ssh, readset, writeset);
390
			channel_after_select(ssh, readset, writeset);
444
		if (process_input(ssh, readset, connection_in) < 0)
391
		if (process_input(ssh, readset, connection_in) < 0)
(-)sshd.c (-3 / +17 lines)
Lines 1087-1092 server_accept_loop(int *sock_in, int *so Link Here
1087
	struct sockaddr_storage from;
1087
	struct sockaddr_storage from;
1088
	socklen_t fromlen;
1088
	socklen_t fromlen;
1089
	pid_t pid;
1089
	pid_t pid;
1090
	sigset_t nsigset, osigset;
1090
1091
1091
	/* setup fd set for accept */
1092
	/* setup fd set for accept */
1092
	fdset = NULL;
1093
	fdset = NULL;
Lines 1101-1106 server_accept_loop(int *sock_in, int *so Link Here
1101
		startup_pipes[i] = -1;
1102
		startup_pipes[i] = -1;
1102
1103
1103
	/*
1104
	/*
1105
	 * Block signals except when in pselect.  This guarantees that we
1106
	 * will wake up if a signal would have been received after we check
1107
	 * the corresponding flag.
1108
	 */
1109
	sigemptyset(&nsigset);
1110
	sigaddset(&nsigset, SIGHUP);
1111
	sigaddset(&nsigset, SIGCHLD);
1112
	sigaddset(&nsigset, SIGTERM);
1113
	sigaddset(&nsigset, SIGQUIT);
1114
	sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1115
1116
	/*
1104
	 * Stay listening for connections until the system crashes or
1117
	 * Stay listening for connections until the system crashes or
1105
	 * the daemon is killed with a signal.
1118
	 * the daemon is killed with a signal.
1106
	 */
1119
	 */
Lines 1130-1139 server_accept_loop(int *sock_in, int *so Link Here
1130
			if (startup_pipes[i] != -1)
1143
			if (startup_pipes[i] != -1)
1131
				FD_SET(startup_pipes[i], fdset);
1144
				FD_SET(startup_pipes[i], fdset);
1132
1145
1133
		/* Wait in select until there is a connection. */
1146
		/* Wait until a connection arrives or a child exits. */
1134
		ret = select(maxfd+1, fdset, NULL, NULL, NULL);
1147
		ret = pselect(maxfd+1, fdset, NULL, NULL, NULL, &osigset);
1135
		if (ret == -1 && errno != EINTR)
1148
		if (ret == -1 && errno != EINTR)
1136
			error("select: %.100s", strerror(errno));
1149
			error("pselect: %.100s", strerror(errno));
1137
		if (received_sigterm) {
1150
		if (received_sigterm) {
1138
			logit("Received signal %d; terminating.",
1151
			logit("Received signal %d; terminating.",
1139
			    (int) received_sigterm);
1152
			    (int) received_sigterm);
Lines 1226-1231 server_accept_loop(int *sock_in, int *so Link Here
1226
			 * Got connection.  Fork a child to handle it, unless
1239
			 * Got connection.  Fork a child to handle it, unless
1227
			 * we are in debugging mode.
1240
			 * we are in debugging mode.
1228
			 */
1241
			 */
1242
			sigprocmask(SIG_SETMASK, &osigset, NULL);
1229
			if (debug_flag) {
1243
			if (debug_flag) {
1230
				/*
1244
				/*
1231
				 * In debugging mode.  Close the listening
1245
				 * In debugging mode.  Close the listening

Return to bug 2158