usb: Replace {v}snprintf() variants with safer alternatives
Subsystems (5)
cover usb: Replace {v}snprintf() variants with safer alternatives
This series is part of an effort to rid {v}snprintf() where possible.
For a far better description of the problem than I could author, see Jon's write-up on LWN [1] and/or Alex's on the Kernel Self Protection Project [1].
[0] https://lwn.net/Articles/69419/
[1] https://github.com/KSPP/linux/issues/105
Lee Jones (5):
usb: atm: Remove snprintf() from sysfs call-backs and replace with
sysfs_emit()
usb: cdnsp: Replace snprintf() with the safer scnprintf() variant
usb: fotg210-hcd: Replace snprintf() with the safer scnprintf()
variant
usb: gadget: Remove snprintf() from sysfs call-backs and replace with
sysfs_emit()
usb: gadget: f_tcm: Remove snprintf() from sysfs call-backs and
replace with sysfs_emit()
drivers/usb/atm/ueagle-atm.c | 16 +- drivers/usb/cdns3/cdnsp-debug.h | 354 ++++++++++++++-------------- drivers/usb/fotg210/fotg210-hcd.c | 12 +- drivers/usb/gadget/configfs.c | 2 +- drivers/usb/gadget/function/f_tcm.c | 4 +- 5 files changed, 192 insertions(+), 196 deletions(-)
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
PATCH 1/5 usb: atm: Remove snprintf() from sysfs call-backs and replace with sysfs_emit()
Since snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion.
In the case of sysfs call-backs, new wrappers exist that do just that.
This patch replaces the 2 uses of snprintf() found in the sysfs .show() call-backs with the new sysfs_emit() helpers. Whist we're at it, let's replace the sprintf()s as well. For no other reason than consistency.
--- drivers/usb/atm/ueagle-atm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/usb/atm/ueagle-atm.c +8 -8
@@ -2252,7 +2252,7 @@ static ssize_t stat_status_show(struct device *dev, struct device_attribute *att sc =dev_to_uea (dev);if (!sc) goto out; - ret =snprintf (buf,10 ,"%08x\n" , sc->stats.phy.state); + ret =sysfs_emit (buf,"%08x\n" , sc->stats.phy.state); out:mutex_unlock (&uea_mutex);return ret;
@@ -2318,19 +2318,19 @@ static ssize_t stat_human_status_show(struct device *dev,switch (modem_state) {case 0 : - ret =sprintf (buf,"Modem is booting\n" ); + ret =sysfs_emit (buf,"Modem is booting\n" );break ;case 1 : - ret =sprintf (buf,"Modem is initializing\n" ); + ret =sysfs_emit (buf,"Modem is initializing\n" );break ;case 2 : - ret =sprintf (buf,"Modem is operational\n" ); + ret =sysfs_emit (buf,"Modem is operational\n" );break ;case 3 : - ret =sprintf (buf,"Modem synchronization failed\n" ); + ret =sysfs_emit (buf,"Modem synchronization failed\n" );break ;default : - ret =sprintf (buf,"Modem state is unknown\n" ); + ret =sysfs_emit (buf,"Modem state is unknown\n" );break ; } out:
@@ -2364,7 +2364,7 @@ static ssize_t stat_delin_show(struct device *dev, struct device_attribute *attr delin ="LOSS" ; } - ret =sprintf (buf,"%s\n" , delin); + ret =sysfs_emit (buf,"%s\n" , delin); out:mutex_unlock (&uea_mutex);return ret;
@@ -2384,7 +2384,7 @@ static ssize_t stat_##name##_show(struct device *dev, \ sc =dev_to_uea (dev); \if (!sc) \ goto out; \ - ret =snprintf (buf,10 ,"%08x\n" , sc->stats.phy.name); \ + ret =sysfs_emit (buf,"%08x\n" , sc->stats.phy.name); \if (reset) \ sc->stats.phy.name =0 ; \ out: \
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
PATCH 2/5 usb: cdnsp: Replace snprintf() with the safer scnprintf() variant
In reply to Lee JonesThere 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!
--- drivers/usb/cdns3/cdnsp-debug.h | 354 ++++++++++++++++---------------- 1 file changed, 177 insertions(+), 177 deletions(-)
drivers/usb/cdns3/cdnsp-debug.h +177 -177
@@ -187,202 +187,202 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,switch (type) {case TRB_LINK : - ret =snprintf (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), - field3 &TRB_IOC ?'I' :'i' , - field3 &TRB_CHAIN ?'C' :'c' , - field3 &TRB_TC ?'T' :'t' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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), + field3 &TRB_IOC ?'I' :'i' , + field3 &TRB_CHAIN ?'C' :'c' , + field3 &TRB_TC ?'T' :'t' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_TRANSFER :case TRB_COMPLETION :case TRB_PORT_STATUS :case TRB_HC_EVENT : - ret =snprintf (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" , -TRB_TO_EP_INDEX (field3), -cdnsp_trb_type_string (type), field1, field0, -cdnsp_trb_comp_code_string (GET_COMP_CODE (field2)), -EVENT_TRB_LEN (field2),TRB_TO_SLOT_ID (field3), - field3 &EVENT_DATA ?'E' :'e' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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" , +TRB_TO_EP_INDEX (field3), +cdnsp_trb_type_string (type), field1, field0, +cdnsp_trb_comp_code_string (GET_COMP_CODE (field2)), +EVENT_TRB_LEN (field2),TRB_TO_SLOT_ID (field3), + field3 &EVENT_DATA ?'E' :'e' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_MFINDEX_WRAP : - ret =snprintf (str, size,"%s: flags %c" , -cdnsp_trb_type_string (type), - field3 &TRB_CYCLE ?'C' :'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, -"type '%s' bRequestType %02x bRequest %02x " -"wValue %02x%02x wIndex %02x%02x wLength %d " -"length %ld TD size %ld intr %ld Setup ID %ld " -"flags %c:%c:%c" , -cdnsp_trb_type_string (type), - field0 &0xff , - (field0 &0xff00 ) >>8 , - (field0 &0xff000000 ) >>24 , - (field0 &0xff0000 ) >>16 , - (field1 &0xff00 ) >>8 , - field1 &0xff , - (field1 &0xff000000 ) >>16 | - (field1 &0xff0000 ) >>16 , -TRB_LEN (field2),GET_TD_SIZE (field2), -GET_INTR_TARGET (field2), -TRB_SETUPID_TO_TYPE (field3), - field3 &TRB_IDT ?'D' :'d' , - field3 &TRB_IOC ?'I' :'i' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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 " +"flags %c:%c:%c" , +cdnsp_trb_type_string (type), + field0 &0xff , + (field0 &0xff00 ) >>8 , + (field0 &0xff000000 ) >>24 , + (field0 &0xff0000 ) >>16 , + (field1 &0xff00 ) >>8 , + field1 &0xff , + (field1 &0xff000000 ) >>16 | + (field1 &0xff0000 ) >>16 , +TRB_LEN (field2),GET_TD_SIZE (field2), +GET_INTR_TARGET (field2), +TRB_SETUPID_TO_TYPE (field3), + field3 &TRB_IDT ?'D' :'d' , + field3 &TRB_IOC ?'I' :'i' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_DATA : - ret =snprintf (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), - field1, field0,TRB_LEN (field2), -GET_TD_SIZE (field2), -GET_INTR_TARGET (field2), - field3 &TRB_IDT ?'D' :'i' , - field3 &TRB_IOC ?'I' :'i' , - field3 &TRB_CHAIN ?'C' :'c' , - field3 &TRB_NO_SNOOP ?'S' :'s' , - field3 &TRB_ISP ?'I' :'i' , - field3 &TRB_ENT ?'E' :'e' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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), + field1, field0,TRB_LEN (field2), +GET_TD_SIZE (field2), +GET_INTR_TARGET (field2), + field3 &TRB_IDT ?'D' :'i' , + field3 &TRB_IOC ?'I' :'i' , + field3 &TRB_CHAIN ?'C' :'c' , + field3 &TRB_NO_SNOOP ?'S' :'s' , + field3 &TRB_ISP ?'I' :'i' , + field3 &TRB_ENT ?'E' :'e' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_STATUS : - ret =snprintf (str, size, -"Buffer %08x%08x length %ld TD size %ld intr" -"%ld type '%s' flags %c:%c:%c:%c" , - field1, field0,TRB_LEN (field2), -GET_TD_SIZE (field2), -GET_INTR_TARGET (field2), -cdnsp_trb_type_string (type), - field3 &TRB_IOC ?'I' :'i' , - field3 &TRB_CHAIN ?'C' :'c' , - field3 &TRB_ENT ?'E' :'e' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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), +GET_TD_SIZE (field2), +GET_INTR_TARGET (field2), +cdnsp_trb_type_string (type), + field3 &TRB_IOC ?'I' :'i' , + field3 &TRB_CHAIN ?'C' :'c' , + field3 &TRB_ENT ?'E' :'e' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_NORMAL :case TRB_ISOC :case TRB_EVENT_DATA :case TRB_TR_NOOP : - ret =snprintf (str, size, -"type '%s' Buffer %08x%08x length %ld " -"TD size %ld intr %ld " -"flags %c:%c:%c:%c:%c:%c:%c:%c:%c" , -cdnsp_trb_type_string (type), - field1, field0,TRB_LEN (field2), -GET_TD_SIZE (field2), -GET_INTR_TARGET (field2), - field3 &TRB_BEI ?'B' :'b' , - field3 &TRB_IDT ?'T' :'t' , - field3 &TRB_IOC ?'I' :'i' , - field3 &TRB_CHAIN ?'C' :'c' , - field3 &TRB_NO_SNOOP ?'S' :'s' , - field3 &TRB_ISP ?'I' :'i' , - field3 &TRB_ENT ?'E' :'e' , - field3 &TRB_CYCLE ?'C' :'c' , - !(field3 &TRB_EVENT_INVALIDATE ) ?'V' :'v' ); + 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" , +cdnsp_trb_type_string (type), + field1, field0,TRB_LEN (field2), +GET_TD_SIZE (field2), +GET_INTR_TARGET (field2), + field3 &TRB_BEI ?'B' :'b' , + field3 &TRB_IDT ?'T' :'t' , + field3 &TRB_IOC ?'I' :'i' , + field3 &TRB_CHAIN ?'C' :'c' , + field3 &TRB_NO_SNOOP ?'S' :'s' , + field3 &TRB_ISP ?'I' :'i' , + field3 &TRB_ENT ?'E' :'e' , + field3 &TRB_CYCLE ?'C' :'c' , + !(field3 &TRB_EVENT_INVALIDATE ) ?'V' :'v' );break ;case TRB_CMD_NOOP :case TRB_ENABLE_SLOT : - ret =snprintf (str, size,"%s: flags %c" , -cdnsp_trb_type_string (type), - field3 &TRB_CYCLE ?'C' :'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" , -cdnsp_trb_type_string (type), -TRB_TO_SLOT_ID (field3), - field3 &TRB_CYCLE ?'C' :'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, -"%s: ctx %08x%08x slot %ld flags %c:%c" , -cdnsp_trb_type_string (type), field1, field0, -TRB_TO_SLOT_ID (field3), - field3 &TRB_BSR ?'B' :'b' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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), + field3 &TRB_BSR ?'B' :'b' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_CONFIG_EP : - ret =snprintf (str, size, -"%s: ctx %08x%08x slot %ld flags %c:%c" , -cdnsp_trb_type_string (type), field1, field0, -TRB_TO_SLOT_ID (field3), - field3 &TRB_DC ?'D' :'d' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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), + field3 &TRB_DC ?'D' :'d' , + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_EVAL_CONTEXT : - ret =snprintf (str, size, -"%s: ctx %08x%08x slot %ld flags %c" , -cdnsp_trb_type_string (type), field1, field0, -TRB_TO_SLOT_ID (field3), - field3 &TRB_CYCLE ?'C' :'c' ); + ret =scnprintf (str, size, +"%s: ctx %08x%08x slot %ld flags %c" , +cdnsp_trb_type_string (type), field1, field0, +TRB_TO_SLOT_ID (field3), + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_RESET_EP :case TRB_HALT_ENDPOINT : - ret =snprintf (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" , -TRB_TO_EP_INDEX (field3), field1, field0, -TRB_TO_SLOT_ID (field3), - field3 &TRB_CYCLE ?'C' :'c' ); + 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" , +TRB_TO_EP_INDEX (field3), field1, field0, +TRB_TO_SLOT_ID (field3), + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_STOP_RING : - ret =snprintf (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" , -TRB_TO_EP_INDEX (field3), -TRB_TO_SLOT_ID (field3), -TRB_TO_SUSPEND_PORT (field3), - field3 &TRB_CYCLE ?'C' :'c' ); + 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" , +TRB_TO_EP_INDEX (field3), +TRB_TO_SLOT_ID (field3), +TRB_TO_SUSPEND_PORT (field3), + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_SET_DEQ : - ret =snprintf (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" , -TRB_TO_EP_INDEX (field3), field1, field0, -TRB_TO_STREAM_ID (field2), -TRB_TO_SLOT_ID (field3), - field3 &TRB_CYCLE ?'C' :'c' ); + 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" , +TRB_TO_EP_INDEX (field3), field1, field0, +TRB_TO_STREAM_ID (field2), +TRB_TO_SLOT_ID (field3), + field3 &TRB_CYCLE ?'C' :'c' );break ;case TRB_RESET_DEV : - ret =snprintf (str, size,"%s: slot %ld flags %c" , -cdnsp_trb_type_string (type), -TRB_TO_SLOT_ID (field3), - field3 &TRB_CYCLE ?'C' :'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_ENDPOINT_NRDY : temp =TRB_TO_HOST_STREAM (field2); - ret =snprintf (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" , -TRB_TO_EP_INDEX (field3), temp, - temp ==STREAM_PRIME_ACK ?"(PRIME)" :"" , - temp ==STREAM_REJECTED ?"(REJECTED)" :"" , -TRB_TO_DEV_STREAM (field0), - field3 &TRB_STAT ?'S' :'s' , - field3 &TRB_CYCLE ?'C' :'c' ); + 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" , +TRB_TO_EP_INDEX (field3), temp, + temp ==STREAM_PRIME_ACK ?"(PRIME)" :"" , + temp ==STREAM_REJECTED ?"(REJECTED)" :"" , +TRB_TO_DEV_STREAM (field0), + field3 &TRB_STAT ?'S' :'s' , + field3 &TRB_CYCLE ?'C' :'c' );break ;default : - ret =snprintf (str, size, -"type '%s' -> raw %08x %08x %08x %08x" , -cdnsp_trb_type_string (type), - field0, field1, field2, field3); + 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,32 +465,32 @@ 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 " , - portsc &PORT_POWER ?"Powered" :"Powered-off" , - portsc &PORT_CONNECT ?"Connected" :"Not-connected" , - portsc &PORT_PED ?"Enabled" :"Disabled" , -cdnsp_portsc_link_state_string (portsc), -DEV_PORT_SPEED (portsc)); + 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" , +cdnsp_portsc_link_state_string (portsc), +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" , -cdnsp_ep_state_string (ep_state), mult, - max_pstr, lsa ?"LSA " :"" ); + 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, -"interval %d us max ESIT payload %d CErr %d " , - (1 << interval) *125 , esit, cerr); + 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, -"Type %s %sburst %d maxp %d deq %016llx " , -cdnsp_ep_type_string (ep_type), hid ?"HID" :"" , - burst, maxp, deq); + 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; }
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
PATCH 3/5 usb: fotg210-hcd: Replace snprintf() with the safer scnprintf() variant
In reply to Lee JonesThere 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 both seem to assume that data *has been* written!
--- drivers/usb/fotg210/fotg210-hcd.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/usb/fotg210/fotg210-hcd.c +4 -8
@@ -404,9 +404,9 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,else if (td->hw_alt_next != list_end) mark ='/' ; } - temp = snprintf(next, size, - "\n\t%p%c%s len=%d %08x urb %p", - td, mark, ({ char *tmp; + temp = scnprintf(next, size, + "\n\t%p%c%s len=%d %08x urb %p", + td, mark, ({ char *tmp; switch ((scratch>>8)&0x03) { case 0: tmp = "out";
@@ -424,17 +424,13 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, (scratch >>16 ) &0x7fff , scratch, td->urb); -if (size < temp) - temp = size; size -= temp; next += temp;if (temp == size) goto done; } - temp =snprintf (next, size,"\n" ); -if (size < temp) - temp = size; + temp =scnprintf (next, size,"\n" ); size -= temp; next += temp;
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
RE: [PATCH 3/5] usb: fotg210-hcd: Replace snprintf() with the safer scnprintf() variant
From: Lee Jones
Quoted 12 lines
Sent: 30 November 2023 10:55
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 both seem to assume that data *has been* written!
...
Quoted 3 lines
drivers/usb/fotg210/fotg210-hcd.c +0
-3- temp = snprintf(next, size, - "\n\t%p%c%s len=%d %08x urb %p", - td, mark, ({ char *tmp;
...
Review
Quoted 2 lines
(quoted diff) +0
-2- if (size < temp) - temp = size;
That is actually a bug - even though it is trying to be correct. The trailing '\0' that snprintf() adds (unless you are using the M$ one) will end up in the buffer.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH 3/5] usb: fotg210-hcd: Replace snprintf() with the safer scnprintf() variant
In reply to Lee JonesQuoted 11 lines · Lee Jones
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 both seem to assume that data *has been* written!
Quoted 9 lines
Cc Linus Walleij <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Cc Yuan-Hsin Chen <[email protected]>Cc Feng-Hsin Chiang <[email protected]>Cc Po-Yu Chuang <[email protected]>Signed-off-by Lee Jones <[email protected]>
Thanks for doing this Lee!
And as David points out it is even a bug fix at the same time.
Yours,
Linus Walleij
PATCH 4/5 usb: gadget: Remove snprintf() from sysfs call-backs and replace with sysfs_emit()
In reply to Lee JonesSince snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion.
In the case of sysfs call-backs, new wrappers exist that do just that.
This patch replaces just one use of snprintf() found in the sysfs .show() call-back with the new sysfs_emit() helper.
--- drivers/usb/gadget/configfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/configfs.c +1 -1
@@ -812,7 +812,7 @@ static ssize_t gadget_string_s_show(struct config_item *item, char *page)struct gadget_string *string =to_gadget_string (item);int ret; - ret =snprintf (page,sizeof (string->string),"%s\n" , string->string); + ret =sysfs_emit (page,"%s\n" , string->string);return ret; }
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
PATCH 5/5 usb: gadget: f_tcm: Remove snprintf() from sysfs call-backs and replace with sysfs_emit()
In reply to Lee JonesSince snprintf() has the documented, but still rather strange trait of returning the length of the data that *would have been* written to the array if space were available, rather than the arguably more useful length of data *actually* written, it is usually considered wise to use something else instead in order to avoid confusion.
In the case of sysfs call-backs, new wrappers exist that do just that.
This patch replaces just one use of snprintf() found in the sysfs .show() call-back with the new sysfs_emit() helper.
--- drivers/usb/gadget/function/f_tcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/gadget/function/f_tcm.c +2 -2
@@ -1504,8 +1504,8 @@ static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page) ret = -ENODEV ; goto out; } - ret =snprintf (page,PAGE_SIZE ,"%s\n" , - tv_nexus->tvn_se_sess->se_node_acl->initiatorname); + ret =sysfs_emit (page,"%s\n" , + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); out:mutex_unlock (&tpg->tpg_mutex);return ret;
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog