unix/stream: provide uipc_cantrcvmore()
and use it the pr_shutdown method. While unix/dgram can still use generic socket socantrcvmore(), the stream versions need a specific one. This fixes a panic reported by syzkaller. While here inline unp_shutdown() into uipc_shutdown(). Reported-by: syzbot+86c18f0886f70a3509c6@syzkaller.appspotmail.com
This commit is contained in:
+28
-24
@@ -299,7 +299,6 @@ static int unp_connectat(int, struct socket *, struct sockaddr *,
|
||||
static void unp_connect2(struct socket *, struct socket *, bool);
|
||||
static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2);
|
||||
static void unp_dispose(struct socket *so);
|
||||
static void unp_shutdown(struct unpcb *);
|
||||
static void unp_drop(struct unpcb *);
|
||||
static void unp_gc(__unused void *, int);
|
||||
static void unp_scan(struct mbuf *, void (*)(struct filedescent **, int));
|
||||
@@ -1341,6 +1340,18 @@ uipc_wakeup(struct socket *so)
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
}
|
||||
|
||||
static void
|
||||
uipc_cantrcvmore(struct socket *so)
|
||||
{
|
||||
|
||||
SOCK_RECVBUF_LOCK(so);
|
||||
so->so_rcv.sb_state |= SBS_CANTRCVMORE;
|
||||
if (so->so_rcv.uxst_peer != NULL)
|
||||
uipc_wakeup(so);
|
||||
else
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
}
|
||||
|
||||
static int
|
||||
uipc_soreceive_stream_or_seqpacket(struct socket *so, struct sockaddr **psa,
|
||||
struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
|
||||
@@ -2646,18 +2657,28 @@ uipc_shutdown(struct socket *so, enum shutdown_how how)
|
||||
|
||||
switch (how) {
|
||||
case SHUT_RD:
|
||||
socantrcvmore(so);
|
||||
if (so->so_type == SOCK_DGRAM)
|
||||
socantrcvmore(so);
|
||||
else
|
||||
uipc_cantrcvmore(so);
|
||||
unp_dispose(so);
|
||||
break;
|
||||
case SHUT_RDWR:
|
||||
socantrcvmore(so);
|
||||
if (so->so_type == SOCK_DGRAM)
|
||||
socantrcvmore(so);
|
||||
else
|
||||
uipc_cantrcvmore(so);
|
||||
unp_dispose(so);
|
||||
/* FALLTHROUGH */
|
||||
case SHUT_WR:
|
||||
UNP_PCB_LOCK(unp);
|
||||
socantsendmore(so);
|
||||
unp_shutdown(unp);
|
||||
UNP_PCB_UNLOCK(unp);
|
||||
if (so->so_type == SOCK_DGRAM) {
|
||||
socantsendmore(so);
|
||||
} else {
|
||||
UNP_PCB_LOCK(unp);
|
||||
if (unp->unp_conn != NULL)
|
||||
uipc_cantrcvmore(unp->unp_conn->unp_socket);
|
||||
UNP_PCB_UNLOCK(unp);
|
||||
}
|
||||
}
|
||||
wakeup(&so->so_timeo);
|
||||
|
||||
@@ -3380,23 +3401,6 @@ SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist,
|
||||
(void *)(intptr_t)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb",
|
||||
"List of active local seqpacket sockets");
|
||||
|
||||
static void
|
||||
unp_shutdown(struct unpcb *unp)
|
||||
{
|
||||
struct unpcb *unp2;
|
||||
struct socket *so;
|
||||
|
||||
UNP_PCB_LOCK_ASSERT(unp);
|
||||
|
||||
unp2 = unp->unp_conn;
|
||||
if ((unp->unp_socket->so_type == SOCK_STREAM ||
|
||||
(unp->unp_socket->so_type == SOCK_SEQPACKET)) && unp2 != NULL) {
|
||||
so = unp2->unp_socket;
|
||||
if (so != NULL)
|
||||
socantrcvmore(so);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unp_drop(struct unpcb *unp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user