4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
37 #include <sys/types.h>
42 #include <sys/sysmacros.h>
44 #include <sys/socket.h>
45 #include <sys/pfmod.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/in.h>
49 #include <netinet/if_ether.h>
56 /* Global error recovery variables */
57 sigjmp_buf jmp_env
, ojmp_env
; /* error recovery jmp buf */
58 int snoop_nrecover
; /* number of recoveries on curr pkt */
59 int quitting
; /* user termination flag */
61 static struct snoop_handler
*snoop_hp
; /* global alarm handler head */
62 static struct snoop_handler
*snoop_tp
; /* global alarm handler tail */
63 static time_t snoop_nalarm
; /* time of next alarm */
65 /* protected interpreter output areas */
68 static char *sumline
[MAXSUM
];
69 static char *detail_line
;
74 int maxcount
; /* maximum no of packets to capture */
75 int count
; /* count of packets captured */
78 int x_length
= 0x7fffffff;
87 struct Pf_ext_packetfilt pf
;
89 static int vlanid
= 0;
91 static void usage(void);
92 static void snoop_sigrecover(int sig
, siginfo_t
*info
, void *p
);
93 static char *protmalloc(size_t);
94 static void resetperm(void);
97 main(int argc
, char **argv
)
102 struct Pf_ext_packetfilt
*fp
= NULL
;
103 char *icapfile
= NULL
;
104 char *ocapfile
= NULL
;
105 boolean_t nflg
= B_FALSE
;
106 boolean_t Nflg
= B_FALSE
;
108 boolean_t Uflg
= B_FALSE
;
110 int last
= 0x7fffffff;
111 boolean_t use_kern_pf
;
113 char names
[MAXPATHLEN
+ 1];
114 char self
[MAXHOSTNAMELEN
+ 1];
119 struct sigaction sigact
;
123 char *datalink
= NULL
;
128 * Global error recovery: Prepare for interpreter failures
129 * with corrupted packets or confused interpreters.
130 * Allocate protected output and stack areas, with generous
133 nbytes
= (MAXSUM
+ 3) * (MAXLINE
+ REDZONE
);
134 output_area
= protmalloc(nbytes
);
135 if (output_area
== NULL
) {
136 perror("Warning: mmap");
140 /* Allocate protected output areas */
141 for (ret
= 0; ret
< MAXSUM
; ret
++) {
142 sumline
[ret
] = (char *)output_area
;
143 output_area
+= (MAXLINE
+ REDZONE
);
145 detail_line
= output_area
;
146 output_area
+= MAXLINE
+ REDZONE
;
148 output_area
+= MAXLINE
+ REDZONE
;
150 output_area
+= MAXLINE
+ REDZONE
;
152 /* Initialize an alternate signal stack to increase robustness */
153 if ((sigstk
.ss_sp
= (char *)malloc(SIGSTKSZ
+REDZONE
)) == NULL
) {
154 perror("Warning: malloc");
157 sigstk
.ss_size
= SIGSTKSZ
;
159 if (sigaltstack(&sigstk
, (stack_t
*)NULL
) < 0) {
160 perror("Warning: sigaltstack");
164 /* Initialize a master signal handler */
165 sigact
.sa_handler
= NULL
;
166 sigact
.sa_sigaction
= snoop_sigrecover
;
167 (void) sigemptyset(&sigact
.sa_mask
);
168 sigact
.sa_flags
= SA_ONSTACK
|SA_SIGINFO
;
170 /* Register master signal handler */
171 if (sigaction(SIGHUP
, &sigact
, NULL
) < 0) {
172 perror("Warning: sigaction");
175 if (sigaction(SIGINT
, &sigact
, NULL
) < 0) {
176 perror("Warning: sigaction");
179 if (sigaction(SIGQUIT
, &sigact
, NULL
) < 0) {
180 perror("Warning: sigaction");
183 if (sigaction(SIGILL
, &sigact
, NULL
) < 0) {
184 perror("Warning: sigaction");
187 if (sigaction(SIGTRAP
, &sigact
, NULL
) < 0) {
188 perror("Warning: sigaction");
191 if (sigaction(SIGIOT
, &sigact
, NULL
) < 0) {
192 perror("Warning: sigaction");
195 if (sigaction(SIGEMT
, &sigact
, NULL
) < 0) {
196 perror("Warning: sigaction");
199 if (sigaction(SIGFPE
, &sigact
, NULL
) < 0) {
200 perror("Warning: sigaction");
203 if (sigaction(SIGBUS
, &sigact
, NULL
) < 0) {
204 perror("Warning: sigaction");
207 if (sigaction(SIGSEGV
, &sigact
, NULL
) < 0) {
208 perror("Warning: sigaction");
211 if (sigaction(SIGSYS
, &sigact
, NULL
) < 0) {
212 perror("Warning: sigaction");
215 if (sigaction(SIGALRM
, &sigact
, NULL
) < 0) {
216 perror("Warning: sigaction");
219 if (sigaction(SIGTERM
, &sigact
, NULL
) < 0) {
220 perror("Warning: sigaction");
224 /* Prepare for failure during program initialization/exit */
225 if (sigsetjmp(jmp_env
, 1)) {
228 (void) setvbuf(stdout
, NULL
, _IOLBF
, BUFSIZ
);
230 while ((c
= getopt(argc
, argv
, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz"))
234 audiodev
= getenv("AUDIODEV");
235 if (audiodev
== NULL
)
236 audiodev
= "/dev/audio";
237 audio
= open(audiodev
, O_WRONLY
);
239 pr_err("Audio device %s: %m",
247 case 'r': flags
|= F_RTIME
; break;
248 case 'a': flags
|= F_ATIME
; break;
254 if (datalink
!= NULL
)
279 (void) strlcpy(names
, optarg
, MAXPATHLEN
);
282 snaplen
= atoi(optarg
);
298 p2
= strpbrk(p
, ",:-");
300 first
= last
= atoi(p
);
308 (void) gethostname(self
, MAXHOSTNAMELEN
);
309 p
= strchr(optarg
, ':');
312 if (strcmp(optarg
, self
) == 0 ||
313 strcmp(p
+1, self
) == 0)
314 (void) fprintf(stderr
,
315 "Warning: cannot capture packets from %s\n",
318 } else if (strcmp(optarg
, self
) == 0)
319 (void) fprintf(stderr
,
320 "Warning: cannot capture packets from %s\n",
326 p2
= strpbrk(p
, ",:-");
337 maxcount
= atoi(optarg
);
363 argstr
= (char *)concat_args(&argv
[optind
], argc
- optind
);
366 * Need to know before we decide on filtering method some things
367 * about the interface. So, go ahead and do part of the initialization
368 * now so we have that data. Note that if no datalink is specified,
369 * open_datalink() selects one and returns it. In an ideal world,
370 * it might be nice if the "correct" interface for the filter
371 * requested was chosen, but that's too hard.
374 use_kern_pf
= open_datalink(&dh
, datalink
);
376 use_kern_pf
= B_FALSE
;
377 cap_open_read(icapfile
);
381 (void) strlcpy(names
, icapfile
, MAXPATHLEN
);
382 (void) strlcat(names
, ".names", MAXPATHLEN
);
387 use_kern_pf
= B_FALSE
;
389 /* attempt to read .names file if it exists before filtering */
390 if ((!Nflg
) && names
[0] != '\0') {
391 if (access(names
, F_OK
) == 0) {
394 (void) fprintf(stderr
, "%s not found\n", names
);
401 ret
= pf_compile(argstr
, Cflg
);
405 compile(argstr
, Cflg
);
417 compile(argstr
, Cflg
);
428 * If the -o flag is set then capture packets
429 * directly to a file. Don't attempt to
430 * interpret them on the fly (F_NOW).
431 * Note: capture to file is much less likely
432 * to drop packets since we don't spend cpu
433 * cycles running through the interpreters
434 * and possibly hanging in address-to-name
435 * mappings through the name service.
438 cap_open_write(ocapfile
);
447 * If the -i flag is set then get packets from
448 * the log file which has been previously captured
449 * with the -o option.
453 (void) strlcpy(names
, icapfile
, MAXPATHLEN
);
454 (void) strlcat(names
, ".names", MAXPATHLEN
);
457 namefile
= fopen(names
, "w");
458 if (namefile
== NULL
) {
463 (void) fprintf(stderr
,
464 "Creating name file %s\n", names
);
470 flags
|= F_NUM
| F_TIME
;
473 cap_read(first
, last
, filter
, proc
, flags
);
476 (void) fclose(namefile
);
479 const int chunksize
= 8 * 8192;
480 struct timeval timeout
;
483 * If listening to packets on audio
484 * then set the buffer timeout down
485 * to 1/10 sec. A higher value
486 * makes the audio "bursty".
490 timeout
.tv_usec
= 100000;
496 init_datalink(dh
, snaplen
, chunksize
, &timeout
, fp
);
497 if (! qflg
&& ocapfile
)
500 net_read(dh
, chunksize
, filter
, proc
, flags
);
503 if (!(flags
& F_NOW
))
513 static int tone
[] = {
514 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
515 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
516 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
517 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
518 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
519 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
523 * Make a sound on /dev/audio according to the length of the packet. The
524 * amount of waveform used is a function of packet length e.g. a series
525 * of small packets is heard as clicks, whereas a series of NFS packets in
526 * an 8k read sounds like a "WHAAAARP".
535 (void) write(audio
, tone
, len
);
539 /* Display a count of packets */
543 static int prev
= -1;
549 (void) fprintf(stderr
, "\r%d ", count
);
552 #define ENCAP_LEN 16 /* Hold "(NN encap)" */
555 * Display data that's external to the packet.
556 * This constitutes the first half of the summary
560 show_pktinfo(int flags
, int num
, char *src
, char *dst
, struct timeval
*ptvp
,
561 struct timeval
*tvp
, int drops
, int len
)
564 static struct timeval tvp0
;
570 (void) sprintf(lp
, "%3d ", num
);
573 tm
= localtime(&tvp
->tv_sec
);
575 if (flags
& F_TIME
) {
576 if (flags
& F_ATIME
) {
577 (void) sprintf(lp
, "%02d:%02d:%02d.%05d ",
578 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
,
579 (int)tvp
->tv_usec
/ 10);
582 if (flags
& F_RTIME
) {
583 if (tvp0
.tv_sec
== 0) {
584 tvp0
.tv_sec
= tvp
->tv_sec
;
585 tvp0
.tv_usec
= tvp
->tv_usec
;
589 sec
= tvp
->tv_sec
- ptvp
->tv_sec
;
590 usec
= tvp
->tv_usec
- ptvp
->tv_usec
;
595 (void) sprintf(lp
, "%3d.%05d ", sec
, usec
/ 10);
600 if ((flags
& F_SUM
) && !(flags
& F_ALLSUM
) && (vlanid
!= 0)) {
601 (void) snprintf(lp
, MAXLINE
, "VLAN#%i: ", vlanid
);
606 (void) sprintf(lp
, "%12s -> %-12s ", src
, dst
);
610 if (flags
& F_DROPS
) {
611 (void) sprintf(lp
, "drops: %d ", drops
);
616 (void) sprintf(lp
, "length: %4d ", len
);
621 if (flags
& F_ALLSUM
)
622 (void) printf("________________________________\n");
624 start
= flags
& F_ALLSUM
? 0 : sumcount
- 1;
625 (void) sprintf(encap
, " (%d encap)", total_encap_levels
- 1);
626 (void) printf("%s%s%s\n", line
, sumline
[start
],
627 ((flags
& F_ALLSUM
) || (total_encap_levels
== 1)) ? "" :
630 for (i
= start
+ 1; i
< sumcount
; i
++)
631 (void) printf("%s%s\n", line
, sumline
[i
]);
636 if (flags
& F_DTAIL
) {
637 (void) printf("%s\n\n", detail_line
);
638 detail_line
[0] = '\0';
643 * The following three routines are called back
644 * from the interpreters to display their stuff.
645 * The theory is that when snoop becomes a window
646 * based tool we can just supply a new version of
647 * get_sum_line and get_detail_line and not have
648 * to touch the interpreters at all.
653 int tsumcount
= sumcount
;
655 if (sumcount
>= MAXSUM
) {
656 sumcount
= 0; /* error recovery */
658 "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n",
662 sumline
[sumcount
][0] = '\0';
663 return (sumline
[sumcount
++]);
668 get_detail_line(int off
, int len
)
670 if (detail_line
[0]) {
671 (void) printf("%s\n", detail_line
);
672 detail_line
[0] = '\0';
674 return (detail_line
);
678 * This function exists to make sure that VLAN information is
679 * prepended to summary lines displayed. The problem this function
680 * solves is how to display VLAN information while in summary mode.
681 * Each interpretor uses the get_sum_line and get_detail_line functions
682 * to get a character buffer to display information to the user.
683 * get_sum_line is the important one here. Each call to get_sum_line
684 * gets a buffer which stores one line of information. In summary mode,
685 * the last line generated is the line printed. Instead of changing each
686 * interpreter to add VLAN information to the summary line, the ethernet
687 * interpreter changes to call this function and set an ID. If the ID is not
688 * zero and snoop is in default summary mode, snoop displays the
689 * VLAN information at the beginning of the output line. Otherwise,
690 * no VLAN information is displayed.
700 * Works like printf (fmt string and variable args)
701 * except that it will substitute an error message
702 * for a "%m" string (like syslog) and it calls
703 * long_jump - it doesn't return to where it was
704 * called from - it goes to the last setjmp().
708 pr_err(const char *fmt
, ...)
714 (void) strcpy(buf
, "snoop: ");
715 p2
= buf
+ strlen(buf
);
718 * Note that we terminate the buffer with '\n' and '\0'.
720 for (p1
= fmt
; *p1
!= '\0' && p2
< buf
+ sizeof (buf
) - 2; p1
++) {
721 if (*p1
== '%' && *(p1
+1) == 'm') {
724 if ((errstr
= strerror(errno
)) != NULL
) {
726 (void) strlcat(buf
, errstr
, sizeof (buf
));
734 if (p2
> buf
&& *(p2
-1) != '\n')
739 /* LINTED: E_SEC_PRINTF_VAR_FMT */
740 (void) vfprintf(stderr
, buf
, ap
);
742 snoop_sigrecover(-1, NULL
, NULL
); /* global error recovery */
746 * Store a copy of linkname associated with the DLPI handle.
747 * Save errno before closing the dlpi handle so that the
748 * correct error value is used if 'err' is a system error.
751 pr_errdlpi(dlpi_handle_t dh
, const char *cmd
, int err
)
753 int save_errno
= errno
;
754 char linkname
[DLPI_LINKNAME_MAX
];
756 (void) strlcpy(linkname
, dlpi_linkname(dh
), sizeof (linkname
));
761 pr_err("%s on \"%s\": %s", cmd
, linkname
, dlpi_strerror(err
));
766 * PLEASE keep this up to date!
767 * Naive users *love* this stuff.
772 (void) fprintf(stderr
, "\nUsage: snoop\n");
773 (void) fprintf(stderr
,
774 "\t[ -a ] # Listen to packets on audio\n");
775 (void) fprintf(stderr
,
776 "\t[ -d link ] # Listen on named link\n");
777 (void) fprintf(stderr
,
778 "\t[ -s snaplen ] # Truncate packets\n");
779 (void) fprintf(stderr
,
780 "\t[ -I IP interface ] # Listen on named IP interface\n");
781 (void) fprintf(stderr
,
782 "\t[ -c count ] # Quit after count packets\n");
783 (void) fprintf(stderr
,
784 "\t[ -P ] # Turn OFF promiscuous mode\n");
785 (void) fprintf(stderr
,
786 "\t[ -D ] # Report dropped packets\n");
787 (void) fprintf(stderr
,
788 "\t[ -S ] # Report packet size\n");
789 (void) fprintf(stderr
,
790 "\t[ -i file ] # Read previously captured packets\n");
791 (void) fprintf(stderr
,
792 "\t[ -o file ] # Capture packets in file\n");
793 (void) fprintf(stderr
,
794 "\t[ -n file ] # Load addr-to-name table from file\n");
795 (void) fprintf(stderr
,
796 "\t[ -N ] # Create addr-to-name table\n");
797 (void) fprintf(stderr
,
798 "\t[ -t r|a|d ] # Time: Relative, Absolute or Delta\n");
799 (void) fprintf(stderr
,
800 "\t[ -v ] # Verbose packet display\n");
801 (void) fprintf(stderr
,
802 "\t[ -V ] # Show all summary lines\n");
803 (void) fprintf(stderr
,
804 "\t[ -p first[,last] ] # Select packet(s) to display\n");
805 (void) fprintf(stderr
,
806 "\t[ -x offset[,length] ] # Hex dump from offset for length\n");
807 (void) fprintf(stderr
,
808 "\t[ -C ] # Print packet filter code\n");
809 (void) fprintf(stderr
,
810 "\t[ -q ] # Suppress printing packet count\n");
811 (void) fprintf(stderr
,
812 "\t[ -r ] # Do not resolve address to name\n");
813 (void) fprintf(stderr
,
814 "\n\t[ filter expression ]\n");
815 (void) fprintf(stderr
, "\nExample:\n");
816 (void) fprintf(stderr
, "\tsnoop -o saved host fred\n\n");
817 (void) fprintf(stderr
, "\tsnoop -i saved -tr -v -p19\n");
822 * sdefault: default global alarm handler. Causes the current packet
828 snoop_nrecover
= SNOOP_MAXRECOVER
;
832 * snoop_alarm: register or unregister an alarm handler to be called after
833 * s_sec seconds. Because snoop wasn't written to tolerate random signal
834 * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
836 * s_sec argument of 0 seconds unregisters the handler.
837 * s_handler argument of NULL registers default handler sdefault(), or
838 * unregisters all signal handlers (for error recovery).
840 * Variables must be volatile to force the compiler to not optimize
841 * out the signal blocking.
845 snoop_alarm(int s_sec
, void (*s_handler
)())
848 volatile time_t nalarm
= 0;
849 volatile struct snoop_handler
*sh
= NULL
;
850 volatile struct snoop_handler
*hp
, *tp
, *next
;
851 volatile sigset_t s_mask
;
852 volatile int ret
= -1;
854 (void) sigemptyset((sigset_t
*)&s_mask
);
855 (void) sigaddset((sigset_t
*)&s_mask
, SIGALRM
);
859 /* register an alarm handler */
862 sh
= malloc(sizeof (struct snoop_handler
));
863 sh
->s_time
= now
+ s_sec
;
864 if (s_handler
== NULL
)
865 s_handler
= sdefault
;
866 sh
->s_handler
= s_handler
;
868 (void) sigprocmask(SIG_BLOCK
, (sigset_t
*)&s_mask
, NULL
);
869 if (snoop_hp
== NULL
) {
870 snoop_hp
= snoop_tp
= (struct snoop_handler
*)sh
;
872 snoop_nalarm
= sh
->s_time
;
873 (void) alarm(sh
->s_time
- now
);
875 snoop_tp
->s_next
= (struct snoop_handler
*)sh
;
876 snoop_tp
= (struct snoop_handler
*)sh
;
878 if (sh
->s_time
< snoop_nalarm
) {
879 snoop_nalarm
= sh
->s_time
;
880 (void) alarm(sh
->s_time
- now
);
883 (void) sigprocmask(SIG_UNBLOCK
, (sigset_t
*)&s_mask
, NULL
);
888 /* unregister an alarm handler */
889 (void) sigprocmask(SIG_BLOCK
, (sigset_t
*)&s_mask
, NULL
);
890 tp
= (struct snoop_handler
*)&snoop_hp
;
891 for (hp
= snoop_hp
; hp
; hp
= next
) {
893 if (s_handler
== NULL
|| hp
->s_handler
== s_handler
) {
895 tp
->s_next
= hp
->s_next
;
896 if (snoop_tp
== hp
) {
897 if (tp
== (struct snoop_handler
*)&snoop_hp
)
900 snoop_tp
= (struct snoop_handler
*)tp
;
904 if (nalarm
== 0 || nalarm
> hp
->s_time
)
905 nalarm
= now
< hp
->s_time
? hp
->s_time
:
911 * Stop or adjust timer
913 if (snoop_hp
== NULL
) {
916 } else if (nalarm
> 0 && nalarm
< snoop_nalarm
) {
917 snoop_nalarm
= nalarm
;
918 (void) alarm(nalarm
- now
);
921 (void) sigprocmask(SIG_UNBLOCK
, (sigset_t
*)&s_mask
, NULL
);
926 * snoop_recover: reset snoop's output area, and any internal variables,
927 * to allow continuation.
928 * XXX: make this an interface such that each interpreter can
929 * register a reset routine.
936 /* Error recovery: reset output_area and associated variables */
937 for (i
= 0; i
< MAXSUM
; i
++)
938 sumline
[i
][0] = '\0';
939 detail_line
[0] = '\0';
944 /* stacking/unstacking cannot be relied upon */
946 total_encap_levels
= 1;
948 /* remove any pending timeouts */
949 (void) snoop_alarm(0, NULL
);
953 * snoop_sigrecover: global sigaction routine to manage recovery
954 * from catastrophic interpreter failures while interpreting
955 * corrupt trace files/packets. SIGALRM timeouts, program errors,
956 * and user termination are all handled. In the case of a corrupt
957 * packet or confused interpreter, the packet will be skipped, and
958 * execution will continue in scan().
960 * Global alarm handling (see snoop_alarm()) is managed here.
962 * Variables must be volatile to force the compiler to not optimize
963 * out the signal blocking.
967 snoop_sigrecover(int sig
, siginfo_t
*info
, void *p
)
970 volatile time_t nalarm
= 0;
971 volatile struct snoop_handler
*hp
;
974 * Invoke any registered alarms. This involves first calculating
975 * the time for the next alarm, setting it up, then progressing
976 * through handler invocations. Note that since handlers may
977 * use siglongjmp(), in the worst case handlers may be serviced
980 if (sig
== SIGALRM
) {
982 /* Calculate next alarm time */
983 for (hp
= snoop_hp
; hp
; hp
= hp
->s_next
) {
985 if ((hp
->s_time
- now
) > 0) {
986 if (nalarm
== 0 || nalarm
> hp
->s_time
)
987 nalarm
= now
< hp
->s_time
?
988 hp
->s_time
: now
+ 1;
992 /* Setup next alarm */
994 snoop_nalarm
= nalarm
;
995 (void) alarm(nalarm
- now
);
1000 /* Invoke alarm handlers (may not return) */
1001 for (hp
= snoop_hp
; hp
; hp
= hp
->s_next
) {
1003 if ((now
- hp
->s_time
) >= 0) {
1004 hp
->s_time
= 0; /* only invoke once */
1015 * Exit if a signal has occurred after snoop has begun the process
1022 * If an alarm handler has timed out, and snoop_nrecover has
1023 * reached SNOOP_MAXRECOVER, skip to the next packet.
1025 * If any other signal has occurred, and snoop_nrecover has
1026 * reached SNOOP_MAXRECOVER, give up.
1028 if (sig
== SIGALRM
) {
1029 if (ioctl(STDOUT_FILENO
, I_CANPUT
, 0) == 0) {
1031 * We've stalled on output, which is not a critical
1032 * failure. Reset the recovery counter so we do not
1033 * consider this a persistent failure, and return so
1034 * we do not skip this packet.
1039 if (snoop_nrecover
>= SNOOP_MAXRECOVER
) {
1040 (void) fprintf(stderr
,
1041 "snoop: WARNING: skipping from packet %d\n",
1045 /* continue trying */
1048 } else if (snoop_nrecover
>= SNOOP_MAXRECOVER
) {
1049 (void) fprintf(stderr
,
1050 "snoop: ERROR: cannot recover from packet %d\n", count
);
1055 (void) fprintf(stderr
, "snoop_sigrecover(%d, %p, %p)\n", sig
, info
, p
);
1059 * Prepare to quit. This allows final processing to occur
1060 * after first terminal interruption.
1062 if (sig
== SIGTERM
|| sig
== SIGHUP
|| sig
== SIGINT
) {
1065 } else if (sig
!= -1 && sig
!= SIGALRM
) {
1066 /* Inform user that snoop has taken a fault */
1067 (void) fprintf(stderr
,
1068 "WARNING: received signal %d from packet %d\n",
1072 /* Reset interpreter variables */
1075 /* Continue in scan() with the next packet */
1076 siglongjmp(jmp_env
, 1);
1081 * Protected malloc for global error recovery: prepare for interpreter
1082 * failures with corrupted packets or confused interpreters. Dynamically
1083 * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
1084 * catch writes outside of the allocated region.
1087 protmalloc(size_t nbytes
)
1090 int psz
= sysconf(_SC_PAGESIZE
);
1092 nbytes
= P2ROUNDUP(nbytes
, psz
);
1093 start
= mmap(NULL
, nbytes
+ psz
* 2, PROT_READ
|PROT_WRITE
,
1094 MAP_PRIVATE
|MAP_ANON
, -1, 0);
1095 if (start
== MAP_FAILED
) {
1096 perror("Error: protmalloc: mmap");
1099 assert(IS_P2ALIGNED(start
, psz
));
1100 if (mprotect(start
, 1, PROT_NONE
) == -1)
1101 perror("Warning: mprotect");
1104 if (mprotect(start
+ nbytes
, 1, PROT_NONE
) == -1)
1105 perror("Warning: mprotect");
1111 * resetperm - reduce security vulnerabilities by resetting
1112 * owner/group/permissions. Always attempt setuid() - if we have
1113 * permission to drop our privilege level, do so.
1118 if (geteuid() == 0) {
1119 (void) setgid(GID_NOBODY
);
1120 (void) setuid(UID_NOBODY
);