From 8b8667503b5248524dbe94fa11be312fca5b380c Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 3 Dec 2024 00:13:43 +0000 Subject: [PATCH 1/1] Fix IP SRR parsing. Bug 3124 --- doc/doc-txt/ChangeLog | 7 +++++ src/src/smtp_in.c | 71 +++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 37cc3b77d..cf9420b19 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -80,6 +80,13 @@ JH/15 Disallow tainted metadata in lists. - Exclamation-marks ("!" signifying negation) are not checked for taint at this time. +JH/16 Bug 3124: Fix theoretical crash in received connection, triggerable by a + crafted packet with massive count of IP options. A buffer overflow was + detected, but a null-deref results. In practice, IP packets with options + are rare (to non-existent). Exim refuses connections having any, but this + issue was in the coding for logging preceding that refusal. If coredumps + were enabled (not common), an attack could cause filesystem space usage. + Exim version 4.98 ----------------- diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index fd28c4454..be065eafb 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2317,10 +2317,9 @@ if (!f.sender_host_unknown) else if (optlen > 0) { - uschar * p = big_buffer; - uschar * pend = big_buffer + big_buffer_size; + uschar * p = big_buffer, * pend = big_buffer + big_buffer_size; uschar * adptr; - int optcount; + int optcount, sprint_len; struct in_addr addr; # if OPTSTYLE == 1 @@ -2351,57 +2350,57 @@ if (!f.sender_host_unknown) case IPOPT_LSRR: if (! # if OPTSTYLE == 1 - string_format(p, pend-p, " %s [@%s", - (*opt == IPOPT_SSRR)? "SSRR" : "LSRR", - inet_ntoa(*((struct in_addr *)(&(ipopt->faddr))))) + string_format(p, pend-p, " %s [@%s%n", + *opt == IPOPT_SSRR ? "SSRR" : "LSRR", + inet_ntoa(*(struct in_addr *)&ipopt->faddr), + &sprint_len) # elif OPTSTYLE == 2 - string_format(p, pend-p, " %s [@%s", - (*opt == IPOPT_SSRR)? "SSRR" : "LSRR", - inet_ntoa(ipopt->ip_dst)) + string_format(p, pend-p, " %s [@%s%n", + *opt == IPOPT_SSRR ? "SSRR" : "LSRR", + inet_ntoa(ipopt->ip_dst), + &sprint_len) # else - string_format(p, pend-p, " %s [@%s", - (*opt == IPOPT_SSRR)? "SSRR" : "LSRR", - inet_ntoa(ipopt->ipopt_dst)) + string_format(p, pend-p, " %s [@%s%n", + *opt == IPOPT_SSRR ? "SSRR" : "LSRR", + inet_ntoa(ipopt->ipopt_dst), + &sprint_len) # endif - ) - { + ) opt = NULL; - break; - } - - p += Ustrlen(p); - optcount = (opt[1] - 3) / sizeof(struct in_addr); - adptr = opt + 3; - while (optcount-- > 0) + else { - memcpy(&addr, adptr, sizeof(addr)); - if (!string_format(p, pend - p - 1, "%s%s", - (optcount == 0)? ":" : "@", inet_ntoa(addr))) + p += sprint_len; + optcount = (opt[1] - 3) / sizeof(struct in_addr); + adptr = opt + 3; + while (optcount-- > 0) { - opt = NULL; - break; + memcpy(&addr, adptr, sizeof(addr)); + if (!string_format(p, pend - p - 1, "%s%s%n", + optcount == 0 ? ":" : "@", inet_ntoa(addr), &sprint_len)) + { opt = NULL; goto bad_srr; } + p += sprint_len; + adptr += sizeof(struct in_addr); } - p += Ustrlen(p); - adptr += sizeof(struct in_addr); + *p++ = ']'; + opt += opt[1]; } - *p++ = ']'; - opt += opt[1]; - break; +bad_srr: break; default: + if (pend - p < 4 + 3*opt[1]) + opt = NULL; + else { - if (pend - p < 4 + 3*opt[1]) { opt = NULL; break; } - Ustrcat(p, "[ "); - p += 2; + p = Ustpcpy(p, "[ "); for (int i = 0; i < opt[1]; i++) p += sprintf(CS p, "%2.2x ", opt[i]); *p++ = ']'; + opt += opt[1]; } - opt += opt[1]; break; } - *p = 0; + *p = '\0'; log_write(0, LOG_MAIN, "%s", big_buffer); /* Refuse any call with IP options. This is what tcpwrappers 7.5 does. */ -- 2.30.2