diff --git a/sys/netproto/smb/smb_trantcp.c b/sys/netproto/smb/smb_trantcp.c --- a/sys/netproto/smb/smb_trantcp.c +++ b/sys/netproto/smb/smb_trantcp.c @@ -198,7 +198,7 @@ } static int -nbssn_rq_request(struct nbpcb *nbp, struct thread *td) +nbssn_rq_request(struct nbpcb *nbp, struct thread *td, int depth) { struct mbchain mb, *mbp = &mb; struct mdchain md, *mdp = &md; @@ -208,6 +208,14 @@ u_int8_t rpcode; int error, rplen, res; + /* Bound the NetBIOS session retarget recursion. NBNS_MAXREDIRECTS=3 is + * defined in netbios.h but was never enforced; without this a malicious + * SMB server that always answers NB_SSN_RTGRESP drives this function + * into unbounded self-recursion (the recursive call below) and overflows + * the 16KB lwkt stack. */ + if (depth >= NBNS_MAXREDIRECTS) + return ECONNREFUSED; + error = mb_init(mbp); if (error) return error; @@ -255,6 +263,12 @@ error = ECONNABORTED; break; } + /* Initialize the retarget sockaddr fully: the original code set only + * sin_addr/sin_port, leaving sin_len/sin_family as stack garbage, + * which made the retarget connect fail EAFNOSUPPORT (in_pcb.c). */ + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); md_get_uint16(mdp, &port); sin.sin_port = port; @@ -262,7 +276,7 @@ smb_nbst_disconnect(nbp->nbp_vc, td); error = nb_connect_in(nbp, &sin, td); if (!error) - error = nbssn_rq_request(nbp, td); + error = nbssn_rq_request(nbp, td, depth + 1); if (error) { smb_nbst_disconnect(nbp->nbp_vc, td); break; @@ -481,7 +495,7 @@ timespecadd(&ts2, &ts2, &nbp->nbp_timo); timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); /* * 4 */ - error = nbssn_rq_request(nbp, td); + error = nbssn_rq_request(nbp, td, 0); if (error) smb_nbst_disconnect(vcp, td); return error;