Add missing namelen checks in __pmDecodeFetch routine
authorNathan Scott <nathans@redhat.com>
Mon, 13 Aug 2012 01:28:43 +0000 (11:28 +1000)
committerNathan Scott <nathans@redhat.com>
Mon, 13 Aug 2012 01:28:43 +0000 (11:28 +1000)
pmcd crashes when processing a crafted PDU_FETCH request because of a
missing length check in __pmDecodeFetch.  Code execution through this
bug appears unlikely because the loop which runs past the end of the
PDU only performs byte swapping (on little-endian architectures).

Original report and fixes reviewed by Florian Weimer of the Red Hat
Security team.  Red Hat bugzilla bug #841183.

Security advisory CVE-2012-3418.

src/libpcp/src/p_fetch.c

index 046917e..be9c8ba 100644 (file)
@@ -66,18 +66,33 @@ __pmSendFetch(int fd, int from, int ctxnum, __pmTimeval *when, int numpmid, pmID
 }
 
 int
-__pmDecodeFetch(__pmPDU *pdubuf, int *ctxnum, __pmTimeval *when, int *numpmid, pmID **pmidlist)
+__pmDecodeFetch(__pmPDU *pdubuf, int *ctxnum, __pmTimeval *when, int *numpmidp, pmID **pmidlist)
 {
     fetch_t    *pp;
+    char       *pduend;
+    int                numpmid;
     int                j;
 
     pp = (fetch_t *)pdubuf;
+    pduend = (char *)pdubuf + pp->hdr.len;
+
+    if (pduend - (char*)pp < sizeof(fetch_t))
+       return PM_ERR_IPC;
+    numpmid = ntohl(pp->numpmid);
+    if (numpmid <= 0 || numpmid > pp->hdr.len)
+       return PM_ERR_IPC;
+    if (numpmid >= (INT_MAX - sizeof(fetch_t)) / sizeof(pmID))
+       return PM_ERR_IPC;
+    if ((pduend - (char*)pp) != sizeof(fetch_t) + ((sizeof(pmID)) * (numpmid-1)))
+       return PM_ERR_IPC;
+
+    for (j = 0; j < numpmid; j++)
+       pp->pmidlist[j] = __ntohpmID(pp->pmidlist[j]);
+
     *ctxnum = ntohl(pp->ctxnum);
     when->tv_sec = ntohl(pp->when.tv_sec);
     when->tv_usec = ntohl(pp->when.tv_usec);
-    *numpmid = ntohl(pp->numpmid);
-    for (j = 0; j < *numpmid; j++)
-       pp->pmidlist[j] = __ntohpmID(pp->pmidlist[j]);
+    *numpmidp = numpmid;
     *pmidlist = pp->pmidlist;
     __pmPinPDUBuf((void *)pdubuf);
     return 0;