Coverage Report

Created: 2023-12-14 14:08

/src/libpcap/pcap-util.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-util.c - common code for various files
22
 */
23
24
#ifdef HAVE_CONFIG_H
25
#include <config.h>
26
#endif
27
28
#include <pcap-types.h>
29
30
#include "pcap-int.h"
31
#include "extract.h"
32
#include "pcap-usb-linux-common.h"
33
34
#include "pcap-util.h"
35
36
#include "pflog.h"
37
#include "pcap/can_socketcan.h"
38
#include "pcap/sll.h"
39
#include "pcap/usb.h"
40
#include "pcap/nflog.h"
41
42
/*
43
 * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields
44
 * that are saved in host byte order.
45
 *
46
 * When reading a DLT_PFLOG packet, we need to convert those fields from
47
 * the byte order of the host that wrote the file to this host's byte
48
 * order.
49
 */
50
static void
51
swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
52
55.3k
{
53
55.3k
  u_int caplen = hdr->caplen;
54
55.3k
  u_int length = hdr->len;
55
55.3k
  u_int pfloghdr_length;
56
55.3k
  struct pfloghdr *pflhdr = (struct pfloghdr *)buf;
57
58
55.3k
  if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) ||
59
55.3k
      length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
60
    /* Not enough data to have the uid field */
61
52.9k
    return;
62
52.9k
  }
63
64
2.40k
  pfloghdr_length = pflhdr->length;
65
66
2.40k
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
67
    /* Header doesn't include uid field */
68
822
    return;
69
822
  }
70
1.58k
  pflhdr->uid = SWAPLONG(pflhdr->uid);
71
72
1.58k
  if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) ||
73
1.58k
      length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
74
    /* Not enough data to have the pid field */
75
279
    return;
76
279
  }
77
1.30k
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
78
    /* Header doesn't include pid field */
79
136
    return;
80
136
  }
81
1.17k
  pflhdr->pid = SWAPLONG(pflhdr->pid);
82
83
1.17k
  if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) ||
84
1.17k
      length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
85
    /* Not enough data to have the rule_uid field */
86
139
    return;
87
139
  }
88
1.03k
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
89
    /* Header doesn't include rule_uid field */
90
139
    return;
91
139
  }
92
894
  pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid);
93
94
894
  if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) ||
95
894
      length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
96
    /* Not enough data to have the rule_pid field */
97
152
    return;
98
152
  }
99
742
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
100
    /* Header doesn't include rule_pid field */
101
143
    return;
102
143
  }
103
599
  pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid);
104
599
}
105
106
/*
107
 * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or
108
 * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload,
109
 * with the CAN ID being in host byte order.
110
 *
111
 * When reading a DLT_LINUX_SLL packet, we need to check for those
112
 * packets and convert the CAN ID from the byte order of the host that
113
 * wrote the file to this host's byte order.
114
 */
115
static void
116
swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
117
22.9k
{
118
22.9k
  u_int caplen = hdr->caplen;
119
22.9k
  u_int length = hdr->len;
120
22.9k
  struct sll_header *shdr = (struct sll_header *)buf;
121
22.9k
  uint16_t protocol;
122
22.9k
  pcap_can_socketcan_hdr *chdr;
123
124
22.9k
  if (caplen < (u_int) sizeof(struct sll_header) ||
125
22.9k
      length < (u_int) sizeof(struct sll_header)) {
126
    /* Not enough data to have the protocol field */
127
21.6k
    return;
128
21.6k
  }
129
130
1.34k
  protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
131
1.34k
  if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
132
1.01k
    return;
133
134
  /*
135
   * SocketCAN packet; fix up the packet's header.
136
   */
137
331
  chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
138
331
  if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
139
331
      length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
140
    /* Not enough data to have the CAN ID */
141
200
    return;
142
200
  }
143
131
  chdr->can_id = SWAPLONG(chdr->can_id);
144
131
}
145
146
/*
147
 * The same applies for DLT_LINUX_SLL2.
148
 */
