Commit b385ef08 authored by Lee Jones's avatar Lee Jones Committed by Greg Kroah-Hartman

usb: cdnsp: Replace snprintf() with the safer scnprintf() variant

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.

The uses in this file all seem to assume that data *has been* written!

Link: https://lwn.net/Articles/69419/
Link: https://github.com/KSPP/linux/issues/105
Cc: Pawel Laszczak <pawell@cadence.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-usb@vger.kernel.org
Signed-off-by: default avatarLee Jones <lee@kernel.org>
Link: https://lore.kernel.org/r/20231130105459.3208986-3-lee@kernel.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 36d8aef5
...@@ -187,202 +187,202 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0, ...@@ -187,202 +187,202 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
switch (type) { switch (type) {
case TRB_LINK: case TRB_LINK:
ret = snprintf(str, size, ret = scnprintf(str, size,
"LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c", "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c",
field1, field0, GET_INTR_TARGET(field2), field1, field0, GET_INTR_TARGET(field2),
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field3 & TRB_IOC ? 'I' : 'i', field3 & TRB_IOC ? 'I' : 'i',
field3 & TRB_CHAIN ? 'C' : 'c', field3 & TRB_CHAIN ? 'C' : 'c',
field3 & TRB_TC ? 'T' : 't', field3 & TRB_TC ? 'T' : 't',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_TRANSFER: case TRB_TRANSFER:
case TRB_COMPLETION: case TRB_COMPLETION:
case TRB_PORT_STATUS: case TRB_PORT_STATUS:
case TRB_HC_EVENT: case TRB_HC_EVENT:
ret = snprintf(str, size, ret = scnprintf(str, size,
"ep%d%s(%d) type '%s' TRB %08x%08x status '%s'" "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'"
" len %ld slot %ld flags %c:%c", " len %ld slot %ld flags %c:%c",
ep_num, ep_id % 2 ? "out" : "in", ep_num, ep_id % 2 ? "out" : "in",
TRB_TO_EP_INDEX(field3), TRB_TO_EP_INDEX(field3),
cdnsp_trb_type_string(type), field1, field0, cdnsp_trb_type_string(type), field1, field0,
cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)), cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)),
EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
field3 & EVENT_DATA ? 'E' : 'e', field3 & EVENT_DATA ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_MFINDEX_WRAP: case TRB_MFINDEX_WRAP:
ret = snprintf(str, size, "%s: flags %c", ret = scnprintf(str, size, "%s: flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_SETUP: case TRB_SETUP:
ret = snprintf(str, size, ret = scnprintf(str, size,
"type '%s' bRequestType %02x bRequest %02x " "type '%s' bRequestType %02x bRequest %02x "
"wValue %02x%02x wIndex %02x%02x wLength %d " "wValue %02x%02x wIndex %02x%02x wLength %d "
"length %ld TD size %ld intr %ld Setup ID %ld " "length %ld TD size %ld intr %ld Setup ID %ld "
"flags %c:%c:%c", "flags %c:%c:%c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field0 & 0xff, field0 & 0xff,
(field0 & 0xff00) >> 8, (field0 & 0xff00) >> 8,
(field0 & 0xff000000) >> 24, (field0 & 0xff000000) >> 24,
(field0 & 0xff0000) >> 16, (field0 & 0xff0000) >> 16,
(field1 & 0xff00) >> 8, (field1 & 0xff00) >> 8,
field1 & 0xff, field1 & 0xff,
(field1 & 0xff000000) >> 16 | (field1 & 0xff000000) >> 16 |
(field1 & 0xff0000) >> 16, (field1 & 0xff0000) >> 16,
TRB_LEN(field2), GET_TD_SIZE(field2), TRB_LEN(field2), GET_TD_SIZE(field2),
GET_INTR_TARGET(field2), GET_INTR_TARGET(field2),
TRB_SETUPID_TO_TYPE(field3), TRB_SETUPID_TO_TYPE(field3),
field3 & TRB_IDT ? 'D' : 'd', field3 & TRB_IDT ? 'D' : 'd',
field3 & TRB_IOC ? 'I' : 'i', field3 & TRB_IOC ? 'I' : 'i',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_DATA: case TRB_DATA:
ret = snprintf(str, size, ret = scnprintf(str, size,
"type '%s' Buffer %08x%08x length %ld TD size %ld " "type '%s' Buffer %08x%08x length %ld TD size %ld "
"intr %ld flags %c:%c:%c:%c:%c:%c:%c", "intr %ld flags %c:%c:%c:%c:%c:%c:%c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field1, field0, TRB_LEN(field2), field1, field0, TRB_LEN(field2),
GET_TD_SIZE(field2), GET_TD_SIZE(field2),
GET_INTR_TARGET(field2), GET_INTR_TARGET(field2),
field3 & TRB_IDT ? 'D' : 'i', field3 & TRB_IDT ? 'D' : 'i',
field3 & TRB_IOC ? 'I' : 'i', field3 & TRB_IOC ? 'I' : 'i',
field3 & TRB_CHAIN ? 'C' : 'c', field3 & TRB_CHAIN ? 'C' : 'c',
field3 & TRB_NO_SNOOP ? 'S' : 's', field3 & TRB_NO_SNOOP ? 'S' : 's',
field3 & TRB_ISP ? 'I' : 'i', field3 & TRB_ISP ? 'I' : 'i',
field3 & TRB_ENT ? 'E' : 'e', field3 & TRB_ENT ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_STATUS: case TRB_STATUS:
ret = snprintf(str, size, ret = scnprintf(str, size,
"Buffer %08x%08x length %ld TD size %ld intr" "Buffer %08x%08x length %ld TD size %ld intr"
"%ld type '%s' flags %c:%c:%c:%c", "%ld type '%s' flags %c:%c:%c:%c",
field1, field0, TRB_LEN(field2), field1, field0, TRB_LEN(field2),
GET_TD_SIZE(field2), GET_TD_SIZE(field2),
GET_INTR_TARGET(field2), GET_INTR_TARGET(field2),
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field3 & TRB_IOC ? 'I' : 'i', field3 & TRB_IOC ? 'I' : 'i',
field3 & TRB_CHAIN ? 'C' : 'c', field3 & TRB_CHAIN ? 'C' : 'c',
field3 & TRB_ENT ? 'E' : 'e', field3 & TRB_ENT ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_NORMAL: case TRB_NORMAL:
case TRB_ISOC: case TRB_ISOC:
case TRB_EVENT_DATA: case TRB_EVENT_DATA:
case TRB_TR_NOOP: case TRB_TR_NOOP:
ret = snprintf(str, size, ret = scnprintf(str, size,
"type '%s' Buffer %08x%08x length %ld " "type '%s' Buffer %08x%08x length %ld "
"TD size %ld intr %ld " "TD size %ld intr %ld "
"flags %c:%c:%c:%c:%c:%c:%c:%c:%c", "flags %c:%c:%c:%c:%c:%c:%c:%c:%c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field1, field0, TRB_LEN(field2), field1, field0, TRB_LEN(field2),
GET_TD_SIZE(field2), GET_TD_SIZE(field2),
GET_INTR_TARGET(field2), GET_INTR_TARGET(field2),
field3 & TRB_BEI ? 'B' : 'b', field3 & TRB_BEI ? 'B' : 'b',
field3 & TRB_IDT ? 'T' : 't', field3 & TRB_IDT ? 'T' : 't',
field3 & TRB_IOC ? 'I' : 'i', field3 & TRB_IOC ? 'I' : 'i',
field3 & TRB_CHAIN ? 'C' : 'c', field3 & TRB_CHAIN ? 'C' : 'c',
field3 & TRB_NO_SNOOP ? 'S' : 's', field3 & TRB_NO_SNOOP ? 'S' : 's',
field3 & TRB_ISP ? 'I' : 'i', field3 & TRB_ISP ? 'I' : 'i',
field3 & TRB_ENT ? 'E' : 'e', field3 & TRB_ENT ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c', field3 & TRB_CYCLE ? 'C' : 'c',
!(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v'); !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v');
break; break;
case TRB_CMD_NOOP: case TRB_CMD_NOOP:
case TRB_ENABLE_SLOT: case TRB_ENABLE_SLOT:
ret = snprintf(str, size, "%s: flags %c", ret = scnprintf(str, size, "%s: flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_DISABLE_SLOT: case TRB_DISABLE_SLOT:
ret = snprintf(str, size, "%s: slot %ld flags %c", ret = scnprintf(str, size, "%s: slot %ld flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_ADDR_DEV: case TRB_ADDR_DEV:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ctx %08x%08x slot %ld flags %c:%c", "%s: ctx %08x%08x slot %ld flags %c:%c",
cdnsp_trb_type_string(type), field1, field0, cdnsp_trb_type_string(type), field1, field0,
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_BSR ? 'B' : 'b', field3 & TRB_BSR ? 'B' : 'b',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_CONFIG_EP: case TRB_CONFIG_EP:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ctx %08x%08x slot %ld flags %c:%c", "%s: ctx %08x%08x slot %ld flags %c:%c",
cdnsp_trb_type_string(type), field1, field0, cdnsp_trb_type_string(type), field1, field0,
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_DC ? 'D' : 'd', field3 & TRB_DC ? 'D' : 'd',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_EVAL_CONTEXT: case TRB_EVAL_CONTEXT:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ctx %08x%08x slot %ld flags %c", "%s: ctx %08x%08x slot %ld flags %c",
cdnsp_trb_type_string(type), field1, field0, cdnsp_trb_type_string(type), field1, field0,
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_RESET_EP: case TRB_RESET_EP:
case TRB_HALT_ENDPOINT: case TRB_HALT_ENDPOINT:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c", "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
ep_num, ep_id % 2 ? "out" : "in", ep_num, ep_id % 2 ? "out" : "in",
TRB_TO_EP_INDEX(field3), field1, field0, TRB_TO_EP_INDEX(field3), field1, field0,
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_STOP_RING: case TRB_STOP_RING:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ep%d%s(%d) slot %ld sp %d flags %c", "%s: ep%d%s(%d) slot %ld sp %d flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
ep_num, ep_id % 2 ? "out" : "in", ep_num, ep_id % 2 ? "out" : "in",
TRB_TO_EP_INDEX(field3), TRB_TO_EP_INDEX(field3),
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
TRB_TO_SUSPEND_PORT(field3), TRB_TO_SUSPEND_PORT(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_SET_DEQ: case TRB_SET_DEQ:
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c", "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
ep_num, ep_id % 2 ? "out" : "in", ep_num, ep_id % 2 ? "out" : "in",
TRB_TO_EP_INDEX(field3), field1, field0, TRB_TO_EP_INDEX(field3), field1, field0,
TRB_TO_STREAM_ID(field2), TRB_TO_STREAM_ID(field2),
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_RESET_DEV: case TRB_RESET_DEV:
ret = snprintf(str, size, "%s: slot %ld flags %c", ret = scnprintf(str, size, "%s: slot %ld flags %c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
TRB_TO_SLOT_ID(field3), TRB_TO_SLOT_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
case TRB_ENDPOINT_NRDY: case TRB_ENDPOINT_NRDY:
temp = TRB_TO_HOST_STREAM(field2); temp = TRB_TO_HOST_STREAM(field2);
ret = snprintf(str, size, ret = scnprintf(str, size,
"%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c", "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
ep_num, ep_id % 2 ? "out" : "in", ep_num, ep_id % 2 ? "out" : "in",
TRB_TO_EP_INDEX(field3), temp, TRB_TO_EP_INDEX(field3), temp,
temp == STREAM_PRIME_ACK ? "(PRIME)" : "", temp == STREAM_PRIME_ACK ? "(PRIME)" : "",
temp == STREAM_REJECTED ? "(REJECTED)" : "", temp == STREAM_REJECTED ? "(REJECTED)" : "",
TRB_TO_DEV_STREAM(field0), TRB_TO_DEV_STREAM(field0),
field3 & TRB_STAT ? 'S' : 's', field3 & TRB_STAT ? 'S' : 's',
field3 & TRB_CYCLE ? 'C' : 'c'); field3 & TRB_CYCLE ? 'C' : 'c');
break; break;
default: default:
ret = snprintf(str, size, ret = scnprintf(str, size,
"type '%s' -> raw %08x %08x %08x %08x", "type '%s' -> raw %08x %08x %08x %08x",
cdnsp_trb_type_string(type), cdnsp_trb_type_string(type),
field0, field1, field2, field3); field0, field1, field2, field3);
} }
if (ret >= size) if (ret == size - 1)
pr_info("CDNSP: buffer overflowed.\n"); pr_info("CDNSP: buffer may be truncated.\n");
return str; return str;
} }
...@@ -465,32 +465,32 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size, ...@@ -465,32 +465,32 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size,
{ {
int ret; int ret;
ret = snprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ", ret = scnprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ",
portsc & PORT_POWER ? "Powered" : "Powered-off", portsc & PORT_POWER ? "Powered" : "Powered-off",
portsc & PORT_CONNECT ? "Connected" : "Not-connected", portsc & PORT_CONNECT ? "Connected" : "Not-connected",
portsc & PORT_PED ? "Enabled" : "Disabled", portsc & PORT_PED ? "Enabled" : "Disabled",
cdnsp_portsc_link_state_string(portsc), cdnsp_portsc_link_state_string(portsc),
DEV_PORT_SPEED(portsc)); DEV_PORT_SPEED(portsc));
if (portsc & PORT_RESET) if (portsc & PORT_RESET)
ret += snprintf(str + ret, size - ret, "In-Reset "); ret += scnprintf(str + ret, size - ret, "In-Reset ");
ret += snprintf(str + ret, size - ret, "Change: "); ret += scnprintf(str + ret, size - ret, "Change: ");
if (portsc & PORT_CSC) if (portsc & PORT_CSC)
ret += snprintf(str + ret, size - ret, "CSC "); ret += scnprintf(str + ret, size - ret, "CSC ");
if (portsc & PORT_WRC) if (portsc & PORT_WRC)
ret += snprintf(str + ret, size - ret, "WRC "); ret += scnprintf(str + ret, size - ret, "WRC ");
if (portsc & PORT_RC) if (portsc & PORT_RC)
ret += snprintf(str + ret, size - ret, "PRC "); ret += scnprintf(str + ret, size - ret, "PRC ");
if (portsc & PORT_PLC) if (portsc & PORT_PLC)
ret += snprintf(str + ret, size - ret, "PLC "); ret += scnprintf(str + ret, size - ret, "PLC ");
if (portsc & PORT_CEC) if (portsc & PORT_CEC)
ret += snprintf(str + ret, size - ret, "CEC "); ret += scnprintf(str + ret, size - ret, "CEC ");
ret += snprintf(str + ret, size - ret, "Wake: "); ret += scnprintf(str + ret, size - ret, "Wake: ");
if (portsc & PORT_WKCONN_E) if (portsc & PORT_WKCONN_E)
ret += snprintf(str + ret, size - ret, "WCE "); ret += scnprintf(str + ret, size - ret, "WCE ");
if (portsc & PORT_WKDISC_E) if (portsc & PORT_WKDISC_E)
ret += snprintf(str + ret, size - ret, "WDE "); ret += scnprintf(str + ret, size - ret, "WDE ");
return str; return str;
} }
...@@ -562,20 +562,20 @@ static inline const char *cdnsp_decode_ep_context(char *str, size_t size, ...@@ -562,20 +562,20 @@ static inline const char *cdnsp_decode_ep_context(char *str, size_t size,
avg = EP_AVG_TRB_LENGTH(tx_info); avg = EP_AVG_TRB_LENGTH(tx_info);
ret = snprintf(str, size, "State %s mult %d max P. Streams %d %s", ret = scnprintf(str, size, "State %s mult %d max P. Streams %d %s",
cdnsp_ep_state_string(ep_state), mult, cdnsp_ep_state_string(ep_state), mult,
max_pstr, lsa ? "LSA " : ""); max_pstr, lsa ? "LSA " : "");
ret += snprintf(str + ret, size - ret, ret += scnprintf(str + ret, size - ret,
"interval %d us max ESIT payload %d CErr %d ", "interval %d us max ESIT payload %d CErr %d ",
(1 << interval) * 125, esit, cerr); (1 << interval) * 125, esit, cerr);
ret += snprintf(str + ret, size - ret, ret += scnprintf(str + ret, size - ret,
"Type %s %sburst %d maxp %d deq %016llx ", "Type %s %sburst %d maxp %d deq %016llx ",
cdnsp_ep_type_string(ep_type), hid ? "HID" : "", cdnsp_ep_type_string(ep_type), hid ? "HID" : "",
burst, maxp, deq); burst, maxp, deq);
ret += snprintf(str + ret, size - ret, "avg trb len %d", avg); ret += scnprintf(str + ret, size - ret, "avg trb len %d", avg);
return str; return str;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment