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