149
static void
150
swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf)
151
32.0k
{
152
32.0k
  u_int caplen = hdr->caplen;
153
32.0k
  u_int length = hdr->len;
154
32.0k
  struct sll2_header *shdr = (struct sll2_header *)buf;
155
32.0k
  uint16_t protocol;
156
32.0k
  pcap_can_socketcan_hdr *chdr;
157
158
32.0k
  if (caplen < (u_int) sizeof(struct sll2_header) ||
159
32.0k
      length < (u_int) sizeof(struct sll2_header)) {
160
    /* Not enough data to have the protocol field */
161
30.7k
    return;
162
30.7k
  }
163
164
1.23k
  protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol);
165
1.23k
  if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
166
848
    return;
167
168
  /*
169
   * SocketCAN packet; fix up the packet's header.
170
   */
171
382
  chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header));
172
382
  if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) ||
173
382
      length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) {
174
    /* Not enough data to have the CAN ID */
175
180
    return;
176
180
  }
177
202
  chdr->can_id = SWAPLONG(chdr->can_id);
178
202
}
179
180
/*
181
 * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
182
 * byte order when capturing (it's supplied directly from a
183
 * memory-mapped buffer shared by the kernel).
184
 *
185
 * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we
186
 * need to convert it from the byte order of the host that wrote the
187
 * file to this host's byte order.
188
 */
189
static void
190
swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
191
    int header_len_64_bytes)
