nis: Fix stack overflow (stack exhaustion) in yp_all (bug 34528)

Message ID lhupkzhdqum.fsf@oldenburg.str.redhat.com (mailing list archive)
State Under Review
Delegated to: Carlos O'Donell
Headers
Series nis: Fix stack overflow (stack exhaustion) in yp_all (bug 34528) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed

Commit Message

Florian Weimer Aug. 17, 2026, 9:43 a.m. UTC
  The fix relies on the XDRMAXRECORD limit imposed in yp_xdr.c.
The bug was present from the beginning.

---
 nis/ypclnt.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)


base-commit: 6144ef08960e1db191db2054abef02d361042018
  

Patch

diff --git a/nis/ypclnt.c b/nis/ypclnt.c
index 455d80df1f..83bafb5151 100644
--- a/nis/ypclnt.c
+++ b/nis/ypclnt.c
@@ -685,23 +685,36 @@  __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
 	{
 	case YP_TRUE:
 	  {
-	    char key[resp.ypresp_all_u.val.key.keydat_len + 1];
-	    char val[resp.ypresp_all_u.val.val.valdat_len + 1];
-	    int keylen = resp.ypresp_all_u.val.key.keydat_len;
-	    int vallen = resp.ypresp_all_u.val.val.valdat_len;
 
 	    /* We are not allowed to modify the key and val data.
 	       But we are allowed to add data behind the buffer,
 	       if we don't modify the length. So add an extra NUL
 	       character to avoid trouble with broken code. */
+
+	    size_t keylen = resp.ypresp_all_u.val.key.keydat_len;
+	    size_t vallen = resp.ypresp_all_u.val.val.valdat_len;
+	    /* Cannot overflow due to the XDRMAXRECORD limit in yp_xdr.c.  */
+	    size_t keyval_size = keylen + vallen + 2;
+	    char *buffer = malloc (keyval_size);
+	    if (buffer == NULL)
+	      {
+		xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+		objp->status = YP_YPERR;
+		return FALSE;
+	      }
+
 	    objp->status = YP_TRUE;
-	    *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
-				  keylen)) = '\0';
-	    *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
-				  vallen)) = '\0';
+	    buffer[keylen] = '\0';
+	    buffer[keyval_size - 1] = '\0';
+	    char *val = buffer + keylen + 1;
+	    memcpy (buffer, resp.ypresp_all_u.val.key.keydat_val, keylen);
+	    memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
 	    xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
-	    if ((*objp->foreach) (objp->status, key, keylen,
-				  val, vallen, objp->data))
+
+	    bool ok = (*objp->foreach) (objp->status, buffer, keylen,
+					val, vallen, objp->data);
+	    free (buffer);
+	    if (ok)
 	      return TRUE;
 	  }
 	  break;