Bug 2509 - Unexpected change in tcpip-forward reply message in OpenSSH 6.8
Summary: Unexpected change in tcpip-forward reply message in OpenSSH 6.8
Status: CLOSED FIXED
Alias: None
Product: Portable OpenSSH
Classification: Unclassified
Component: sshd (show other bugs)
Version: 6.8p1
Hardware: All All
: P5 major
Assignee: Assigned to nobody
URL:
Keywords:
Depends on:
Blocks: V_7_2
  Show dependency treegraph
 
Reported: 2015-11-27 11:20 AEDT by Ron Frederick
Modified: 2016-08-02 10:42 AEST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ron Frederick 2015-11-27 11:20:17 AEDT
Today I tested my AsyncSSH client against OpenSSH 7.1 and noticed that it had a problem with the reply message coming back from tcpip-forward. After a bit of digging, I tracked down the change to OpenSSH 6.8 which I think was part of the fix for bz#2147.

According to the OpenSSH spec:

   If a client passes 0 as port number to bind and has 'want reply' as
   TRUE, then the server allocates the next available unprivileged port
   number and replies with the following message; otherwise, there is no
   response-specific data.

      byte     SSH_MSG_REQUEST_SUCCESS
      uint32   port that was bound on the server

OpenSSH 6.7 honors this, with there being no response-specific data in the case where a non-zero port number is requested. The associated code for this in server_input_global_request() in server loop.c is:

        if (want_reply) {
                packet_start(success ?
                    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
                if (success && allocated_listen_port > 0)
                        packet_put_int(allocated_listen_port);
                packet_send();
                packet_write_wait();
        }

Note the test for "allocated_listen_port > 0". However, the new code in OpenSSH 6.8 does the following:

                if ((r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
                        fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r));

and then later uses this "resp" buffer to create the response packet. It puts the allocated_listen_port into the response unconditionally, and so the end result is that requests for a non-zero port number actually end up getting back a uint32 with a zero value in the response instead of no data. This is causing a problem for AsyncSSH, as it validates that there's no unexpected data at the end of the reply packet, expecting this value only when it passes a port number of 0 in the request.

Since I only noticed this now and it's present in OpenSSH 6.8, 6.9, 7.0, and 7.1, I'm probably going to need to relax my check and allow this value to be ignored, at least for the affected OpenSSH versions. However, I think this should be fixed to match the spec and omit the port in the reply when a dynamic port is not allocated.
Comment 1 Damien Miller 2015-11-28 18:25:20 AEDT
Thanks for the detailed report, I've just committed a fix for OpenSSH 7.2

https://anongit.mindrot.org/openssh.git/commit/?id=b1d6b3971ef256a08692efc409fc9ada719111cc
Comment 2 Damien Miller 2016-08-02 10:42:25 AEST
Close all resolved bugs after 7.3p1 release