192
357k
{
193
357k
  pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
194
357k
  bpf_u_int32 offset = 0;
195
196
  /*
197
   * "offset" is the offset *past* the field we're swapping;
198
   * we skip the field *before* checking to make sure
199
   * the captured data length includes the entire field.
200
   */
201
202
  /*
203
   * The URB id is a totally opaque value; do we really need to
204
   * convert it to the reading host's byte order???
205
   */
206
357k
  offset += 8;      /* skip past id */
207
357k
  if (hdr->caplen < offset)
208
330k
    return;
209
26.3k
  uhdr->id = SWAPLL(uhdr->id);
210
211
26.3k
  offset += 4;      /* skip past various 1-byte fields */
212
213
26.3k
  offset += 2;      /* skip past bus_id */
214
26.3k
  if (hdr->caplen < offset)
215
1.76k
    return;
216
24.5k
  uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
217
218
24.5k
  offset += 2;      /* skip past various 1-byte fields */
219
220
24.5k
  offset += 8;      /* skip past ts_sec */
221
24.5k
  if (hdr->caplen < offset)
222
2.64k
    return;
223
21.9k
  uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
224
225
21.9k
  offset += 4;      /* skip past ts_usec */
226
21.9k
  if (hdr->caplen < offset)
227
2.52k
    return;
228
19.4k
  uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
229
230
19.4k
  offset += 4;      /* skip past status */
231
19.4k
  if (hdr->caplen < offset)
232
2.39k
    return;
233
17.0k
  uhdr->status = SWAPLONG(uhdr->status);
234
235
17.0k
  offset += 4;      /* skip past urb_len */
236
17.0k
  if (hdr->caplen < offset)
237
2.49k
    return;
238
14.5k
  uhdr->urb_len = SWAPLONG(uhdr->urb_len);
239
240
14.5k
  offset += 4;      /* skip past data_len */
241
14.5k
  if (hdr->caplen < offset)
242
1.10k
    return;
243
13.4k
  uhdr->data_len = SWAPLONG(uhdr->data_len);
244
245
13.4k
  if (uhdr->transfer_type == URB_ISOCHRONOUS) {
246
9.96k
    offset += 4;      /* skip past s.iso.error_count */
247
9.96k
    if (hdr->caplen < offset)
248
1.14k
      return;
249
8.82k
    uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
250
251
8.82k
    offset += 4;      /* skip past s.iso.numdesc */
252
8.82k
    if (hdr->caplen < offset)
253
1.09k
      return;
254
7.73k
    uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
255
7.73k
  } else
256
3.44k
    offset += 8;      /* skip USB setup header */
257
258
  /*
259
   * With the old header, there are no isochronous descriptors
260
   * after the header.
261
   *
262
   * With the new header, the actual number of descriptors in
263
   * the header is not s.iso.numdesc, it's ndesc - only the
264
   * first N descriptors, for some value of N, are put into
265
   * the header, and ndesc is set to the actual number copied.
266
   * In addition, if s.iso.numdesc is negative, no descriptors
267
   * are captured, and ndesc is set to 0.
268
   */
269
11.1k
  if (header_len_64_bytes) {
270
    /*
271
     * This is either the "version 1" header, with
272
     * 16 bytes of additional fields at the end, or
273
     * a "version 0" header from a memory-mapped
274
     * capture, with 16 bytes of zeroed-out padding
275
     * at the end.  Byte swap them as if this were
276
     * a "version 1" header.
277
     */
278
8.90k
    offset += 4;      /* skip past interval */
279
8.90k
    if (hdr->caplen < offset)
280
1.26k
      return;
281
7.63k
    uhdr->interval = SWAPLONG(uhdr->interval);
282
283
7.63k
    offset += 4;      /* skip past start_frame */
284
7.63k
    if (hdr->caplen < offset)
285
855
      return;
286
6.78k
    uhdr->start_frame = SWAPLONG(uhdr->start_frame);
287
288
6.78k
    offset += 4;      /* skip past xfer_flags */
289
6.78k
    if (hdr->caplen < offset)
290
447
      return;
291
6.33k
    uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
292
293
6.33k
    offset += 4;      /* skip past ndesc */
294
6.33k
    if (hdr->caplen < offset)
295
499
      return;
296
5.83k
    uhdr->ndesc = SWAPLONG(uhdr->ndesc);
297
298
5.83k
    if (uhdr->transfer_type == URB_ISOCHRONOUS) {
299
      /* swap the values in struct linux_usb_isodesc */
300
4.43k
      usb_isodesc *pisodesc;
301
4.43k
      uint32_t i;
302
303
4.43k
      pisodesc = (usb_isodesc *)(void *)(buf+offset);
304
36.2k
      for (i = 0; i < uhdr->ndesc; i++) {
305
33.9k
        offset += 4;    /* skip past status */
306
33.9k
        if (hdr->caplen < offset)
307
1.13k
          return;
308
32.8k
        pisodesc->status = SWAPLONG(pisodesc->status);
309
310
32.8k
        offset += 4;    /* skip past offset */
311
32.8k
        if (hdr->caplen < offset)
312
583
          return;
313
32.2k
        pisodesc->offset = SWAPLONG(pisodesc->offset);
314
315
32.2k
        offset += 4;    /* skip past len */
316
32.2k
        if (hdr->caplen < offset)
317
436
          return;
318
31.8k
        pisodesc->len = SWAPLONG(pisodesc->len);
319
320
31.8k
        offset += 4;    /* skip past padding */
321
322
31.8k
        pisodesc++;
323
31.8k
      }
324
4.43k
    }
325
5.83k
  }
326
11.1k
}
327
328
/*
329
 * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order
330
 * data.  They begin with a fixed-length header with big-endian fields,
331
 * followed by a set of TLVs, where the type and length are in host
332
 * byte order but the values are either big-endian or are a raw byte
333
 * sequence that's the same regardless of the host's byte order.
334
 *
335
 * When reading a DLT_NFLOG packet, we need to convert the type and
336
 * length values from the byte order of the host that wrote the file
337
 * to the byte order of this host.
338
 */
