usb: cdns2: Replace snprintf() with the safer scnprintf() variant
authorLee Jones <lee@kernel.org>
Wed, 13 Dec 2023 16:42:35 +0000 (16:42 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 15 Dec 2023 12:55:30 +0000 (13:55 +0100)
There is a general misunderstanding amongst engineers that {v}snprintf()
returns the length of the data *actually* encoded into the destination
array.  However, as per the C99 standard {v}snprintf() really returns
the length of the data that *would have been* written if there were
enough space for it.  This misunderstanding has led to buffer-overruns
in the past.  It's generally considered safer to use the {v}scnprintf()
variants in their place (or even sprintf() in simple cases).  So let's
do that.

Link: https://lwn.net/Articles/69419/
Link: https://github.com/KSPP/linux/issues/105
Cc: Pawel Laszczak <pawell@cadence.com>
Signed-off-by: Lee Jones <lee@kernel.org>
Link: https://lore.kernel.org/r/20231213164246.1021885-7-lee@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/cdns2/cdns2-debug.h

index be9ae0d28a40975be29f9ee27c81c4b789324800..f5f330004190ea0a8388cf23748b15bd4560a5e1 100644 (file)
@@ -16,34 +16,34 @@ static inline const char *cdns2_decode_usb_irq(char *str, size_t size,
 {
        int ret;
 
-       ret = snprintf(str, size, "usbirq: 0x%02x - ", usb_irq);
+       ret = scnprintf(str, size, "usbirq: 0x%02x - ", usb_irq);
 
        if (usb_irq & USBIRQ_SOF)
-               ret += snprintf(str + ret, size - ret, "SOF ");
+               ret += scnprintf(str + ret, size - ret, "SOF ");
        if (usb_irq & USBIRQ_SUTOK)
-               ret += snprintf(str + ret, size - ret, "SUTOK ");
+               ret += scnprintf(str + ret, size - ret, "SUTOK ");
        if (usb_irq & USBIRQ_SUDAV)
-               ret += snprintf(str + ret, size - ret, "SETUP ");
+               ret += scnprintf(str + ret, size - ret, "SETUP ");
        if (usb_irq & USBIRQ_SUSPEND)
-               ret += snprintf(str + ret, size - ret, "Suspend ");
+               ret += scnprintf(str + ret, size - ret, "Suspend ");
        if (usb_irq & USBIRQ_URESET)
-               ret += snprintf(str + ret, size - ret, "Reset ");
+               ret += scnprintf(str + ret, size - ret, "Reset ");
        if (usb_irq & USBIRQ_HSPEED)
-               ret += snprintf(str + ret, size - ret, "HS ");
+               ret += scnprintf(str + ret, size - ret, "HS ");
        if (usb_irq & USBIRQ_LPM)
-               ret += snprintf(str + ret, size - ret, "LPM ");
+               ret += scnprintf(str + ret, size - ret, "LPM ");
 
-       ret += snprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq);
+       ret += scnprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq);
 
        if (ext_irq & EXTIRQ_WAKEUP)
-               ret += snprintf(str + ret, size - ret, "Wakeup ");
+               ret += scnprintf(str + ret, size - ret, "Wakeup ");
        if (ext_irq & EXTIRQ_VBUSFAULT_FALL)
-               ret += snprintf(str + ret, size - ret, "VBUS_FALL ");
+               ret += scnprintf(str + ret, size - ret, "VBUS_FALL ");
        if (ext_irq & EXTIRQ_VBUSFAULT_RISE)
-               ret += snprintf(str + ret, size - ret, "VBUS_RISE ");
+               ret += scnprintf(str + ret, size - ret, "VBUS_RISE ");
 
-       if (ret >= size)
-               pr_info("CDNS2: buffer overflowed.\n");
+       if (ret == size - 1)
+               pr_info("CDNS2: buffer may be truncated.\n");
 
        return str;
 }
