Author: jrtc27
Date: Thu Oct 15 18:03:14 2020
New Revision: 366736
URL: https://svnweb.freebsd.org/changeset/base/366736

Log:
  kldxref: Avoid buffer overflows in parse_pnp_list
  
  We convert a string like "W32:vendor/device" into "I:vendor;I:device",
  where the output is longer than the input, but only allocate space equal
  to the length of the input, leading to a buffer overflow.
  
  Instead use open_memstream so we get a safe dynamically-grown buffer.
  
  Found by:     CHERI
  Reviewed by:  imp, jhb (mentor)
  Approved by:  imp, jhb (mentor)
  Obtained from:        CheriBSD
  Differential Revision:        https://reviews.freebsd.org/D26637

Modified:
  head/usr.sbin/kldxref/kldxref.c

Modified: head/usr.sbin/kldxref/kldxref.c
==============================================================================
--- head/usr.sbin/kldxref/kldxref.c     Thu Oct 15 17:44:17 2020        
(r366735)
+++ head/usr.sbin/kldxref/kldxref.c     Thu Oct 15 18:03:14 2020        
(r366736)
@@ -235,14 +235,17 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_
        const char *walker, *ep;
        const char *colon, *semi;
        struct pnp_elt *elt;
-       char *nd;
        char type[8], key[32];
        int off;
+       size_t new_desc_size;
+       FILE *fp;
 
        walker = desc;
        ep = desc + strlen(desc);
        off = 0;
-       nd = *new_desc = malloc(strlen(desc) + 1);
+       fp = open_memstream(new_desc, &new_desc_size);
+       if (fp == NULL)
+               err(1, "Could not open new memory stream");
        if (verbose > 1)
                printf("Converting %s into a list\n", desc);
        while (walker < ep) {
@@ -336,42 +339,44 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_
                        off = elt->pe_offset + sizeof(void *);
                }
                if (elt->pe_kind & TYPE_PAIRED) {
-                       char *word, *ctx;
+                       char *word, *ctx, newtype;
 
                        for (word = strtok_r(key, "/", &ctx);
                             word; word = strtok_r(NULL, "/", &ctx)) {
-                               sprintf(nd, "%c:%s;", elt->pe_kind & 
TYPE_FLAGGED ? 'J' : 'I',
-                                   word);
-                               nd += strlen(nd);
+                               newtype = elt->pe_kind & TYPE_FLAGGED ? 'J' : 
'I';
+                               fprintf(fp, "%c:%s;", newtype, word);
                        }
-                       
                }
                else {
+                       char newtype;
+
                        if (elt->pe_kind & TYPE_FLAGGED)
-                               *nd++ = 'J';
+                               newtype = 'J';
                        else if (elt->pe_kind & TYPE_GE)
-                               *nd++ = 'G';
+                               newtype = 'G';
                        else if (elt->pe_kind & TYPE_LE)
-                               *nd++ = 'L';
+                               newtype = 'L';
                        else if (elt->pe_kind & TYPE_MASK)
-                               *nd++ = 'M';
+                               newtype = 'M';
                        else if (elt->pe_kind & TYPE_INT)
-                               *nd++ = 'I';
+                               newtype = 'I';
                        else if (elt->pe_kind == TYPE_D)
-                               *nd++ = 'D';
+                               newtype = 'D';
                        else if (elt->pe_kind == TYPE_Z || elt->pe_kind == 
TYPE_E)
-                               *nd++ = 'Z';
+                               newtype = 'Z';
                        else if (elt->pe_kind == TYPE_T)
-                               *nd++ = 'T';
+                               newtype = 'T';
                        else
                                errx(1, "Impossible type %x\n", elt->pe_kind);
-                       *nd++ = ':';
-                       strcpy(nd, key);
-                       nd += strlen(nd);
-                       *nd++ = ';';
+                       fprintf(fp, "%c:%s;", newtype, key);
                }
        }
-       *nd++ = '\0';
+       if (ferror(fp) != 0) {
+               fclose(fp);
+               errx(1, "Exhausted space converting description %s", desc);
+       }
+       if (fclose(fp) != 0)
+               errx(1, "Failed to close memory stream");
        return (0);
 err:
        errx(1, "Parse error of description string %s", desc);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to