Bug Summary

File:src/lib/libpcap/savefile.c
Warning:line 282, column 3
Null pointer passed as 2nd argument to memory copy function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name savefile.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libpcap/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -I /usr/src/lib/libpcap -D yylval=pcap_yylval -D HAVE_SYS_IOCCOM_H -D HAVE_SYS_SOCKIO_H -D HAVE_ETHER_HOSTTON -D HAVE_STRERROR -D HAVE_SOCKADDR_SA_LEN -D LBL_ALIGN -D HAVE_IFADDRS_H -D INET6 -D HAVE_BSD_IEEE80211 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libpcap/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libpcap/savefile.c
1/* $OpenBSD: savefile.c,v 1.17 2020/05/27 04:24:01 dlg Exp $ */
2
3/*
4 * Copyright (c) 1993, 1994, 1995, 1996, 1997
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
18 * written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 *
23 * savefile.c - supports offline use of tcpdump
24 * Extraction/creation by Jeffrey Mogul, DECWRL
25 * Modified by Steve McCanne, LBL.
26 *
27 * Used to save the received packet headers, after filtering, to
28 * a file, and then read them later.
29 * The first record in the file contains saved values for the machine
30 * dependent values so we can print the dump file on any architecture.
31 */
32
33#include <sys/types.h>
34#include <sys/time.h>
35
36#include <errno(*__errno()).h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#ifdef HAVE_OS_PROTO_H
43#include "os-proto.h"
44#endif
45
46#include "pcap-int.h"
47
48#define TCPDUMP_MAGIC0xa1b2c3d4 0xa1b2c3d4
49
50/*
51 * We use the "receiver-makes-right" approach to byte order,
52 * because time is at a premium when we are writing the file.
53 * In other words, the pcap_file_header and pcap_pkthdr,
54 * records are written in host byte order.
55 * Note that the packets are always written in network byte order.
56 *
57 * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
58 * machine (if the file was written in little-end order).
59 */
60#define SWAPLONG(y)((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (
((y)&0xff0000)>>8) | (((y)>>24)&0xff))
\
61((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
62#define SWAPSHORT(y)( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>
8) )
\
63 ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) )
64
65#define SFERR_TRUNC1 1
66#define SFERR_BADVERSION2 2
67#define SFERR_BADF3 3
68#define SFERR_EOF4 4 /* not really an error, just a status */
69
70static int
71sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
72{
73 struct pcap_file_header hdr;
74
75 hdr.magic = TCPDUMP_MAGIC0xa1b2c3d4;
76 hdr.version_major = PCAP_VERSION_MAJOR2;
77 hdr.version_minor = PCAP_VERSION_MINOR4;
78
79 hdr.thiszone = thiszone;
80 hdr.snaplen = snaplen;
81 hdr.sigfigs = 0;
82 hdr.linktype = linktype;
83
84 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
85 return (-1);
86
87 return (0);
88}
89
90static void
91swap_hdr(struct pcap_file_header *hp)
92{
93 hp->version_major = SWAPSHORT(hp->version_major)( (((hp->version_major)&0xff)<<8) | ((u_short)((
hp->version_major)&0xff00)>>8) )
;
94 hp->version_minor = SWAPSHORT(hp->version_minor)( (((hp->version_minor)&0xff)<<8) | ((u_short)((
hp->version_minor)&0xff00)>>8) )
;
95 hp->thiszone = SWAPLONG(hp->thiszone)((((hp->thiszone)&0xff)<<24) | (((hp->thiszone
)&0xff00)<<8) | (((hp->thiszone)&0xff0000)>>
8) | (((hp->thiszone)>>24)&0xff))
;
96 hp->sigfigs = SWAPLONG(hp->sigfigs)((((hp->sigfigs)&0xff)<<24) | (((hp->sigfigs)
&0xff00)<<8) | (((hp->sigfigs)&0xff0000)>>
8) | (((hp->sigfigs)>>24)&0xff))
;
97 hp->snaplen = SWAPLONG(hp->snaplen)((((hp->snaplen)&0xff)<<24) | (((hp->snaplen)
&0xff00)<<8) | (((hp->snaplen)&0xff0000)>>
8) | (((hp->snaplen)>>24)&0xff))
;
98 hp->linktype = SWAPLONG(hp->linktype)((((hp->linktype)&0xff)<<24) | (((hp->linktype
)&0xff00)<<8) | (((hp->linktype)&0xff0000)>>
8) | (((hp->linktype)>>24)&0xff))
;
99}
100
101pcap_t *
102pcap_open_offline(const char *fname, char *errbuf)
103{
104 pcap_t *p;
105 FILE *fp;
106
107 if (fname[0] == '-' && fname[1] == '\0')
108 fp = stdin(&__sF[0]);
109 else {
110 fp = fopen(fname, "r");
111 if (fp == NULL((void *)0)) {
112 snprintf(errbuf, PCAP_ERRBUF_SIZE256, "%s: %s", fname,
113 pcap_strerror(errno(*__errno())));
114 return (NULL((void *)0));
115 }
116 }
117 p = pcap_fopen_offline(fp, errbuf);
118 if (p == NULL((void *)0)) {
119 if (fp != stdin(&__sF[0]))
120 fclose(fp);
121 }
122 return (p);
123}
124
125pcap_t *
126pcap_fopen_offline(FILE *fp, char *errbuf)
127{
128 pcap_t *p;
129 struct pcap_file_header hdr;
130 int linklen;
131
132 p = calloc(1, sizeof(*p));
133 if (p == NULL((void *)0)) {
134 strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE256);
135 return (NULL((void *)0));
136 }
137
138 /*
139 * Set this field so we don't double-close in pcap_close!
140 */
141 p->fd = -1;
142
143 if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
144 snprintf(errbuf, PCAP_ERRBUF_SIZE256, "fread: %s",
145 pcap_strerror(errno(*__errno())));
146 goto bad;
147 }
148 if (hdr.magic != TCPDUMP_MAGIC0xa1b2c3d4) {
149 if (SWAPLONG(hdr.magic)((((hdr.magic)&0xff)<<24) | (((hdr.magic)&0xff00
)<<8) | (((hdr.magic)&0xff0000)>>8) | (((hdr.
magic)>>24)&0xff))
!= TCPDUMP_MAGIC0xa1b2c3d4) {
150 snprintf(errbuf, PCAP_ERRBUF_SIZE256,
151 "bad dump file format");
152 goto bad;
153 }
154 p->sf.swapped = 1;
155 swap_hdr(&hdr);
156 }
157 if (hdr.version_major < PCAP_VERSION_MAJOR2) {
158 snprintf(errbuf, PCAP_ERRBUF_SIZE256, "archaic file format");
159 goto bad;
160 }
161 p->tzoff = hdr.thiszone;
162 p->snapshot = hdr.snaplen;
163 p->linktype = hdr.linktype;
164 p->sf.rfile = fp;
165 p->bufsize = hdr.snaplen;
166
167 /* Align link header as required for proper data alignment */
168 /* XXX should handle all types */
169 switch (p->linktype) {
170
171 case DLT_EN10MB1:
172 linklen = 14;
173 break;
174
175 case DLT_FDDI10:
176 linklen = 13 + 8; /* fddi_header + llc */
177 break;
178
179 case DLT_NULL0:
180 default:
181 linklen = 0;
182 break;
183 }
184
185 if (p->bufsize < 0)
186 p->bufsize = BPF_MAXBUFSIZE(2 * 1024 * 1024);
187 p->sf.base = malloc(p->bufsize + BPF_ALIGNMENTsizeof(u_int32_t));
188 if (p->sf.base == NULL((void *)0)) {
189 strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE256);
190 goto bad;
191 }
192 p->buffer = p->sf.base + BPF_ALIGNMENTsizeof(u_int32_t) - (linklen % BPF_ALIGNMENTsizeof(u_int32_t));
193 p->sf.version_major = hdr.version_major;
194 p->sf.version_minor = hdr.version_minor;
195#ifdef PCAP_FDDIPAD
196 /* XXX padding only needed for kernel fcode */
197 pcap_fddipad = 0;
198#endif
199
200 return (p);
201 bad:
202 free(p);
203 return (NULL((void *)0));
204}
205
206/*
207 * Read sf_readfile and return the next packet. Return the header in hdr
208 * and the contents in buf. Return 0 on success, SFERR_EOF if there were
209 * no more packets, and SFERR_TRUNC if a partial packet was encountered.
210 */
211static int
212sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen)
213{
214 FILE *fp = p->sf.rfile;
215
216 /* read the stamp */
217 if (fread((char *)hdr, sizeof(struct pcap_pkthdr), 1, fp) != 1) {
5
Assuming the condition is false
6
Taking false branch
218 /* probably an EOF, though could be a truncated packet */
219 return (1);
220 }
221
222 if (p->sf.swapped) {
7
Assuming field 'swapped' is 0
8
Taking false branch
223 /* these were written in opposite byte order */
224 hdr->caplen = SWAPLONG(hdr->caplen)((((hdr->caplen)&0xff)<<24) | (((hdr->caplen)
&0xff00)<<8) | (((hdr->caplen)&0xff0000)>>
8) | (((hdr->caplen)>>24)&0xff))
;
225 hdr->len = SWAPLONG(hdr->len)((((hdr->len)&0xff)<<24) | (((hdr->len)&0xff00
)<<8) | (((hdr->len)&0xff0000)>>8) | (((hdr
->len)>>24)&0xff))
;
226 hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec)((((hdr->ts.tv_sec)&0xff)<<24) | (((hdr->ts.tv_sec
)&0xff00)<<8) | (((hdr->ts.tv_sec)&0xff0000)
>>8) | (((hdr->ts.tv_sec)>>24)&0xff))
;
227 hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec)((((hdr->ts.tv_usec)&0xff)<<24) | (((hdr->ts.
tv_usec)&0xff00)<<8) | (((hdr->ts.tv_usec)&0xff0000
)>>8) | (((hdr->ts.tv_usec)>>24)&0xff))
;
228 }
229 /*
230 * We interchanged the caplen and len fields at version 2.3,
231 * in order to match the bpf header layout. But unfortunately
232 * some files were written with version 2.3 in their headers
233 * but without the interchanged fields.
234 */
235 if (p->sf.version_minor < 3 ||
9
Assuming field 'version_minor' is >= 3
236 (p->sf.version_minor == 3 && hdr->caplen > hdr->len)) {
10
Assuming field 'version_minor' is not equal to 3
237 int t = hdr->caplen;
238 hdr->caplen = hdr->len;
239 hdr->len = t;
240 }
241
242 if (hdr->caplen > buflen) {
11
Assuming 'buflen' is < field 'caplen'
12
Taking true branch
243 /*
244 * This can happen due to Solaris 2.3 systems tripping
245 * over the BUFMOD problem and not setting the snapshot
246 * correctly in the savefile header. If the caplen isn't
247 * grossly wrong, try to salvage.
248 */
249 static u_char *tp = NULL((void *)0);
13
'tp' initialized to a null pointer value
250 static int tsize = 0;
251
252 if (hdr->caplen > 65535) {
14
Assuming field 'caplen' is <= 65535
15
Taking false branch
253 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256,
254 "bogus savefile header");
255 return (-1);
256 }
257
258 if (tsize < hdr->caplen) {
16
Assuming 'tsize' is >= field 'caplen'
17
Taking false branch
259 tsize = ((hdr->caplen + 1023) / 1024) * 1024;
260 free(tp);
261 tp = malloc(tsize);
262 if (tp == NULL((void *)0)) {
263 tsize = 0;
264 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256,
265 "BUFMOD hack malloc");
266 return (-1);
267 }
268 }
269 if (fread((char *)tp, hdr->caplen, 1, fp) != 1) {
18
Assuming the condition is false
19
Taking false branch
270 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256,
271 "truncated dump file");
272 return (-1);
273 }
274 /*
275 * We can only keep up to buflen bytes. Since caplen > buflen
276 * is exactly how we got here, we know we can only keep the
277 * first buflen bytes and must drop the remainder. Adjust
278 * caplen accordingly, so we don't get confused later as
279 * to how many bytes we have to play with.
280 */
281 hdr->caplen = buflen;
282 memcpy((char *)buf, (char *)tp, buflen);
20
Null pointer passed as 2nd argument to memory copy function
283
284 } else {
285 /* read the packet itself */
286
287 if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
288 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256,
289 "truncated dump file");
290 return (-1);
291 }
292 }
293 return (0);
294}
295
296/*
297 * Print out packets stored in the file initialized by sf_read_init().
298 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
299 */
300int
301pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
302{
303 struct bpf_insn *fcode = p->fcode.bf_insns;
304 int status = 0;
305 int n = 0;
306
307 while (status == 0) {
1
Loop condition is true. Entering loop body
308 struct pcap_pkthdr h;
309
310 /*
311 * Has "pcap_breakloop()" been called?
312 * If so, return immediately - if we haven't read any
313 * packets, clear the flag and return -2 to indicate
314 * that we were told to break out of the loop, otherwise
315 * leave the flag set, so that the *next* call will break
316 * out of the loop without having read any packets, and
317 * return the number of packets we've processed so far.
318 */
319 if (p->break_loop) {
2
Assuming field 'break_loop' is 0
3
Taking false branch
320 if (n == 0) {
321 p->break_loop = 0;
322 return (PCAP_ERROR_BREAK-2);
323 } else
324 return (n);
325 }
326
327 status = sf_next_packet(p, &h, p->buffer, p->bufsize);
4
Calling 'sf_next_packet'
328 if (status) {
329 if (status == 1)
330 return (0);
331 return (status);
332 }
333
334 if (fcode == NULL((void *)0) ||
335 bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
336 (*callback)(user, &h, p->buffer);
337 if (++n >= cnt && cnt > 0)
338 break;
339 }
340 }
341 /*XXX this breaks semantics tcpslice expects */
342 return (n);
343}
344
345/*
346 * Output a packet to the initialized dump file.
347 */
348void
349pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
350{
351 FILE *f;
352
353 f = (FILE *)user;
354 /* XXX we should check the return status */
355 (void)fwrite((char *)h, sizeof(*h), 1, f);
356 (void)fwrite((char *)sp, h->caplen, 1, f);
357}
358
359static pcap_dumper_t *
360pcap_setup_dump(pcap_t *p, FILE *f, const char *fname)
361{
362 if (sf_write_header(f, p->linktype, p->tzoff, p->snapshot) == -1) {
363 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, "Can't write to %s: %s",
364 fname, pcap_strerror(errno(*__errno())));
365 if (f != stdout(&__sF[1]))
366 (void)fclose(f);
367 return (NULL((void *)0));
368 }
369 return ((pcap_dumper_t *)f);
370}
371
372/*
373 * Initialize so that sf_write() will output to the file named 'fname'.
374 */
375pcap_dumper_t *
376pcap_dump_open(pcap_t *p, const char *fname)
377{
378 FILE *f;
379 if (fname[0] == '-' && fname[1] == '\0')
380 f = stdout(&__sF[1]);
381 else {
382 f = fopen(fname, "w");
383 if (f == NULL((void *)0)) {
384 snprintf(p->errbuf, PCAP_ERRBUF_SIZE256, "%s: %s",
385 fname, pcap_strerror(errno(*__errno())));
386 return (NULL((void *)0));
387 }
388 }
389 return (pcap_setup_dump(p, f, fname));
390}
391
392/*
393 * Initialize so that sf_write() will output to the given stream.
394 */
395pcap_dumper_t *
396pcap_dump_fopen(pcap_t *p, FILE *f)
397{
398 return (pcap_setup_dump(p, f, "stream"));
399}
400
401FILE *
402pcap_dump_file(pcap_dumper_t *p)
403{
404 return ((FILE *)p);
405}
406
407long
408pcap_dump_ftell(pcap_dumper_t *p)
409{
410 return (ftell((FILE *)p));
411}
412
413int
414pcap_dump_flush(pcap_dumper_t *p)
415{
416
417 if (fflush((FILE *)p) == EOF(-1))
418 return (-1);
419 else
420 return (0);
421}
422
423void
424pcap_dump_close(pcap_dumper_t *p)
425{
426
427#ifdef notyet
428 if (ferror((FILE *)p)(!__isthreaded ? ((((FILE *)p)->_flags & 0x0040) != 0)
: (ferror)((FILE *)p))
)
429 return-an-error;
430 /* XXX should check return from fclose() too */
431#endif
432 (void)fclose((FILE *)p);
433}