339
static void
340
swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
341
35.9k
{
342
35.9k
  u_char *p = buf;
343
35.9k
  nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
344
35.9k
  nflog_tlv_t *tlv;
345
35.9k
  u_int caplen = hdr->caplen;
346
35.9k
  u_int length = hdr->len;
347
35.9k
  uint16_t size;
348
349
35.9k
  if (caplen < (u_int) sizeof(nflog_hdr_t) ||
350
35.9k
      length < (u_int) sizeof(nflog_hdr_t)) {
351
    /* Not enough data to have any TLVs. */
352
32.1k
    return;
353
32.1k
  }
354
355
3.78k
  if (nfhdr->nflog_version != 0) {
356
    /* Unknown NFLOG version */
357
918
    return;
358
918
  }
359
360
2.86k
  length -= sizeof(nflog_hdr_t);
361
2.86k
  caplen -= sizeof(nflog_hdr_t);
362
2.86k
  p += sizeof(nflog_hdr_t);
363
364
4.31k
  while (caplen >= sizeof(nflog_tlv_t)) {
365
3.24k
    tlv = (nflog_tlv_t *) p;
366
367
    /* Swap the type and length. */
368
3.24k
    tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
369
3.24k
    tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
370
371
    /* Get the length of the TLV. */
372
3.24k
    size = tlv->tlv_length;
373
3.24k
    if (size % 4 != 0)
374
1.59k
      size += 4 - size % 4;
375
376
    /* Is the TLV's length less than the minimum? */
377
3.24k
    if (size < sizeof(nflog_tlv_t)) {
378
      /* Yes. Give up now. */
379
1.01k
      return;
380
1.01k
    }
381
382
    /* Do we have enough data for the full TLV? */
383
2.22k
    if (caplen < size || length < size) {
384
      /* No. */
385
777
      return;
386
777
    }
387
388
    /* Skip over the TLV. */
389
1.45k
    length -= size;
390
1.45k
    caplen -= size;
391
1.45k
    p += size;
392
1.45k
  }
393
2.86k
}
394
395
static void
396
swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
397
866k
{
398
  /*
399
   * Convert pseudo-headers from the byte order of
400
   * the host on which the file was saved to our
401
   * byte order, as necessary.
402
   */
403
866k
  switch (linktype) {
404
405
55.3k
  case DLT_PFLOG:
406
55.3k
    swap_pflog_header(hdr, data);
407
55.3k
    break;
408
409
22.9k
  case DLT_LINUX_SLL:
410
22.9k
    swap_linux_sll_header(hdr, data);
411
22.9k
    break;
412
413
32.0k
  case DLT_LINUX_SLL2:
414
32.0k
    swap_linux_sll2_header(hdr, data);
415
32.0k
    break;
416
417
143k
  case DLT_USB_LINUX:
418
143k
    swap_linux_usb_header(hdr, data, 0);
419
143k
    break;
420
421
213k
  case DLT_USB_LINUX_MMAPPED:
422
213k
    swap_linux_usb_header(hdr, data, 1);
423
213k
    break;
424
425
35.9k
  case DLT_NFLOG:
426
35.9k
    swap_nflog_header(hdr, data);
427
35.9k
    break;
428
866k
  }
429
866k
}
430
431
void
432
pcap_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr,
433
    u_char *data)
434
1.20M
{
435
1.20M
  if (swapped)
436
866k
    swap_pseudo_headers(linktype, hdr, data);
437
438
1.20M
  fixup_pcap_pkthdr(linktype, hdr, data);
439
1.20M
}
440
441
void
442
fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
443
1.20M
{
444
1.20M
  const pcap_usb_header_mmapped *usb_hdr;
445
446
1.20M
  usb_hdr = (const pcap_usb_header_mmapped *) data;
447
1.20M
  if (linktype == DLT_USB_LINUX_MMAPPED &&
448
1.20M
      hdr->caplen >= sizeof (pcap_usb_header_mmapped)) {
449
    /*
450
     * In older versions of libpcap, in memory-mapped captures,
451
     * the "on-the-bus length" for completion events for
452
     * incoming isochronous transfers was miscalculated; it
453
     * needed to be calculated based on the* offsets and lengths
454
     * in the descriptors, not on the raw URB length, but it
455
     * wasn't.
456
     *
457
     * If this packet contains transferred data (yes, data_flag
458
     * is 0 if we *do* have data), and the total on-the-network
459
     * length is equal to the value calculated from the raw URB
460
     * length, then it might be one of those transfers.
461
     *
462
     * We only do this if we have the full USB pseudo-header.
463
     */
464
6.46k
    if (!usb_hdr->data_flag &&
465
6.46k
        hdr->len == sizeof(pcap_usb_header_mmapped) +
466
5.11k
          (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) {
467
      /*
468
       * It might need fixing; fix it if it's a completion
469
       * event for an incoming isochronous transfer.
470
       */
471
1.04k
      fix_linux_usb_mmapped_length(hdr, data);
472
1.04k
    }
473
6.46k
  }
474
1.20M
}