Coverage Report

Created: 2023-03-06 09:48

/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
1.26k
{
53
1.26k
  u_int caplen = hdr->caplen;
54
1.26k
  u_int length = hdr->len;
55
1.26k
  u_int pfloghdr_length;
56
1.26k
  struct pfloghdr *pflhdr = (struct pfloghdr *)buf;
57
58
1.26k
  if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) ||
59
1.26k
      length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
60
    /* Not enough data to have the uid field */
61
805
    return;
62
805
  }
63
64
460
  pfloghdr_length = pflhdr->length;
65
66
460
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
67
    /* Header doesn't include uid field */
68
95
    return;
69
95
  }
70
365
  pflhdr->uid = SWAPLONG(pflhdr->uid);
71
72
365
  if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) ||
73
365
      length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
74
    /* Not enough data to have the pid field */
75
80
    return;
76
80
  }
77
285
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
78
    /* Header doesn't include pid field */
79
21
    return;
80
21
  }
81
264
  pflhdr->pid = SWAPLONG(pflhdr->pid);
82
83
264
  if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) ||
84
264
      length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
85
    /* Not enough data to have the rule_uid field */
86
64
    return;
87
64
  }
88
200
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
89
    /* Header doesn't include rule_uid field */
90
31
    return;
91
31
  }
92
169
  pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid);
93
94
169
  if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) ||
95
169
      length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
96
    /* Not enough data to have the rule_pid field */
97
76
    return;
98
76
  }
99
93
  if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
100
    /* Header doesn't include rule_pid field */
101
14
    return;
102
14
  }
103
79
  pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid);
104
79
}
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
921
{
118
921
  u_int caplen = hdr->caplen;
119
921
  u_int length = hdr->len;
120
921
  struct sll_header *shdr = (struct sll_header *)buf;
121
921
  uint16_t protocol;
122
921
  pcap_can_socketcan_hdr *chdr;
123
124
921
  if (caplen < (u_int) sizeof(struct sll_header) ||
125
921
      length < (u_int) sizeof(struct sll_header)) {
126
    /* Not enough data to have the protocol field */
127
668
    return;
128
668
  }
129
130
253
  protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
131
253
  if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
132
192
    return;
133
134
  /*
135
   * SocketCAN packet; fix up the packet's header.
136
   */
137
61
  chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
138
61
  if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
139
61
      length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
140
    /* Not enough data to have the CAN ID */
141
30
    return;
142
30
  }
143
31
  chdr->can_id = SWAPLONG(chdr->can_id);
144
31
}
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
947
{
152
947
  u_int caplen = hdr->caplen;
153
947
  u_int length = hdr->len;
154
947
  struct sll2_header *shdr = (struct sll2_header *)buf;
155
947
  uint16_t protocol;
156
947
  pcap_can_socketcan_hdr *chdr;
157
158
947
  if (caplen < (u_int) sizeof(struct sll2_header) ||
159
947
      length < (u_int) sizeof(struct sll2_header)) {
160
    /* Not enough data to have the protocol field */
161
742
    return;
162
742
  }
163
164
205
  protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol);
165
205
  if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
166
110
    return;
167
168
  /*
169
   * SocketCAN packet; fix up the packet's header.
170
   */
171
95
  chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header));
172
95
  if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) ||
173
95
      length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) {
174
    /* Not enough data to have the CAN ID */
175
32
    return;
176
32
  }
177
63
  chdr->can_id = SWAPLONG(chdr->can_id);
178
63
}
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
4.32k
{
193
4.32k
  pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
194
4.32k
  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
4.32k
  offset += 8;      /* skip past id */
207
4.32k
  if (hdr->caplen < offset)
208
2.02k
    return;
209
2.30k
  uhdr->id = SWAPLL(uhdr->id);
210
211
2.30k
  offset += 4;      /* skip past various 1-byte fields */
212
213
2.30k
  offset += 2;      /* skip past bus_id */
214
2.30k
  if (hdr->caplen < offset)
215
154
    return;
216
2.14k
  uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
217
218
2.14k
  offset += 2;      /* skip past various 1-byte fields */
219
220
2.14k
  offset += 8;      /* skip past ts_sec */
221
2.14k
  if (hdr->caplen < offset)
222
282
    return;
223
1.86k
  uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
224
225
1.86k
  offset += 4;      /* skip past ts_usec */
226
1.86k
  if (hdr->caplen < offset)
227
143
    return;
228
1.72k
  uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
229
230
1.72k
  offset += 4;      /* skip past status */
231
1.72k
  if (hdr->caplen < offset)
232
159
    return;
233
1.56k
  uhdr->status = SWAPLONG(uhdr->status);
234
235
1.56k
  offset += 4;      /* skip past urb_len */
236
1.56k
  if (hdr->caplen < offset)
237
178
    return;
238
1.38k
  uhdr->urb_len = SWAPLONG(uhdr->urb_len);
239
240
1.38k
  offset += 4;      /* skip past data_len */
241
1.38k
  if (hdr->caplen < offset)
242
133
    return;
243
1.25k
  uhdr->data_len = SWAPLONG(uhdr->data_len);
244
245
1.25k
  if (uhdr->transfer_type == URB_ISOCHRONOUS) {
246
838
    offset += 4;      /* skip past s.iso.error_count */
247
838
    if (hdr->caplen < offset)
248
110
      return;
249
728
    uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
250
251
728
    offset += 4;      /* skip past s.iso.numdesc */
252
728
    if (hdr->caplen < offset)
253
113
      return;
254
615
    uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
255
615
  } else
256
415
    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
1.03k
  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
869
    offset += 4;      /* skip past interval */
279
869
    if (hdr->caplen < offset)
280
121
      return;
281
748
    uhdr->interval = SWAPLONG(uhdr->interval);
282
283
748
    offset += 4;      /* skip past start_frame */
284
748
    if (hdr->caplen < offset)
285
70
      return;
286
678
    uhdr->start_frame = SWAPLONG(uhdr->start_frame);
287
288
678
    offset += 4;      /* skip past xfer_flags */
289
678
    if (hdr->caplen < offset)
290
69
      return;
291
609
    uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
292
293
609
    offset += 4;      /* skip past ndesc */
294
609
    if (hdr->caplen < offset)
295
81
      return;
296
528
    uhdr->ndesc = SWAPLONG(uhdr->ndesc);
297
298
528
    if (uhdr->transfer_type == URB_ISOCHRONOUS) {
299
      /* swap the values in struct linux_usb_isodesc */
300
377
      usb_isodesc *pisodesc;
301
377
      uint32_t i;
302
303
377
      pisodesc = (usb_isodesc *)(void *)(buf+offset);
304
3.18k
      for (i = 0; i < uhdr->ndesc; i++) {
305
3.09k
        offset += 4;    /* skip past status */
306
3.09k
        if (hdr->caplen < offset)
307
139
          return;
308
2.95k
        pisodesc->status = SWAPLONG(pisodesc->status);
309
310
2.95k
        offset += 4;    /* skip past offset */
311
2.95k
        if (hdr->caplen < offset)
312
62
          return;
313
2.89k
        pisodesc->offset = SWAPLONG(pisodesc->offset);
314
315
2.89k
        offset += 4;    /* skip past len */
316
2.89k
        if (hdr->caplen < offset)
317
81
          return;
318
2.80k
        pisodesc->len = SWAPLONG(pisodesc->len);
319
320
2.80k
        offset += 4;    /* skip past padding */
321
322
2.80k
        pisodesc++;
323
2.80k
      }
324
377
    }
325
528
  }