@@ -54,28 +54,28 @@ static inline const char *cdns2_decode_dma_irq(char *str, size_t size,
 {
        int ret;
 
-       ret = snprintf(str, size, "ISTS: %08x, %s: %08x ",
-                      ep_ists, ep_name, ep_sts);
+       ret = scnprintf(str, size, "ISTS: %08x, %s: %08x ",
+                       ep_ists, ep_name, ep_sts);
 
        if (ep_sts & DMA_EP_STS_IOC)
-               ret += snprintf(str + ret, size - ret, "IOC ");
+               ret += scnprintf(str + ret, size - ret, "IOC ");
        if (ep_sts & DMA_EP_STS_ISP)
-               ret += snprintf(str + ret, size - ret, "ISP ");
+               ret += scnprintf(str + ret, size - ret, "ISP ");
        if (ep_sts & DMA_EP_STS_DESCMIS)
-               ret += snprintf(str + ret, size - ret, "DESCMIS ");
+               ret += scnprintf(str + ret, size - ret, "DESCMIS ");
        if (ep_sts & DMA_EP_STS_TRBERR)
-               ret += snprintf(str + ret, size - ret, "TRBERR ");
+               ret += scnprintf(str + ret, size - ret, "TRBERR ");
        if (ep_sts & DMA_EP_STS_OUTSMM)
-               ret += snprintf(str + ret, size - ret, "OUTSMM ");
+               ret += scnprintf(str + ret, size - ret, "OUTSMM ");
        if (ep_sts & DMA_EP_STS_ISOERR)
-               ret += snprintf(str + ret, size - ret, "ISOERR ");
+               ret += scnprintf(str + ret, size - ret, "ISOERR ");
        if (ep_sts & DMA_EP_STS_DBUSY)
-               ret += snprintf(str + ret, size - ret, "DBUSY ");
+               ret += scnprintf(str + ret, size - ret, "DBUSY ");
        if (DMA_EP_STS_CCS(ep_sts))
-               ret += snprintf(str + ret, size - ret, "CCS ");
+               ret += scnprintf(str + ret, size - ret, "CCS ");
 
-       if (ret >= size)
-               pr_info("CDNS2: buffer overflowed.\n");
+       if (ret == size - 1)
+               pr_info("CDNS2: buffer may be truncated.\n");
 
        return str;
 }
@@ -105,43 +105,43 @@ static inline const char *cdns2_raw_ring(struct cdns2_endpoint *pep,
        int ret;
        int i;
 
-       ret = snprintf(str, size, "\n\t\tTR for %s:", pep->name);
+       ret = scnprintf(str, size, "\n\t\tTR for %s:", pep->name);
 
        trb = &trbs[ring->dequeue];
        dma = cdns2_trb_virt_to_dma(pep, trb);
-       ret += snprintf(str + ret, size - ret,
-                       "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n",
-                       ring->dequeue, trb, &dma);
+       ret += scnprintf(str + ret, size - ret,
+                        "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n",
+                        ring->dequeue, trb, &dma);
 
        trb = &trbs[ring->enqueue];
        dma = cdns2_trb_virt_to_dma(pep, trb);
-       ret += snprintf(str + ret, size - ret,
-                       "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n",
-                       ring->enqueue, trb, &dma);
+       ret += scnprintf(str + ret, size - ret,
+                        "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n",
+                        ring->enqueue, trb, &dma);
 
-       ret += snprintf(str + ret, size - ret,
-                       "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
-                       ring->free_trbs, ring->ccs, ring->pcs);
+       ret += scnprintf(str + ret, size - ret,
+                        "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
+                        ring->free_trbs, ring->ccs, ring->pcs);
 
        if (TRBS_PER_SEGMENT > 40) {
-               ret += snprintf(str + ret, size - ret,
-                               "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT);
+               ret += scnprintf(str + ret, size - ret,
+                                "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT);
                return str;
        }
 
        dma = ring->dma;
        for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
                trb = &trbs[i];
-               ret += snprintf(str + ret, size - ret,
-                               "\t\t@%pad %08x %08x %08x\n", &dma,
-                               le32_to_cpu(trb->buffer),
-                               le32_to_cpu(trb->length),
-                               le32_to_cpu(trb->control));
+               ret += scnprintf(str + ret, size - ret,
+                                "\t\t@%pad %08x %08x %08x\n", &dma,
+                                le32_to_cpu(trb->buffer),
+                                le32_to_cpu(trb->length),
+                                le32_to_cpu(trb->control));
                dma += sizeof(*trb);
        }
 
-       if (ret >= size)
-               pr_info("CDNS2: buffer overflowed.\n");
+       if (ret == size - 1)
+               pr_info("CDNS2: buffer may be truncated.\n");
 
        return str;
 }
@@ -166,36 +166,36 @@ static inline const char *cdns2_decode_trb(char *str, size_t size, u32 flags,
 
        switch (type) {
        case TRB_LINK:
-               ret = snprintf(str, size,
-                              "LINK %08x type '%s' flags %c:%c:%c%c:%c",
-                              buffer, cdns2_trb_type_string(type),
-                              flags & TRB_CYCLE ? 'C' : 'c',
-                              flags & TRB_TOGGLE ? 'T' : 't',
-                              flags & TRB_CHAIN ? 'C' : 'c',
-                              flags & TRB_CHAIN ? 'H' : 'h',
-                              flags & TRB_IOC ? 'I' : 'i');
+               ret = scnprintf(str, size,
+                               "LINK %08x type '%s' flags %c:%c:%c%c:%c",
+                               buffer, cdns2_trb_type_string(type),
+                               flags & TRB_CYCLE ? 'C' : 'c',
+                               flags & TRB_TOGGLE ? 'T' : 't',
+                               flags & TRB_CHAIN ? 'C' : 'c',
+                               flags & TRB_CHAIN ? 'H' : 'h',
+                               flags & TRB_IOC ? 'I' : 'i');
                break;
        case TRB_NORMAL:
-               ret = snprintf(str, size,
-                              "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, "
-                              "flags %c:%c:%c%c:%c",
-                              cdns2_trb_type_string(type),
-                              buffer, TRB_LEN(length),
-                              TRB_FIELD_TO_BURST(length),
-                              flags & TRB_CYCLE ? 'C' : 'c',
-                              flags & TRB_ISP ? 'I' : 'i',
-                              flags & TRB_CHAIN ? 'C' : 'c',
-                              flags & TRB_CHAIN ? 'H' : 'h',
-                              flags & TRB_IOC ? 'I' : 'i');
+               ret = scnprintf(str, size,
+                               "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, "
+                               "flags %c:%c:%c%c:%c",
+                               cdns2_trb_type_string(type),
+                               buffer, TRB_LEN(length),
+                               TRB_FIELD_TO_BURST(length),
+                               flags & TRB_CYCLE ? 'C' : 'c',
+                               flags & TRB_ISP ? 'I' : 'i',
+                               flags & TRB_CHAIN ? 'C' : 'c',
+                               flags & TRB_CHAIN ? 'H' : 'h',
+                               flags & TRB_IOC ? 'I' : 'i');
                break;
        default:
-               ret = snprintf(str, size, "type '%s' -> raw %08x %08x %08x",
-                              cdns2_trb_type_string(type),
-                              buffer, length, flags);
+               ret = scnprintf(str, size, "type '%s' -> raw %08x %08x %08x",
+                               cdns2_trb_type_string(type),
+                               buffer, length, flags);
        }
 
-       if (ret >= size)
-               pr_info("CDNS2: buffer overflowed.\n");
+       if (ret == size - 1)
+               pr_info("CDNS2: buffer may be truncated.\n");
 
        return str;
 }