Blob Blame History Raw
diff -up ntp-4.2.6p5/ntpd/ntp_request.c.cve-2015-7977_7978 ntp-4.2.6p5/ntpd/ntp_request.c
--- ntp-4.2.6p5/ntpd/ntp_request.c.cve-2015-7977_7978	2011-12-01 03:55:17.000000000 +0100
+++ ntp-4.2.6p5/ntpd/ntp_request.c	2016-01-20 11:14:20.855586406 +0100
@@ -1730,56 +1730,143 @@ setclr_flags(
 	     	loop_config(LOOP_DRIFTCOMP, drift_comp);
 }
 
+/* There have been some issues with the restrict list processing,
+ * ranging from problems with deep recursion (resulting in stack
+ * overflows) and overfull reply buffers.
+ *
+ * To avoid this trouble the list reversal is done iteratively using a
+ * scratch pad.
+ */
+typedef struct RestrictStack RestrictStackT;
+struct RestrictStack {
+	RestrictStackT   *link;
+	size_t            fcnt;
+	const restrict_u *pres[63];
+};
+
+static size_t
+getStackSheetSize(
+	RestrictStackT *sp
+	)
+{
+	if (sp)
+		return sizeof(sp->pres)/sizeof(sp->pres[0]);
+	return 0u;
+}
+
+static int/*BOOL*/
+pushRestriction(
+	RestrictStackT  **spp,
+	const restrict_u *ptr
+	)
+{
+	RestrictStackT *sp;
+
+	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
+		/* need another sheet in the scratch pad */
+		sp = emalloc(sizeof(*sp));
+		sp->link = *spp;
+		sp->fcnt = getStackSheetSize(sp);
+		*spp = sp;
+	}
+	sp->pres[--sp->fcnt] = ptr;
+	return TRUE;
+}
+
+static int/*BOOL*/
+popRestriction(
+	RestrictStackT   **spp,
+	const restrict_u **opp
+	)
+{
+	RestrictStackT *sp;
+
+	if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize(sp))
+		return FALSE;
+	
+	*opp = sp->pres[sp->fcnt++];
+	if (sp->fcnt >= getStackSheetSize(sp)) {
+		/* discard sheet from scratch pad */
+		*spp = sp->link;
+		free(sp);
+	}
+	return TRUE;
+}
+
+static void
+flushRestrictionStack(
+	RestrictStackT **spp
+	)
+{
+	RestrictStackT *sp;
+
+	while (NULL != (sp = *spp)) {
+		*spp = sp->link;
+		free(sp);
+	}
+}
+
 /*
- * list_restrict4 - recursive helper for list_restrict dumps IPv4
+ * list_restrict4 - iterative helper for list_restrict dumps IPv4
  *		    restriction list in reverse order.
  */
 static void
 list_restrict4(
-	restrict_u *		res,
+	const restrict_u *	res,
 	struct info_restrict **	ppir
 	)
 {
+	RestrictStackT *	rpad;
 	struct info_restrict *	pir;
 
-	if (res->link != NULL)
-		list_restrict4(res->link, ppir);
-
 	pir = *ppir;
-	pir->addr = htonl(res->u.v4.addr);
-	if (client_v6_capable) 
-		pir->v6_flag = 0;
-	pir->mask = htonl(res->u.v4.mask);
-	pir->count = htonl(res->count);
-	pir->flags = htons(res->flags);
-	pir->mflags = htons(res->mflags);
-	*ppir = (struct info_restrict *)more_pkt();
+	for (rpad = NULL; res; res = res->link)
+		if (!pushRestriction(&rpad, res))
+			break;
+	
+	while (pir && popRestriction(&rpad, &res)) {
+		pir->addr = htonl(res->u.v4.addr);
+		if (client_v6_capable) 
+			pir->v6_flag = 0;
+		pir->mask = htonl(res->u.v4.mask);
+		pir->count = htonl(res->count);
+		pir->flags = htons(res->flags);
+		pir->mflags = htons(res->mflags);
+		pir = (struct info_restrict *)more_pkt();
+	}
+	flushRestrictionStack(&rpad);
+	*ppir = pir;
 }
 
-
 /*
- * list_restrict6 - recursive helper for list_restrict dumps IPv6
+ * list_restrict6 - iterative helper for list_restrict dumps IPv6
  *		    restriction list in reverse order.
  */
 static void
 list_restrict6(
-	restrict_u *		res,
+	const restrict_u *	res,
 	struct info_restrict **	ppir
 	)
 {
+	RestrictStackT *	rpad;
 	struct info_restrict *	pir;
 
-	if (res->link != NULL)
-		list_restrict6(res->link, ppir);
-
 	pir = *ppir;
-	pir->addr6 = res->u.v6.addr; 
-	pir->mask6 = res->u.v6.mask;
-	pir->v6_flag = 1;
-	pir->count = htonl(res->count);
-	pir->flags = htons(res->flags);
-	pir->mflags = htons(res->mflags);
-	*ppir = (struct info_restrict *)more_pkt();
+	for (rpad = NULL; res; res = res->link)
+		if (!pushRestriction(&rpad, res))
+			break;
+
+	while (pir && popRestriction(&rpad, &res)) {
+		pir->addr6 = res->u.v6.addr; 
+		pir->mask6 = res->u.v6.mask;
+		pir->v6_flag = 1;
+		pir->count = htonl(res->count);
+		pir->flags = htons(res->flags);
+		pir->mflags = htons(res->mflags);
+		pir = (struct info_restrict *)more_pkt();
+	}
+	flushRestrictionStack(&rpad);
+	*ppir = pir;
 }
 
 
@@ -1803,8 +1890,7 @@ list_restrict(
 	/*
 	 * The restriction lists are kept sorted in the reverse order
 	 * than they were originally.  To preserve the output semantics,
-	 * dump each list in reverse order.  A recursive helper function
-	 * achieves that.
+	 * dump each list in reverse order. The workers take care of that.
 	 */
 	list_restrict4(restrictlist4, &ir);
 	if (client_v6_capable)