Coverage Report

Created: 2024-02-25 06:24

/src/libpcap/pcap-usb-linux-common.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 1993, 1994, 1995, 1996, 1997
3
 *  The Regents of the University of California.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that: (1) source code distributions
7
 * retain the above copyright notice and this paragraph in its entirety, (2)
8
 * distributions including binary code include the above copyright notice and
9
 * this paragraph in its entirety in the documentation or other materials
10
 * provided with the distribution, and (3) all advertising materials mentioning
11
 * features or use of this software display the following acknowledgement:
12
 * ``This product includes software developed by the University of California,
13
 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14
 * the University nor the names of its contributors may be used to endorse
15
 * or promote products derived from this software without specific prior
16
 * written permission.
17
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20
 *
21
 * pcap-usb-linux-common.c - common code for everything that needs to
22
 * deal with Linux USB captures.
23
 */
24
25
#include <limits.h> /* for UINT_MAX */
26
27
#include "pcap/pcap.h"
28
#include "pcap/usb.h"
29
30
#include "pcap-usb-linux-common.h"
31
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
13.8k
{
39
13.8k
  return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX);
40
13.8k
}
41
42
/*
43
 * Compute, from the data provided by the Linux USB memory-mapped capture
44
 * mechanism, the amount of packet data that would have been provided
45
 * had the capture mechanism not chopped off any data at the end, if, in
46
 * fact, it did so.
47
 *
48
 * Set the "unsliced length" field of the packet header to that value.
49
 */
50
void
51
fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
52
3.24k
{
53
3.24k
  const pcap_usb_header_mmapped *hdr;
54
3.24k
  u_int bytes_left;
55
56
  /*
57
   * All callers of this routine must ensure that pkth->caplen is
58
   * >= sizeof (pcap_usb_header_mmapped).
59
   */
60
3.24k
  bytes_left = pkth->caplen;
61
3.24k
  bytes_left -= sizeof (pcap_usb_header_mmapped);
62
63
3.24k
  hdr = (const pcap_usb_header_mmapped *) bp;
64
3.24k
  if (!hdr->data_flag && hdr->transfer_type == URB_ISOCHRONOUS &&
65
3.24k
      hdr->event_type == URB_COMPLETE &&
66
3.24k
      (hdr->endpoint_number & URB_TRANSFER_IN) &&
67
3.24k
      pkth->len == sizeof(pcap_usb_header_mmapped) +
68
1.67k
                   (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len) {
69
1.67k
    usb_isodesc *descs;
70
1.67k
    u_int pre_truncation_descriptors_len;
71
1.67k
    u_int pre_truncation_header_len;
72
1.67k
    u_int pre_truncation_data_len;
73
1.67k
    u_int pre_truncation_len;
74
75
1.67k
    descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped));
76
77
    /*
78
     * We have data (yes, data_flag is 0 if we *do* have data),
79
     * and this is a "this is complete" incoming isochronous
80
     * transfer event, and the length was calculated based
81
     * on the URB length.
82
     *
83
     * That's not correct, because the data isn't contiguous,
84
     * and the isochronous descriptors show how it's scattered.
85
     *
86
     * Find the end of the last chunk of data in the buffer
87
     * referred to by the isochronous descriptors; that indicates
88
     * how far into the buffer the data would have gone.
89
     *
90
     * Make sure we don't run past the end of the captured data
91
     * while processing the isochronous descriptors.
92
     */
93
1.67k
    pre_truncation_data_len = 0;
94
1.67k
    for (uint32_t desc = 0;
95
17.8k
        desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc);
96
16.1k
        desc++, bytes_left -= sizeof (usb_isodesc)) {
97
16.1k
      u_int desc_end;
98
99
16.1k
      if (descs[desc].len != 0) {
100
        /*
101
         * Compute the end offset of the data
102
         * for this descriptor, i.e. the offset
103
         * of the byte after the data.  Clamp
104
         * the sum at UINT_MAX, so that it fits
105
         * in a u_int.
106
         */
107
10.4k
        desc_end = u_int_sum(descs[desc].offset,
108
10.4k
            descs[desc].len);
109
10.4k
        if (desc_end > pre_truncation_data_len)
110
1.17k
          pre_truncation_data_len = desc_end;
111
10.4k
      }
112
16.1k
    }
113
114
    /*
115
     * Now calculate the total length based on that data
116
     * 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
1.67k
    if (hdr->ndesc < (UINT_MAX + (uint64_t)1) / sizeof (usb_isodesc)) {
129
      /*
130
       * It fits.
131
       */
132
1.67k
      pre_truncation_descriptors_len =
133
1.67k
          hdr->ndesc * sizeof (usb_isodesc);
134
1.67k
    } else {
135
      /*
136
       * It doesn't fit.
137
       */
138
0
      pre_truncation_descriptors_len = UINT_MAX;
139
0
    }
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
1.67k
    pre_truncation_header_len = u_int_sum(sizeof(pcap_usb_header_mmapped),
147
1.67k
        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.
153
     */
154
1.67k
                pre_truncation_len = u_int_sum(pre_truncation_header_len,
155
1.67k
        pre_truncation_data_len);
156
157
    /*
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.
161
     */
162
1.67k
    if (pre_truncation_len >= pkth->caplen)
163
1.27k
      pkth->len = pre_truncation_len;
164
165
    /*
166
     * If the captured length is greater than the length,
167
     * use the captured length.
168
     *
169
     * For completion events for incoming isochronous transfers,
170
     * it's based on data_len, which is calculated the same way
171
     * we calculated pre_truncation_data_len above, except that
172
     * it has access to all the isochronous descriptors, not
173
     * just the ones that the kernel were able to provide us or,
174
     * for a capture file, that weren't sliced off by a snapshot
175
     * length.
176
     *
177
     * However, it might have been reduced by the USB capture
178
     * mechanism arbitrarily limiting the amount of data it
179
     * provides to userland, or by the libpcap capture code
180
     * limiting it to being no more than the snapshot, so
181
     * we don't want to just use it all the time; we only
182
     * do so to try to get a better estimate of the actual
183
     * length - and to make sure the on-the-network length
184
     * is always >= the captured length.
185
     */
186
1.67k
    if (pkth->caplen > pkth->len)
187
398
      pkth->len = pkth->caplen;
188
1.67k
  }
189
3.24k
}