summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <gharris@sonic.net>2022-03-29 00:51:21 -0700
committerGuy Harris <gharris@sonic.net>2022-03-29 00:51:21 -0700
commitbe43281053727d9a32c479813fd0ec79bdaf2dda (patch)
treee054f7f33cd3a898f5610800015c24fb276e9bcc
parent518e1bf60b5a72f29593e00a535f0a563d5d077b (diff)
downloadtcpdump-be43281053727d9a32c479813fd0ec79bdaf2dda.tar.gz
Make sure we don't set the snapend before the beginning of the packet.
If a caller attempts to set it after the current snapend, just silently ignore the attempt. If they try to set it before the beginning of the packet, report it as a bug and quit dissection. Add a new setjmp() return value meaning "bug" rather than "truncated packet", add an "nd_bug_longjmp()" routine for reporting bugs where we should quit dissecting, and use that in this case.
-rw-r--r--netdissect.c61
-rw-r--r--netdissect.h17
-rw-r--r--print.c7
3 files changed, 76 insertions, 9 deletions
diff --git a/netdissect.c b/netdissect.c
index 7e46d6aa..a706a6a0 100644
--- a/netdissect.c
+++ b/netdissect.c
@@ -185,9 +185,31 @@ nd_push_snapend(netdissect_options *ndo, const u_char *new_snapend)
ndspi->ndspi_snapend = ndo->ndo_snapend;
ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
- /* No new packet pointer, either */
- if (new_snapend < ndo->ndo_snapend)
- ndo->ndo_snapend = new_snapend;
+ /*
+ * Make sure the new snapend is sane.
+ *
+ * If it's after the current snapend, it's not valid. We
+ * silently ignore the new setting; that means that our callers
+ * don't have to do this check themselves, and also means that
+ * if the new length is used when dissecting, we'll go past the
+ * snapend and report an error.
+ *
+ * If it's before the beginning of the packet, it's not valid.
+ * That "should not happen", but might happen with a *very*
+ * large adjustment to the snapend; our callers *should* check
+ * for that, so we fail if they haven't done so.
+ */
+ if (new_snapend <= ndo->ndo_snapend) {
+ /* Snapend isn't past the previous snapend */
+ if (new_snapend >= ndo->ndo_packetp) {
+ /* And it isn't before the beginning of the packet */
+ ndo->ndo_snapend = new_snapend;
+ } else {
+ /* But it's before the beginning of the packet */
+ ND_PRINT(" [new snapend before beginning of packet in nd_push_snapend]");
+ nd_bug_longjmp(ndo);
+ }
+ }
ndo->ndo_packet_info_stack = ndspi;
return (1); /* success */
@@ -203,14 +225,37 @@ void
nd_change_snapend(netdissect_options *ndo, const u_char *new_snapend)
{
struct netdissect_saved_packet_info *ndspi;
+ const u_char *previous_snapend;
ndspi = ndo->ndo_packet_info_stack;
- if (ndspi->ndspi_prev != NULL) {
- if (new_snapend <= ndspi->ndspi_prev->ndspi_snapend)
- ndo->ndo_snapend = new_snapend;
- } else {
- if (new_snapend < ndo->ndo_snapend)
+ if (ndspi->ndspi_prev != NULL)
+ previous_snapend = ndspi->ndspi_prev->ndspi_snapend;
+ else
+ previous_snapend = ndo->ndo_snapend;
+ /*
+ * Make sure the new snapend is sane.
+ *
+ * If it's after the current snapend, it's not valid. We
+ * silently ignore the new setting; that means that our callers
+ * don't have to do this check themselves, and also means that
+ * if the new length is used when dissecting, we'll go past the
+ * snapend and report an error.
+ *
+ * If it's before the beginning of the packet, it's not valid.
+ * That "should not happen", but might happen with a *very*
+ * large adjustment to the snapend; our callers *should* check
+ * for that, so we fail if they haven't done so.
+ */
+ if (new_snapend <= previous_snapend) {
+ /* Snapend isn't past the previous snapend */
+ if (new_snapend >= ndo->ndo_packetp) {
+ /* And it isn't before the beginning of the packet */
ndo->ndo_snapend = new_snapend;
+ } else {
+ /* But it's before the beginning of the packet */
+ ND_PRINT(" [new snapend before beginning of packet in nd_push_snapend]");
+ nd_bug_longjmp(ndo);
+ }
}
}
diff --git a/netdissect.h b/netdissect.h
index e2b77860..605a9c9b 100644
--- a/netdissect.h
+++ b/netdissect.h
@@ -193,7 +193,8 @@ struct netdissect_saved_packet_info {
};
/* 'val' value(s) for longjmp */
-#define ND_TRUNCATED 1
+#define ND_TRUNCATED 1 /* packet data too short */
+#define ND_BUG 2 /* bug of some sort */
struct netdissect_options {
int ndo_bflag; /* print 4 byte ASes in ASDOT notation */
@@ -283,6 +284,20 @@ nd_trunc_longjmp(netdissect_options *ndo)
#endif /* _AIX */
}
+static inline NORETURN void
+nd_bug_longjmp(netdissect_options *ndo)
+{
+ longjmp(ndo->ndo_early_end, ND_BUG);
+#ifdef _AIX
+ /*
+ * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells
+ * XL C that the function is noreturn, but GCC remains unaware of that and
+ * yields a "'noreturn' function does return" warning.
+ */
+ ND_UNREACHABLE
+#endif /* _AIX */
+}
+
#define PT_VAT 1 /* Visual Audio Tool */
#define PT_WB 2 /* distributed White Board */
#define PT_RPC 3 /* Remote Procedure Call */
diff --git a/print.c b/print.c
index fbb1b3b1..b595a882 100644
--- a/print.c
+++ b/print.c
@@ -421,6 +421,13 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
profile_func_level = pretty_print_packet_level;
#endif
break;
+ case ND_BUG:
+ /*
+ * A printer or helper routine quit because a bug was
+ * detected; report it.
+ */
+ ND_PRINT(" [Bug in %s protocol printer]", ndo->ndo_protocol);
+ break;
}
hdrlen = ndo->ndo_ll_hdr_len;