Coverage Report

Created: 2024-08-17 06:43

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