The administrative APIs accept comments and other metadata as
strings. Since these strings can be arbitrarily long (up to
UINT16_MAX bytes), they may overflow the fixed-size stack buffers
previously used for block construction.

Replace the fixed-size buffers with dynamically allocated memory
sized to the actual block length. Return appropriate error codes
on allocation failure.

Bugzilla ID: 1820
Fixes: 8d23ce8f5ee9 ("pcapng: add new library for writing pcapng files")
Cc: [email protected]

Signed-off-by: Stephen Hemminger <[email protected]>
---
 lib/pcapng/rte_pcapng.c | 39 +++++++++++++++++++++++++--------------
 lib/pcapng/rte_pcapng.h |  3 ++-
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c
index 61d37b4462..d5b3a0cd29 100644
--- a/lib/pcapng/rte_pcapng.c
+++ b/lib/pcapng/rte_pcapng.c
@@ -37,9 +37,6 @@
 /* upper bound for strings in pcapng option data */
 #define PCAPNG_STR_MAX UINT16_MAX
 
-/* upper bound for section, stats and interface blocks (in uint32_t) */
-#define PCAPNG_BLKSIZ  (2048 / sizeof(uint32_t))
-
 /* Format of the capture file handle */
 struct rte_pcapng {
        int  outfd;             /* output file */
@@ -148,8 +145,9 @@ pcapng_section_block(rte_pcapng_t *self,
 {
        struct pcapng_section_header *hdr;
        struct pcapng_option *opt;
-       uint32_t buf[PCAPNG_BLKSIZ];
+       uint32_t *buf;
        uint32_t len;
+       ssize_t ret;
 
        len = sizeof(*hdr);
        if (hw)
@@ -165,8 +163,11 @@ pcapng_section_block(rte_pcapng_t *self,
        len += pcapng_optlen(0);
        len += sizeof(uint32_t);
 
-       if (len > sizeof(buf))
+       buf = malloc(len);
+       if (buf == NULL) {
+               errno = ENOMEM;
                return -1;
+       }
 
        hdr = (struct pcapng_section_header *)buf;
        *hdr = (struct pcapng_section_header) {
@@ -199,7 +200,9 @@ pcapng_section_block(rte_pcapng_t *self,
        /* clone block_length after option */
        memcpy(opt, &hdr->block_length, sizeof(uint32_t));
 
-       return write(self->outfd, buf, len);
+       ret = write(self->outfd, buf, len);
+       free(buf);
+       return ret;
 }
 
 /* Write an interface block for a DPDK port */
@@ -217,7 +220,7 @@ rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, 
uint16_t link_type,
        struct pcapng_option *opt;
        const uint8_t tsresol = 9;      /* nanosecond resolution */
        uint32_t len;
-       uint32_t buf[PCAPNG_BLKSIZ];
+       uint32_t *buf;
        char ifname_buf[IF_NAMESIZE];
        char ifhw[256];
        uint64_t speed = 0;
@@ -279,8 +282,9 @@ rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, 
uint16_t link_type,
        len += pcapng_optlen(0);
        len += sizeof(uint32_t);
 
-       if (len > sizeof(buf))
-               return -EINVAL;
+       buf = malloc(len);
+       if (buf == NULL)
+               return -ENOMEM;
 
        hdr = (struct pcapng_interface_block *)buf;
        *hdr = (struct pcapng_interface_block) {
@@ -326,7 +330,9 @@ rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, 
uint16_t link_type,
        /* remember the file index */
        self->port_index[port] = self->ports++;
 
-       return write(self->outfd, buf, len);
+       ret = write(self->outfd, buf, len);
+       free(buf);
+       return ret;
 }
 
 /*
@@ -343,7 +349,8 @@ rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id,
        uint64_t start_time = self->offset_ns;
        uint64_t sample_time;
        uint32_t optlen, len;
-       uint32_t buf[PCAPNG_BLKSIZ];
+       uint32_t *buf;
+       ssize_t ret;
 
        RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 
@@ -366,8 +373,9 @@ rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id,
                optlen += pcapng_optlen(0);
 
        len = sizeof(*hdr) + optlen + sizeof(uint32_t);
-       if (len > sizeof(buf))
-               return -1;
+       buf = malloc(len);
+       if (buf == NULL)
+               return -ENOMEM;
 
        hdr = (struct pcapng_statistics *)buf;
        opt = (struct pcapng_option *)(hdr + 1);
@@ -398,7 +406,10 @@ rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t 
port_id,
        /* clone block_length after option */
        memcpy(opt, &len, sizeof(uint32_t));
 
-       return write(self->outfd, buf, len);
+       ret = write(self->outfd, buf, len);
+       free(buf);
+
+       return ret < 0 ? -errno : ret;
 }
 
 RTE_EXPORT_SYMBOL(rte_pcapng_mbuf_size)
diff --git a/lib/pcapng/rte_pcapng.h b/lib/pcapng/rte_pcapng.h
index d866042b66..85abf1d93f 100644
--- a/lib/pcapng/rte_pcapng.h
+++ b/lib/pcapng/rte_pcapng.h
@@ -196,7 +196,8 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
  * @param comment
  *  Optional comment to add to statistics.
  * @return
- *  number of bytes written to file, -1 on failure to write file or memory 
allocation failure.
+ *  number of bytes written to file on success,
+ *  negative errno value on error.
  */
 ssize_t
 rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port,
-- 
2.51.0

Reply via email to