Re: unix_stream_connect and socket address resolution
David Laight <[email protected]> Wed, 22 Jul 2026 11:05:22 +0100
| Newsgroups | org.kernel.vger.linux-security-module,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <20260722110522.710ced10@pumpkin> |
On Tue, 21 Jul 2026 16:37:07 -0400 "John Ericson" <[email protected]> wrote: > In case this is useful or interesting to anyone, I deep a some history > spelunking, and the restart logic in question seems to date back to > Import 2.2.4pre6: > > https://github.com/tbodt/linux-history/commit/7d4fc34b9bbc0a14d3e5f6b2f978373422e1ca8a#diff-0553d076c243e06ae312480cb8cb52f1cebe1d80fc099d3842593e12c9e0d4f3 > > --- > @@ -673,9 +703,25 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, > we will have to recheck all again in any case. > */ > > +restart: > /* Find listening sock */ > other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err); > > + if (!other) > + return -ECONNREFUSED; > + > + while (other->ack_backlog >= other->max_ack_backlog) { > + unix_unlock(other); This unlocks the socket - I doubt it makes sense to sleep with it locked. > + if (other->dead || other->state != TCP_LISTEN) > + return -ECONNREFUSED; Those look like potential UAF. Hopefully changed in the current code! > + if (flags & O_NONBLOCK) > + return -EAGAIN; > + interruptible_sleep_on(&unix_ack_wqueue); > + if (signal_pending(current)) > + return -ERESTARTSYS; > + goto restart; Since 'other' was unlocked the search must be repated. David > + } > + > /* create new sock for complete connection */ > newsk = unix_create1(NULL, 1); > > @@ -704,7 +750,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, > > /* Check that listener is in valid state. */ > err = -ECONNREFUSED; > - if (other == NULL || other->dead || other->state != TCP_LISTEN) > + if (other->dead || other->state != TCP_LISTEN) > goto out; > > err = -ENOMEM; > --- > > My question can be basically restated: why should the `restart` label > not go *after* the `unix_find_other` call? > > Cheers, > > John >