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

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.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 36d8aef5
Loading
Loading
Loading
Loading
+177 −177
Original line number Diff line number Diff line
@@ -187,7 +187,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,

	switch (type) {
	case TRB_LINK:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c",
				field1, field0, GET_INTR_TARGET(field2),
				cdnsp_trb_type_string(type),
@@ -200,7 +200,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
	case TRB_COMPLETION:
	case TRB_PORT_STATUS:
	case TRB_HC_EVENT:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"ep%d%s(%d) type '%s' TRB %08x%08x status '%s'"
				" len %ld slot %ld flags %c:%c",
				ep_num, ep_id % 2 ? "out" : "in",
@@ -212,12 +212,12 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_MFINDEX_WRAP:
		ret = snprintf(str, size, "%s: flags %c",
		ret = scnprintf(str, size, "%s: flags %c",
				cdnsp_trb_type_string(type),
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_SETUP:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"type '%s' bRequestType %02x bRequest %02x "
				"wValue %02x%02x wIndex %02x%02x wLength %d "
				"length %ld TD size %ld intr %ld Setup ID %ld "
@@ -239,7 +239,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_DATA:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"type '%s' Buffer %08x%08x length %ld TD size %ld "
				"intr %ld flags %c:%c:%c:%c:%c:%c:%c",
				cdnsp_trb_type_string(type),
@@ -255,7 +255,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_STATUS:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"Buffer %08x%08x length %ld TD size %ld intr"
				"%ld type '%s' flags %c:%c:%c:%c",
				field1, field0, TRB_LEN(field2),
@@ -271,7 +271,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
	case TRB_ISOC:
	case TRB_EVENT_DATA:
	case TRB_TR_NOOP:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"type '%s' Buffer %08x%08x length %ld "
				"TD size %ld intr %ld "
				"flags %c:%c:%c:%c:%c:%c:%c:%c:%c",
@@ -291,18 +291,18 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
		break;
	case TRB_CMD_NOOP:
	case TRB_ENABLE_SLOT:
		ret = snprintf(str, size, "%s: flags %c",
		ret = scnprintf(str, size, "%s: flags %c",
				cdnsp_trb_type_string(type),
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	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),
				TRB_TO_SLOT_ID(field3),
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_ADDR_DEV:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"%s: ctx %08x%08x slot %ld flags %c:%c",
				cdnsp_trb_type_string(type), field1, field0,
				TRB_TO_SLOT_ID(field3),
@@ -310,7 +310,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_CONFIG_EP:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"%s: ctx %08x%08x slot %ld flags %c:%c",
				cdnsp_trb_type_string(type), field1, field0,
				TRB_TO_SLOT_ID(field3),
@@ -318,7 +318,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_EVAL_CONTEXT:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"%s: ctx %08x%08x slot %ld flags %c",
				cdnsp_trb_type_string(type), field1, field0,
				TRB_TO_SLOT_ID(field3),
@@ -326,7 +326,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
		break;
	case TRB_RESET_EP:
	case TRB_HALT_ENDPOINT:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c",
				cdnsp_trb_type_string(type),
				ep_num, ep_id % 2 ? "out" : "in",
@@ -335,7 +335,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	case TRB_STOP_RING:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"%s: ep%d%s(%d) slot %ld sp %d flags %c",
				cdnsp_trb_type_string(type),
				ep_num, ep_id % 2 ? "out" : "in",
@@ -345,7 +345,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	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",
				cdnsp_trb_type_string(type),
				ep_num, ep_id % 2 ? "out" : "in",
@@ -355,7 +355,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	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),
				TRB_TO_SLOT_ID(field3),
				field3 & TRB_CYCLE ? 'C' : 'c');
@@ -363,7 +363,7 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
	case TRB_ENDPOINT_NRDY:
		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",
				cdnsp_trb_type_string(type),
				ep_num, ep_id % 2 ? "out" : "in",
@@ -375,14 +375,14 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
				field3 & TRB_CYCLE ? 'C' : 'c');
		break;
	default:
		ret = snprintf(str, size,
		ret = scnprintf(str, size,
				"type '%s' -> raw %08x %08x %08x %08x",
				cdnsp_trb_type_string(type),
				field0, field1, field2, field3);
	}

	if (ret >= size)
		pr_info("CDNSP: buffer overflowed.\n");
	if (ret == size - 1)
		pr_info("CDNSP: buffer may be truncated.\n");

	return str;
}
@@ -465,7 +465,7 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size,
{
	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_CONNECT ? "Connected" : "Not-connected",
			portsc & PORT_PED ? "Enabled" : "Disabled",
@@ -473,24 +473,24 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size,
			DEV_PORT_SPEED(portsc));

	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)
		ret += snprintf(str + ret, size - ret, "CSC ");
		ret += scnprintf(str + ret, size - ret, "CSC ");
	if (portsc & PORT_WRC)
		ret += snprintf(str + ret, size - ret, "WRC ");
		ret += scnprintf(str + ret, size - ret, "WRC ");
	if (portsc & PORT_RC)
		ret += snprintf(str + ret, size - ret, "PRC ");
		ret += scnprintf(str + ret, size - ret, "PRC ");
	if (portsc & PORT_PLC)
		ret += snprintf(str + ret, size - ret, "PLC ");
		ret += scnprintf(str + ret, size - ret, "PLC ");
	if (portsc & PORT_CEC)
		ret += snprintf(str + ret, size - ret, "CEC ");
	ret += snprintf(str + ret, size - ret, "Wake: ");
		ret += scnprintf(str + ret, size - ret, "CEC ");
	ret += scnprintf(str + ret, size - ret, "Wake: ");
	if (portsc & PORT_WKCONN_E)
		ret += snprintf(str + ret, size - ret, "WCE ");
		ret += scnprintf(str + ret, size - ret, "WCE ");
	if (portsc & PORT_WKDISC_E)
		ret += snprintf(str + ret, size - ret, "WDE ");
		ret += scnprintf(str + ret, size - ret, "WDE ");

	return str;
}
@@ -562,20 +562,20 @@ static inline const char *cdnsp_decode_ep_context(char *str, size_t size,

	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,
			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 ",
			 (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 ",
			 cdnsp_ep_type_string(ep_type), hid ? "HID" : "",
			 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;
}