DragonFlyBSD Kernel Audit
DF-0671 / fix.diff
← back to finding ↓ download raw
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;