2222 * deal with Linux USB captures.
2323 */
2424
25+ #include <limits.h> /* for UINT_MAX */
26+
2527#include "pcap/pcap.h"
2628#include "pcap/usb.h"
2729
2830#include "pcap-usb-linux-common.h"
2931
32+ /*
33+ * Return the sum of the two u_int arguments if that sum fits in a u_int,
34+ * and return UINT_MAX otherwise.
35+ */
36+ static inline u_int
37+ u_int_sum (u_int a , u_int b )
38+ {
39+ return (((b ) <= UINT_MAX - (b )) ? (a ) + (b ) : UINT_MAX );
40+ }
41+
3042/*
3143 * Compute, from the data provided by the Linux USB memory-mapped capture
3244 * mechanism, the amount of packet data that would have been provided
@@ -55,7 +67,10 @@ fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
5567 pkth -> len == sizeof (pcap_usb_header_mmapped ) +
5668 (hdr -> ndesc * sizeof (usb_isodesc )) + hdr -> urb_len ) {
5769 usb_isodesc * descs ;
58- u_int pre_truncation_data_len , pre_truncation_len ;
70+ u_int pre_truncation_descriptors_len ;
71+ u_int pre_truncation_header_len ;
72+ u_int pre_truncation_data_len ;
73+ u_int pre_truncation_len ;
5974
6075 descs = (usb_isodesc * ) (bp + sizeof (pcap_usb_header_mmapped ));
6176
@@ -82,7 +97,15 @@ fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
8297 u_int desc_end ;
8398
8499 if (descs [desc ].len != 0 ) {
85- desc_end = descs [desc ].offset + descs [desc ].len ;
100+ /*
101+ * Compute the end offset of the data
102+ * for this descriptor, i.e. the offset
103+ * of the byte after te data. Clamp
104+ * the sum at UINT_MAX, so that it fits
105+ * in a u_int.
106+ */
107+ desc_end = u_int_sum (descs [desc ].offset ,
108+ descs [desc ].len );
86109 if (desc_end > pre_truncation_data_len )
87110 pre_truncation_data_len = desc_end ;
88111 }
@@ -91,14 +114,50 @@ fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
91114 /*
92115 * Now calculate the total length based on that data
93116 * length.
117+ *
118+ * First, make sure the total length of the ISO
119+ * descriptors fits in an unsigned int. We know
120+ * that sizeof (usb_isodesc) is a small power-of-2
121+ * integer (16 bytes), so we just check whether
122+ * hdr->ndesc < (UINT_MAX + (uint64_t)1) / sizeof (usb_isodesc),
123+ * as that would mean that hdr->ndesc * sizeof (usb_isodesc)
124+ * is < (UINT_MAX + (uint64_t)1) and thus <= UINT_MAX.
125+ * ((UINT_MAX + (uint64_t)1) will probably be computed
126+ * at compile time with most C compilers.)
127+ */
128+ if (hdr -> ndesc < (UINT_MAX + (uint64_t )1 ) / sizeof (usb_isodesc )) {
129+ /*
130+ * It fits.
131+ */
132+ pre_truncation_descriptors_len =
133+ hdr -> ndesc * sizeof (usb_isodesc );
134+ } else {
135+ /*
136+ * It doesn't fit.
137+ */
138+ pre_truncation_descriptors_len = UINT_MAX ;
139+ }
140+
141+ /*
142+ * Now, add the length of the memory-mapped header and
143+ * the length of the ISO descriptors, clamping the
144+ * result at UINT_MAX.
145+ */
146+ pre_truncation_header_len = u_int_sum (sizeof (pcap_usb_header_mmapped ),
147+ pre_truncation_descriptors_len );
148+
149+ /*
150+ * Now, add the total header length (memory-mapped header
151+ * and ISO descriptors) and the data length, clamping
152+ * the result at UINT_MAX.
94153 */
95- pre_truncation_len = sizeof (pcap_usb_header_mmapped ) +
96- (hdr -> ndesc * sizeof (usb_isodesc )) +
97- pre_truncation_data_len ;
154+ pre_truncation_len = u_int_sum (pre_truncation_header_len ,
155+ pre_truncation_data_len );
98156
99157 /*
100- * If that's greater than or equal to the captured length,
101- * use that as the length.
158+ * pre_truncation_len is now the smaller of
159+ * UINT_MAX and the total header plus data length.
160+ * That's guaranteed to fit in a UINT_MAX.
102161 */
103162 if (pre_truncation_len >= pkth -> caplen )
104163 pkth -> len = pre_truncation_len ;
0 commit comments