117 lines
3 KiB
Diff
117 lines
3 KiB
Diff
# UNDF: UNDF-2026-000001021
|
|
--- a/support/export/client.c
|
|
+++ b/support/export/client.c
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* support/export/client.c
|
|
+ * CWE-407: client_lookup non-FQDN branch O(N) scan per call = O(N^2) total
|
|
*
|
|
* Maintain list of nfsd clients.
|
|
*
|
|
@@ -22,6 +23,7 @@
|
|
|
|
#include "sockaddr.h"
|
|
#include "misc.h"
|
|
+#include "search.h" /* hsearch_r: POSIX hash table */
|
|
#include "nfslib.h"
|
|
#include "exportfs.h"
|
|
|
|
@@ -33,6 +35,31 @@ extern int innetgr(char *netgr, char *host, char *, char *);
|
|
static char *add_name(char *old, const char *add);
|
|
|
|
nfs_client *clientlist[MCL_MAXTYPES] = { NULL, };
|
|
+/*
|
|
+ * Hash table for O(1) hostname lookup of non-FQDN clients.
|
|
+ * Keyed by lowercased hostname string, value is nfs_client pointer.
|
|
+ * Sized for up to 8192 unique non-FQDN clients (wildcards, netgroups,
|
|
+ * subnets, GSS identifiers). Resized on overflow would be ideal but
|
|
+ * POSIX hsearch_r does not support resize, so we pre-allocate large.
|
|
+ *
|
|
+ * This replaces the O(N) linked list scan in client_lookup for
|
|
+ * non-FQDN types, reducing export_read from O(N^2) to O(N).
|
|
+ */
|
|
+#define CLIENT_HT_SIZE 8192
|
|
+static struct hsearch_data client_ht;
|
|
+static int client_ht_initialized = 0;
|
|
+
|
|
+static void client_ht_init(void)
|
|
+{
|
|
+ if (!client_ht_initialized) {
|
|
+ memset(&client_ht, 0, sizeof(client_ht));
|
|
+ hcreate_r(CLIENT_HT_SIZE, &client_ht);
|
|
+ client_ht_initialized = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Forward declaration */
|
|
+static nfs_client *client_ht_lookup(const char *hname);
|
|
+static void client_ht_insert(nfs_client *clp);
|
|
|
|
|
|
static void
|
|
@@ -286,11 +313,13 @@ client_lookup(char *hname, int canonical)
|
|
if (client_check(clp, ai))
|
|
break;
|
|
} else {
|
|
- for (clp = clientlist[htype]; clp; clp = clp->m_next) {
|
|
- if (strcasecmp(hname, clp->m_hostname)==0)
|
|
- break;
|
|
- }
|
|
+ /*
|
|
+ * Use hash table for O(1) lookup instead of O(N) linked
|
|
+ * list scan. With many netgroup/wildcard/subnet entries,
|
|
+ * the old code was O(N^2) over all export_create calls.
|
|
+ */
|
|
+ clp = client_ht_lookup(hname);
|
|
}
|
|
|
|
if (clp == NULL) {
|
|
@@ -302,6 +331,8 @@ client_lookup(char *hname, int canonical)
|
|
clp = NULL;
|
|
goto out;
|
|
}
|
|
+ if (htype != MCL_FQDN)
|
|
+ client_ht_insert(clp);
|
|
client_add(clp);
|
|
}
|
|
|
|
@@ -360,9 +391,44 @@ client_freeall(void)
|
|
while (*head) {
|
|
*head = (clp = *head)->m_next;
|
|
client_free(clp);
|
|
}
|
|
}
|
|
+ /* Destroy and reinitialize hash table */
|
|
+ if (client_ht_initialized) {
|
|
+ hdestroy_r(&client_ht);
|
|
+ client_ht_initialized = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static nfs_client *client_ht_lookup(const char *hname)
|
|
+{
|
|
+ ENTRY item, *found;
|
|
+
|
|
+ client_ht_init();
|
|
+ item.key = (char *)hname;
|
|
+ item.data = NULL;
|
|
+
|
|
+ if (hsearch_r(item, FIND, &found, &client_ht) != 0)
|
|
+ return (nfs_client *)found->data;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void client_ht_insert(nfs_client *clp)
|
|
+{
|
|
+ ENTRY item, *found;
|
|
+
|
|
+ client_ht_init();
|
|
+ item.key = clp->m_hostname;
|
|
+ item.data = clp;
|
|
+
|
|
+ /* hsearch_r with ENTER will insert if not found */
|
|
+ hsearch_r(item, ENTER, &found, &client_ht);
|
|
}
|
|
|
|
/**
|
|
* client_resolve - look up an IP address
|