comms/voip/smtp: 30 CWE-407 defects + 9 CLEAN; 224 sites, 101 ecosystems
This commit is contained in:
parent
4d3fcc8e73
commit
b3842ab6b8
86 changed files with 6516 additions and 5 deletions
96
defects/opensmtpd/patch/opensmtpd-0001.patch
Normal file
96
defects/opensmtpd/patch/opensmtpd-0001.patch
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
--- a/usr.sbin/smtpd/ruleset.c
|
||||
+++ b/usr.sbin/smtpd/ruleset.c
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
#include <sys/queue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -30,7 +32,55 @@
|
||||
#include "smtpd.h"
|
||||
|
||||
#define MATCH_RESULT(r, neg) ((r) == -1 ? -1 : ((neg) < 0 ? !(r) : (r)))
|
||||
+
|
||||
+/*
|
||||
+ * CWE-407 fix: dispatch index for ruleset_match().
|
||||
+ *
|
||||
+ * Build a dict from dest_domain -> first candidate rule at ruleset_commit
|
||||
+ * time (called after all rules are loaded). Rules with no flag_for (match-all)
|
||||
+ * are appended to every bucket and to a special "*" bucket for unknown domains.
|
||||
+ *
|
||||
+ * On lookup, fetch the candidate list for evp->dest.domain (O(1) dict_get),
|
||||
+ * evaluate only those rules. Falls back to full TAILQ scan if the index was
|
||||
+ * not built (e.g., all rules use regex to/from).
|
||||
+ */
|
||||
+static struct dict ruleset_to_index;
|
||||
+static int ruleset_indexed = 0;
|
||||
+
|
||||
+void
|
||||
+ruleset_build_index(void)
|
||||
+{
|
||||
+ struct rule *r;
|
||||
+ struct table *t;
|
||||
+ void *iter;
|
||||
+ const char *key;
|
||||
+
|
||||
+ dict_init(&ruleset_to_index);
|
||||
+ ruleset_indexed = 1;
|
||||
+
|
||||
+ TAILQ_FOREACH(r, env->sc_rules, r_entry) {
|
||||
+ if (!r->flag_for || r->flag_for_regex) {
|
||||
+ /* match-all or regex rule: must be evaluated for every domain */
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Simple domain table: index by table name for now.
|
||||
+ * A more aggressive optimisation would resolve table contents to
|
||||
+ * individual domain keys; left as a future enhancement. */
|
||||
+ if (r->table_for) {
|
||||
+ struct rule **slot = dict_get(&ruleset_to_index, r->table_for);
|
||||
+ if (slot == NULL) {
|
||||
+ slot = xcalloc(1, sizeof *slot);
|
||||
+ dict_set(&ruleset_to_index, r->table_for, slot);
|
||||
+ }
|
||||
+ *slot = r;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
static int
|
||||
ruleset_match_tag(struct rule *r, const struct envelope *evp)
|
||||
@@ -222,6 +268,28 @@ struct rule *
|
||||
ruleset_match(const struct envelope *evp)
|
||||
{
|
||||
struct rule *r;
|
||||
+ int i = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * CWE-407 fix: O(1) domain dispatch.
|
||||
+ * Look up the dest domain in the index to get a pre-filtered candidate
|
||||
+ * rule. If found, check it directly. This covers the dominant case
|
||||
+ * of a rule with a plain "for domain <table>" match.
|
||||
+ */
|
||||
+ if (ruleset_indexed && evp->dest.domain[0] != '\0') {
|
||||
+ struct rule **rp = dict_get(&ruleset_to_index, evp->dest.domain);
|
||||
+ if (rp && *rp) {
|
||||
+ int match = 1;
|
||||
+#define TRY(x) do { int _r = (x); if (_r == -1) goto tempfail; if (_r == 0) { match = 0; break; } } while(0)
|
||||
+ TRY(ruleset_match_tag(*rp, evp));
|
||||
+ TRY(ruleset_match_from(*rp, evp));
|
||||
+ TRY(ruleset_match_to(*rp, evp));
|
||||
+ TRY(ruleset_match_smtp_helo(*rp, evp));
|
||||
+ TRY(ruleset_match_smtp_auth(*rp, evp));
|
||||
+ TRY(ruleset_match_smtp_starttls(*rp, evp));
|
||||
+ TRY(ruleset_match_smtp_mail_from(*rp, evp));
|
||||
+ TRY(ruleset_match_smtp_rcpt_to(*rp, evp));
|
||||
+#undef TRY
|
||||
+ if (match) return *rp;
|
||||
+ /* Fall through to full scan on miss */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
int i = 0;
|
||||
|
||||
#define MATCH_EVAL(x) \
|
||||
Loading…
Add table
Add a link
Reference in a new issue