326
1.03k
}
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
1.15k
{
342
1.15k
  u_char *p = buf;
343
1.15k
  nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
344
1.15k
  nflog_tlv_t *tlv;
345
1.15k
  u_int caplen = hdr->caplen;
346
1.15k
  u_int length = hdr->len;
347
1.15k
  uint16_t size;
348
349
1.15k
  if (caplen < (u_int) sizeof(nflog_hdr_t) ||
350
1.15k
      length < (u_int) sizeof(nflog_hdr_t)) {
351
    /* Not enough data to have any TLVs. */
352
802
    return;
353
802
  }
354
355
353
  if (nfhdr->nflog_version != 0) {
356
    /* Unknown NFLOG version */
357
123
    return;
358
123
  }
359
360
230
  length -= sizeof(nflog_hdr_t);
361
230
  caplen -= sizeof(nflog_hdr_t);
362
230
  p += sizeof(nflog_hdr_t);
363
364
364
  while (caplen >= sizeof(nflog_tlv_t)) {
365
307
    tlv = (nflog_tlv_t *) p;
366
367
    /* Swap the type and length. */
368
307
    tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
369
307
    tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
370
371
    /* Get the length of the TLV. */
372
307
    size = tlv->tlv_length;
373
307
    if (size % 4 != 0)
374
165
      size += 4 - size % 4;
375
376
    /* Is the TLV's length less than the minimum? */
377
307
    if (size < sizeof(nflog_tlv_t)) {
378
      /* Yes. Give up now. */
379
75
      return;
380
75
    }
381
382
    /* Do we have enough data for the full TLV? */
383
232
    if (caplen < size || length < size) {
384
      /* No. */
385
98
      return;
386
98
    }
387
388
    /* Skip over the TLV. */
389
134
    length -= size;
390
134
    caplen -= size;
391
134
    p += size;
392
134
  }
393
230
}
394
395
static void
396
swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
397
17.2k
{
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
17.2k
  switch (linktype) {
404
405
1.26k
  case DLT_PFLOG:
406
1.26k
    swap_pflog_header(hdr, data);
407
1.26k
    break;
408
409
921
  case DLT_LINUX_SLL:
410
921
    swap_linux_sll_header(hdr, data);
411
921
    break;
412
413
947
  case DLT_LINUX_SLL2:
414
947
    swap_linux_sll2_header(hdr, data);
415
947
    break;
416
417
1.52k
  case DLT_USB_LINUX:
418
1.52k
    swap_linux_usb_header(hdr, data, 0);
419
1.52k
    break;
420
421
2.80k
  case DLT_USB_LINUX_MMAPPED:
422
2.80k
    swap_linux_usb_header(hdr, data, 1);
423
2.80k
    break;
424
425
1.15k
  case DLT_NFLOG:
426
1.15k
    swap_nflog_header(hdr, data);
427
1.15k
    break;
428
17.2k
  }
429
17.2k
}
430
431
void
432
pcap_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr,
433
    u_char *data)
434
23.2k
{
435
23.2k
  if (swapped)
436
17.2k
    swap_pseudo_headers(linktype, hdr, data);
437
438
23.2k
  fixup_pcap_pkthdr(linktype, hdr, data);
439
23.2k
}
440
441
void
442
fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
443
23.2k
{
444
23.2k
  const pcap_usb_header_mmapped *usb_hdr;
445
446
23.2k
  usb_hdr = (const pcap_usb_header_mmapped *) data;
447
23.2k
  if (linktype == DLT_USB_LINUX_MMAPPED &&
448
23.2k
      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
661
    if (!usb_hdr->data_flag &&
465
661
        hdr->len == sizeof(pcap_usb_header_mmapped) +
466
289
          (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
11
      fix_linux_usb_mmapped_length(hdr, data);
472
11
    }
473
661
  }
474
23.2k
}