sshd -i always exiting with exit status 255

Donald Buczek buczek at molgen.mpg.de
Wed May 29 04:55:21 AEST 2024


On 5/27/24 04:17, Damien Miller wrote:
> On Fri, 24 May 2024, Donald Buczek wrote:
> 
>> Hi,
>>
>> I've created a tool which utilizes sshd to enable users to get an interactive
>> session on a Linux compute cluster. The tool submits a wrapper into the
>> cluster. This wrapper creates the listen socket on a dynamic port number,
>> accepts a connection on that socket and then calls sshd in inetd mode with
>> '-i'. Everything works fine and as intended.
>>
>> However, there is one nuisance: I've noticed that sshd always terminates with
>> exit status 255 even if the interactive session is closed normally. Because of
>> this I can't just exec() sshd from the wrapper as its last step, but need to
>> fork sshd, wait for it, ignore its exit status and exit the wrapper with exit
>> status 0 to communicate a normal exit to the cluster scheduler. This could
>> cover real and unexpected errors.
>>
>> I've used gdbserver to attach to the sshd process, so I can tell that the exit
>> status of the main (the "privileged" process?) of sshd originates in
>> mm_request_receive from the EPIPE errno check:
>>
>> void
>> mm_request_receive(int sock, struct sshbuf *m)
>> {
>>     u_char buf[4], *p = NULL;
>>     u_int msg_len;
>>     int r;
>>
>>     debug3_f("entering");
>>
>>     if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) {
>>         if (errno == EPIPE)
>>             cleanup_exit(255);
>>         fatal_f("read: %s", strerror(errno));
>>     }
>>
>> Questions:
>>
>> - Is this the expected exit point of `sshd -i` ?
>> - If so, is there a reason to return a failure exit status?
> 
> No, it's probably that nobody has checked it before. This might help:
> 
> 
> diff --git a/packet.c b/packet.c
> index beb214f99..7d02379bd 100644
> --- a/packet.c
> +++ b/packet.c
> @@ -1909,7 +1909,8 @@ sshpkt_vfatal(struct ssh *ssh, int r, const char *fmt, va_list ap)
>  		    ssh->state->server_side ? "from" : "to", remote_id);
>  	case SSH_ERR_DISCONNECTED:
>  		ssh_packet_clear_keys(ssh);
> -		logdie("Disconnected from %s", remote_id);
> +		logit("Disconnected from %s", remote_id);
> +		cleanup_exit(0);
>  	case SSH_ERR_SYSTEM_ERROR:
>  		if (errno == ECONNRESET) {
>  			ssh_packet_clear_keys(ssh);

Thanks, I've tested this patch, but it doesn't seem to fix the problem.

Isn't the process doing the ssh protocol the unprivileged one and we have the exist status from the
parent (the privileged one)? I'm not really into it. 

As described, the failure exit status is from EPIPE received by mm_request_receive.

Here's my call stack on exit:

(gdb) where
#0  __GI__exit (status=255) at ../sysdeps/unix/sysv/linux/_exit.c:27
#1  0x0000555555566afa in cleanup_exit (i=255) at sshd.c:2424
#2  0x0000555555592822 in mm_request_receive (sock=8, m=0x55555566f0f0) at monitor_wrap.c:154
#3  0x000055555558cf72 in monitor_read (ssh=0x55555566cf50, pmonitor=0x55555566ee10, ent=0x5555556589e0 <mon_dispatch_postauth20>, pent=0x0) at monitor.c:507
#4  0x000055555558c8c8 in monitor_child_postauth (ssh=0x55555566cf50, pmonitor=0x55555566ee10) at monitor.c:413
#5  0x00005555555605a1 in privsep_postauth (ssh=0x55555566cf50, authctxt=0x55555566ea20) at sshd.c:563
#6  0x00005555555662c3 in main (ac=7, av=0x55555565e2c0) at sshd.c:2266
(gdb) frame 2
#2  0x0000555555592822 in mm_request_receive (sock=8, m=0x55555566f0f0) at monitor_wrap.c:154
154				cleanup_exit(255);
(gdb) list 154
149	
150		debug3_f("entering");
151	
152		if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) {
153			if (errno == EPIPE)
154				cleanup_exit(255);
155			fatal_f("read: %s", strerror(errno));
156		}
157		msg_len = PEEK_U32(buf);
158		if (msg_len > 256 * 1024)
(gdb) 



-- 
Donald Buczek
buczek at molgen.mpg.de
Tel: +49 30 8413 1433



More information about the openssh-unix-dev mailing list