1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 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 22 #include "varattrs.h" 23 24 /* 25 * This doesn't actually test libpcap itself; it tests whether 26 * valgrind properly handles the APIs libpcap uses. If it doesn't, 27 * we end up getting patches submitted to "fix" references that 28 * valgrind claims are being made to uninitialized data, when, in 29 * fact, the OS isn't making any such references - or we get 30 * valgrind *not* detecting *actual* incorrect references. 31 * 32 * Both BPF and Linux socket filters aren't handled correctly 33 * by some versions of valgrind. See valgrind bug 318203 for 34 * Linux: 35 * 36 * https://bugs.kde.org/show_bug.cgi?id=318203 37 * 38 * and valgrind bug 312989 for macOS: 39 * 40 * https://bugs.kde.org/show_bug.cgi?id=312989 41 * 42 * The fixes for both of those are checked into the official valgrind 43 * repository. 44 * 45 * The unofficial FreeBSD port has similar issues to the official macOS 46 * port, for similar reasons. 47 */ 48 #ifndef lint 49 static const char copyright[] _U_ = 50 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ 51 The Regents of the University of California. All rights reserved.\n"; 52 #endif 53 54 #include <config.h> 55 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <stdarg.h> 60 #include <limits.h> 61 #include <unistd.h> 62 #include <fcntl.h> 63 #include <errno.h> 64 #include <arpa/inet.h> 65 #include <sys/types.h> 66 #include <sys/stat.h> 67 68 #include "pcap/funcattrs.h" 69 70 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(_AIX) || defined(sun) 71 /* OS with BPF - use BPF */ 72 #define USE_BPF 73 #elif defined(__linux__) 74 /* Linux - use socket filters */ 75 #define USE_SOCKET_FILTERS 76 #else 77 #error "Unknown platform or platform that doesn't support Valgrind" 78 #endif 79 80 #if defined(USE_BPF) 81 82 #include <sys/ioctl.h> 83 #include <net/bpf.h> 84 85 /* 86 * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the 87 * native OS version, as we're going to be doing our own ioctls to 88 * make sure that, in the uninitialized-data tests, the filters aren't 89 * checked by libpcap before being handed to BPF. 90 */ 91 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 92 93 #elif defined(USE_SOCKET_FILTERS) 94 95 #include <sys/socket.h> 96 #include <linux/types.h> 97 #include <linux/filter.h> 98 99 #endif 100 101 /* 102 * Squelch a warning. 103 * 104 * We include system headers to be able to directly set the filter to 105 * a program with uninitialized content, to make sure what we're testing 106 * is Valgrind's checking of the system call to set the filter, and we 107 * also include <pcap.h> to open the device in the first place, and that 108 * means that we may get collisions between their definitions of 109 * BPF_STMT and BPF_JUMP - and do, in fact, get them on Linux (the 110 * definitions may be semantically the same, but that's not sufficient to 111 * avoid the warnings, as the preprocessor doesn't know that u_short is 112 * just unsigned short). 113 * 114 * So we undefine BPF_STMT and BPF_JUMP to avoid the warning. 115 */ 116 #undef BPF_STMT 117 #undef BPF_JUMP 118 #include <pcap.h> 119 120 static char *program_name; 121 122 /* Forwards */ 123 static void PCAP_NORETURN usage(void); 124 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); 125 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); 126 127 /* 128 * On Windows, we need to open the file in binary mode, so that 129 * we get all the bytes specified by the size we get from "fstat()". 130 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 131 * we define it as 0 if it's not defined, so it does nothing. 132 */ 133 #ifndef O_BINARY 134 #define O_BINARY 0 135 #endif 136 137 static char * 138 read_infile(char *fname) 139 { 140 register int i, fd, cc; 141 register char *cp; 142 struct stat buf; 143 144 fd = open(fname, O_RDONLY|O_BINARY); 145 if (fd < 0) 146 error("can't open %s: %s", fname, pcap_strerror(errno)); 147 148 if (fstat(fd, &buf) < 0) 149 error("can't stat %s: %s", fname, pcap_strerror(errno)); 150 151 /* 152 * _read(), on Windows, has an unsigned int byte count and an 153 * int return value, so we can't handle a file bigger than 154 * INT_MAX - 1 bytes (and have no reason to do so; a filter *that* 155 * big will take forever to compile). (The -1 is for the '\0' at 156 * the end of the string.) 157 */ 158 if (buf.st_size > INT_MAX - 1) 159 error("%s is larger than %d bytes; that's too large", fname, 160 INT_MAX - 1); 161 cp = malloc((u_int)buf.st_size + 1); 162 if (cp == NULL) 163 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 164 fname, pcap_strerror(errno)); 165 cc = (int)read(fd, cp, (u_int)buf.st_size); 166 if (cc < 0) 167 error("read %s: %s", fname, pcap_strerror(errno)); 168 if (cc != buf.st_size) 169 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 170 171 close(fd); 172 /* replace "# comment" with spaces */ 173 for (i = 0; i < cc; i++) { 174 if (cp[i] == '#') 175 while (i < cc && cp[i] != '\n') 176 cp[i++] = ' '; 177 } 178 cp[cc] = '\0'; 179 return (cp); 180 } 181 182 /* VARARGS */ 183 static void 184 error(const char *fmt, ...) 185 { 186 va_list ap; 187 188 (void)fprintf(stderr, "%s: ", program_name); 189 va_start(ap, fmt); 190 (void)vfprintf(stderr, fmt, ap); 191 va_end(ap); 192 if (*fmt) { 193 fmt += strlen(fmt); 194 if (fmt[-1] != '\n') 195 (void)fputc('\n', stderr); 196 } 197 exit(1); 198 /* NOTREACHED */ 199 } 200 201 /* VARARGS */ 202 static void 203 warning(const char *fmt, ...) 204 { 205 va_list ap; 206 207 (void)fprintf(stderr, "%s: WARNING: ", program_name); 208 va_start(ap, fmt); 209 (void)vfprintf(stderr, fmt, ap); 210 va_end(ap); 211 if (*fmt) { 212 fmt += strlen(fmt); 213 if (fmt[-1] != '\n') 214 (void)fputc('\n', stderr); 215 } 216 } 217 218 /* 219 * Copy arg vector into a new buffer, concatenating arguments with spaces. 220 */ 221 static char * 222 copy_argv(register char **argv) 223 { 224 register char **p; 225 register size_t len = 0; 226 char *buf; 227 char *src, *dst; 228 229 p = argv; 230 if (*p == 0) 231 return 0; 232 233 while (*p) 234 len += strlen(*p++) + 1; 235 236 buf = (char *)malloc(len); 237 if (buf == NULL) 238 error("copy_argv: malloc"); 239 240 p = argv; 241 dst = buf; 242 while ((src = *p++) != NULL) { 243 while ((*dst++ = *src++) != '\0') 244 ; 245 dst[-1] = ' '; 246 } 247 dst[-1] = '\0'; 248 249 return buf; 250 } 251 252 #define INSN_COUNT 17 253 254 int 255 main(int argc, char **argv) 256 { 257 char *cp, *device; 258 int op; 259 int dorfmon, useactivate; 260 char ebuf[PCAP_ERRBUF_SIZE]; 261 char *infile; 262 const char *cmdbuf; 263 pcap_if_t *devlist; 264 pcap_t *pd; 265 int status = 0; 266 int pcap_fd; 267 #if defined(USE_BPF) 268 struct bpf_program bad_fcode; 269 struct bpf_insn uninitialized[INSN_COUNT]; 270 #elif defined(USE_SOCKET_FILTERS) 271 struct sock_fprog bad_fcode; 272 struct sock_filter uninitialized[INSN_COUNT]; 273 #endif 274 struct bpf_program fcode; 275 276 device = NULL; 277 dorfmon = 0; 278 useactivate = 0; 279 infile = NULL; 280 281 if ((cp = strrchr(argv[0], '/')) != NULL) 282 program_name = cp + 1; 283 else 284 program_name = argv[0]; 285 286 opterr = 0; 287 while ((op = getopt(argc, argv, "aF:i:I")) != -1) { 288 switch (op) { 289 290 case 'a': 291 useactivate = 1; 292 break; 293 294 case 'F': 295 infile = optarg; 296 break; 297 298 case 'i': 299 device = optarg; 300 break; 301 302 case 'I': 303 dorfmon = 1; 304 useactivate = 1; /* required for rfmon */ 305 break; 306 307 default: 308 usage(); 309 /* NOTREACHED */ 310 } 311 } 312 313 if (device == NULL) { 314 /* 315 * No interface specified; get whatever pcap_lookupdev() 316 * finds. 317 */ 318 if (pcap_findalldevs(&devlist, ebuf) == -1) 319 error("%s", ebuf); 320 if (devlist == NULL) 321 error("no interfaces available for capture"); 322 device = strdup(devlist->name); 323 pcap_freealldevs(devlist); 324 } 325 326 if (infile != NULL) { 327 /* 328 * Filter specified with "-F" and a file containing 329 * a filter. 330 */ 331 cmdbuf = read_infile(infile); 332 } else { 333 if (optind < argc) { 334 /* 335 * Filter specified with arguments on the 336 * command line. 337 */ 338 cmdbuf = copy_argv(&argv[optind+1]); 339 } else { 340 /* 341 * No filter specified; use an empty string, which 342 * compiles to an "accept all" filter. 343 */ 344 cmdbuf = ""; 345 } 346 } 347 348 if (useactivate) { 349 pd = pcap_create(device, ebuf); 350 if (pd == NULL) 351 error("%s: pcap_create() failed: %s", device, ebuf); 352 status = pcap_set_snaplen(pd, 65535); 353 if (status != 0) 354 error("%s: pcap_set_snaplen failed: %s", 355 device, pcap_statustostr(status)); 356 status = pcap_set_promisc(pd, 1); 357 if (status != 0) 358 error("%s: pcap_set_promisc failed: %s", 359 device, pcap_statustostr(status)); 360 if (dorfmon) { 361 status = pcap_set_rfmon(pd, 1); 362 if (status != 0) 363 error("%s: pcap_set_rfmon failed: %s", 364 device, pcap_statustostr(status)); 365 } 366 status = pcap_set_timeout(pd, 1000); 367 if (status != 0) 368 error("%s: pcap_set_timeout failed: %s", 369 device, pcap_statustostr(status)); 370 status = pcap_activate(pd); 371 if (status < 0) { 372 /* 373 * pcap_activate() failed. 374 */ 375 error("%s: %s\n(%s)", device, 376 pcap_statustostr(status), pcap_geterr(pd)); 377 } else if (status > 0) { 378 /* 379 * pcap_activate() succeeded, but it's warning us 380 * of a problem it had. 381 */ 382 warning("%s: %s\n(%s)", device, 383 pcap_statustostr(status), pcap_geterr(pd)); 384 } 385 } else { 386 *ebuf = '\0'; 387 pd = pcap_open_live(device, 65535, 1, 1000, ebuf); 388 if (pd == NULL) 389 error("%s", ebuf); 390 else if (*ebuf) 391 warning("%s", ebuf); 392 } 393 394 pcap_fd = pcap_fileno(pd); 395 396 /* 397 * Try setting a filter with an uninitialized bpf_program 398 * structure. This should cause valgrind to report a 399 * problem. 400 * 401 * We don't check for errors, because it could get an 402 * error due to a bad pointer or count. 403 */ 404 #if defined(USE_BPF) 405 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 406 #elif defined(USE_SOCKET_FILTERS) 407 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 408 sizeof(bad_fcode)); 409 #endif 410 411 /* 412 * Try setting a filter with an initialized bpf_program 413 * structure that points to an uninitialized program. 414 * That should also cause valgrind to report a problem. 415 * 416 * We don't check for errors, because it could get an 417 * error due to a bad pointer or count. 418 */ 419 #if defined(USE_BPF) 420 bad_fcode.bf_len = INSN_COUNT; 421 bad_fcode.bf_insns = uninitialized; 422 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 423 #elif defined(USE_SOCKET_FILTERS) 424 bad_fcode.len = INSN_COUNT; 425 bad_fcode.filter = uninitialized; 426 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 427 sizeof(bad_fcode)); 428 #endif 429 430 /* 431 * Now compile a filter and set the filter with that. 432 * That should *not* cause valgrind to report a 433 * problem. 434 */ 435 if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) 436 error("can't compile filter: %s", pcap_geterr(pd)); 437 if (pcap_setfilter(pd, &fcode) < 0) 438 error("can't set filter: %s", pcap_geterr(pd)); 439 440 pcap_close(pd); 441 exit(status < 0 ? 1 : 0); 442 } 443 444 static void 445 usage(void) 446 { 447 (void)fprintf(stderr, "%s, with %s\n", program_name, 448 pcap_lib_version()); 449 (void)fprintf(stderr, 450 "Usage: %s [-aI] [ -F file ] [ -i interface ] [ expression ]\n", 451 program_name); 452 exit(1); 453 } 454