hurd: add patches for hurd-0001/0006 (auth) and hurd-0002/0003 (notify htable)
This commit is contained in:
parent
e94a4b17b3
commit
360b7abb54
2 changed files with 551 additions and 0 deletions
|
|
@ -0,0 +1,248 @@
|
|||
From a56d5fc886eaea781d1033bf5dc1cd94e4dad4a0 Mon Sep 17 00:00:00 2001
|
||||
From: "russell@unturf.com" <russell@unturf.com>
|
||||
Date: Sat, 4 Apr 2026 20:29:09 -0400
|
||||
Subject: [PATCH 1/2] =?UTF-8?q?CWE-407=20(hurd-0001,=20hurd-0006):=20fix?=
|
||||
=?UTF-8?q?=20O(N=C3=97M=C3=97k)=20auth=20verify=20and=20O(k=C2=B2)=20idve?=
|
||||
=?UTF-8?q?c=20merge?=
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
hurd-0001 (auth/auth.c): S_auth_makeauth scanned every auth handle for every
|
||||
requested UID/GID — O((neuids+nauids+negids+nagids) × nauths × k) where k is
|
||||
idvec size. Fixed by building union sets of permitted UIDs/GIDs from all auth
|
||||
handles once before the verification loops. Verification is now a single pass
|
||||
over the union set — O(nauths×k) build + O(N×k) verify.
|
||||
|
||||
hurd-0006 (libshouldbeinlibc/idvec.c): idvec_merge_ids checked each incoming
|
||||
id by linear scan — O(num × num_old). Fixed by sorting a copy of the existing
|
||||
ids and using binary search — O(num_old×log(num_old) + num×log(num_old)).
|
||||
Called by S_auth_makeauth on every exec/setuid.
|
||||
---
|
||||
auth/auth.c | 98 ++++++++++++++++-----------------------
|
||||
libshouldbeinlibc/idvec.c | 51 ++++++++++++++++----
|
||||
2 files changed, 84 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/auth/auth.c b/auth/auth.c
|
||||
index d5ef5876..bf75bfe0 100644
|
||||
--- a/auth/auth.c
|
||||
+++ b/auth/auth.c
|
||||
@@ -126,6 +126,7 @@ S_auth_makeauth (struct authhandle *auth,
|
||||
int hasroot = 0;
|
||||
error_t err;
|
||||
size_t i, j;
|
||||
+ struct idvec all_uids, all_gids;
|
||||
|
||||
if (!auth)
|
||||
return EOPNOTSUPP;
|
||||
@@ -141,78 +142,50 @@ S_auth_makeauth (struct authhandle *auth,
|
||||
/* Verify that the union of the handles passed in either contains euid 0
|
||||
(root), or contains all the requested ids. */
|
||||
|
||||
-#define isuid(uid, auth) \
|
||||
- (idvec_contains (&(auth)->euids, uid) \
|
||||
- || idvec_contains (&(auth)->auids, uid))
|
||||
-#define groupmember(gid, auth) \
|
||||
- (idvec_contains (&(auth)->egids, gid) \
|
||||
- || idvec_contains (&(auth)->agids, gid))
|
||||
-#define isroot(auth) isuid (0, auth)
|
||||
+ /* CWE-407 fix (hurd-0001): build union sets of permitted UIDs and GIDs from
|
||||
+ all auth handles once, then verify all requested IDs against the union.
|
||||
+ Old complexity: O((neuids+nauids+negids+nagids) * nauths * k) where k is
|
||||
+ idvec size — each requested ID scanned every auth handle linearly.
|
||||
+ New complexity: O(nauths * k) build + O(N * log k) verify. */
|
||||
+ idvec_init (&all_uids);
|
||||
+ idvec_init (&all_gids);
|
||||
|
||||
- for (i = 0; i < nauths; i++)
|
||||
- if (auths[i] && isroot (auths[i]))
|
||||
+ for (j = 0; j < nauths; j++)
|
||||
+ if (auths[j])
|
||||
{
|
||||
- hasroot = 1;
|
||||
- break;
|
||||
+ if (idvec_contains (&auths[j]->euids, 0)
|
||||
+ || idvec_contains (&auths[j]->auids, 0))
|
||||
+ hasroot = 1;
|
||||
+ err = idvec_merge (&all_uids, &auths[j]->euids)
|
||||
+ ?: idvec_merge (&all_uids, &auths[j]->auids)
|
||||
+ ?: idvec_merge (&all_gids, &auths[j]->egids)
|
||||
+ ?: idvec_merge (&all_gids, &auths[j]->agids);
|
||||
+ if (err)
|
||||
+ goto free_idvecs;
|
||||
}
|
||||
|
||||
if (!hasroot)
|
||||
{
|
||||
- int has_it;
|
||||
-
|
||||
for (i = 0; i < neuids; i++)
|
||||
- {
|
||||
- has_it = 0;
|
||||
- for (j = 0; j < nauths; j++)
|
||||
- if (auths[j] && isuid (euids[i], auths[j]))
|
||||
- {
|
||||
- has_it = 1;
|
||||
- break;
|
||||
- }
|
||||
- if (!has_it)
|
||||
- goto eperm;
|
||||
- }
|
||||
+ if (!idvec_contains (&all_uids, euids[i]))
|
||||
+ goto eperm_free;
|
||||
|
||||
for (i = 0; i < nauids; i++)
|
||||
- {
|
||||
- has_it = 0;
|
||||
- for (j = 0; j < nauths; j++)
|
||||
- if (auths[j] && isuid (auids[i], auths[j]))
|
||||
- {
|
||||
- has_it = 1;
|
||||
- break;
|
||||
- }
|
||||
- if (!has_it)
|
||||
- goto eperm;
|
||||
- }
|
||||
+ if (!idvec_contains (&all_uids, auids[i]))
|
||||
+ goto eperm_free;
|
||||
|
||||
for (i = 0; i < negids; i++)
|
||||
- {
|
||||
- has_it = 0;
|
||||
- for (j = 0; j < nauths; j++)
|
||||
- if (auths[j] && groupmember (egids[i], auths[j]))
|
||||
- {
|
||||
- has_it = 1;
|
||||
- break;
|
||||
- }
|
||||
- if (!has_it)
|
||||
- goto eperm;
|
||||
- }
|
||||
+ if (!idvec_contains (&all_gids, egids[i]))
|
||||
+ goto eperm_free;
|
||||
|
||||
for (i = 0; i < nagids; i++)
|
||||
- {
|
||||
- has_it = 0;
|
||||
- for (j = 0; j < nauths; j++)
|
||||
- if (auths[j] && groupmember (agids[i], auths[j]))
|
||||
- {
|
||||
- has_it = 1;
|
||||
- break;
|
||||
- }
|
||||
- if (!has_it)
|
||||
- goto eperm;
|
||||
- }
|
||||
+ if (!idvec_contains (&all_gids, agids[i]))
|
||||
+ goto eperm_free;
|
||||
}
|
||||
|
||||
+ idvec_free_contents (&all_uids);
|
||||
+ idvec_free_contents (&all_gids);
|
||||
+
|
||||
err = create_authhandle (&newauth);
|
||||
|
||||
/* Create a new handle with the specified ids. */
|
||||
@@ -237,11 +210,22 @@ S_auth_makeauth (struct authhandle *auth,
|
||||
ports_port_deref (auths[j]);
|
||||
return err;
|
||||
|
||||
+ eperm_free:
|
||||
+ idvec_free_contents (&all_uids);
|
||||
+ idvec_free_contents (&all_gids);
|
||||
eperm:
|
||||
for (j = 1; j < nauths; j++)
|
||||
if (auths[j])
|
||||
ports_port_deref (auths[j]);
|
||||
return EPERM;
|
||||
+
|
||||
+ free_idvecs:
|
||||
+ idvec_free_contents (&all_uids);
|
||||
+ idvec_free_contents (&all_gids);
|
||||
+ for (j = 1; j < nauths; j++)
|
||||
+ if (auths[j])
|
||||
+ ports_port_deref (auths[j]);
|
||||
+ return err;
|
||||
}
|
||||
|
||||
/* Transaction handling. */
|
||||
diff --git a/libshouldbeinlibc/idvec.c b/libshouldbeinlibc/idvec.c
|
||||
index c60fc9fb..b78f6a2e 100644
|
||||
--- a/libshouldbeinlibc/idvec.c
|
||||
+++ b/libshouldbeinlibc/idvec.c
|
||||
@@ -19,6 +19,7 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <malloc.h>
|
||||
+#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "idvec.h"
|
||||
@@ -176,22 +177,56 @@ idvec_set (struct idvec *idvec, const struct idvec *new)
|
||||
return idvec_set_ids (idvec, new->ids, new->num);
|
||||
}
|
||||
|
||||
+/* Compare two uid_t values for qsort/bsearch. */
|
||||
+static int
|
||||
+uid_cmp (const void *a, const void *b)
|
||||
+{
|
||||
+ uid_t ua = *(const uid_t *)a;
|
||||
+ uid_t ub = *(const uid_t *)b;
|
||||
+ return (ua > ub) - (ua < ub);
|
||||
+}
|
||||
+
|
||||
/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as long as it
|
||||
- wasn't previously in IDVEC. */
|
||||
+ wasn't previously in IDVEC.
|
||||
+ CWE-407 fix (hurd-0006): was O(num * num_old) — linear scan per incoming id.
|
||||
+ Fixed to O(num_old * log(num_old) + num * log(num_old)) by sorting a copy of
|
||||
+ the existing ids and using binary search for duplicate detection. */
|
||||
error_t
|
||||
idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
|
||||
{
|
||||
error_t err = 0;
|
||||
unsigned num_old = idvec->num;
|
||||
+
|
||||
+ if (num_old == 0)
|
||||
+ {
|
||||
+ /* Nothing to deduplicate against — just append all ids. */
|
||||
+ while (num-- > 0 && !err)
|
||||
+ err = idvec_add (idvec, *ids++);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ /* Sort a copy of the existing ids for O(log k) binary search.
|
||||
+ We copy rather than sort in-place to preserve the original order,
|
||||
+ which callers may rely on (e.g. euids[0] is the primary uid). */
|
||||
+ uid_t sorted[num_old];
|
||||
+ memcpy (sorted, idvec->ids, num_old * sizeof (uid_t));
|
||||
+ qsort (sorted, num_old, sizeof (uid_t), uid_cmp);
|
||||
+
|
||||
while (num-- > 0 && !err)
|
||||
{
|
||||
- unsigned int i;
|
||||
- for (i = 0; i < num_old; i++)
|
||||
- if (idvec->ids[i] == *ids)
|
||||
- break;
|
||||
- if (i == num_old)
|
||||
- err = idvec_add (idvec, *ids);
|
||||
- ids++;
|
||||
+ uid_t id = *ids++;
|
||||
+ /* Binary search for id in sorted[0..num_old). */
|
||||
+ unsigned lo = 0, hi = num_old;
|
||||
+ while (lo < hi)
|
||||
+ {
|
||||
+ unsigned mid = lo + (hi - lo) / 2;
|
||||
+ if (sorted[mid] < id)
|
||||
+ lo = mid + 1;
|
||||
+ else
|
||||
+ hi = mid;
|
||||
+ }
|
||||
+ if (lo >= num_old || sorted[lo] != id)
|
||||
+ err = idvec_add (idvec, id);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
From de3b12674e0b0b259d449e70fea83f0491f6d937 Mon Sep 17 00:00:00 2001
|
||||
From: "russell@unturf.com" <russell@unturf.com>
|
||||
Date: Sat, 4 Apr 2026 20:29:19 -0400
|
||||
Subject: [PATCH 2/2] CWE-407 (hurd-0002, hurd-0003): replace
|
||||
_ports_notifications linked list with hash table
|
||||
|
||||
ports_interrupt_rpc_on_notification and ports_interrupt_notified_rpcs both
|
||||
scanned the global _ports_notifications linked list in O(N) on every RPC
|
||||
notification setup and every port-death event respectively.
|
||||
|
||||
Replace the list with _ports_notify_htable (hurd_ihash keyed on mach_port_t)
|
||||
for O(1) port lookup. Multiple entries with the same port but different 'what'
|
||||
values (rare; typically MACH_NOTIFY_DEAD_NAME only) are chained via
|
||||
ports_notify.next/prevp from the primary htable entry. The locp_offset
|
||||
mechanism auto-maintains htable_locp in each primary entry for O(1) removal.
|
||||
---
|
||||
libports/interrupt-notified-rpcs.c | 83 ++++++++++++++++-------
|
||||
libports/interrupt-on-notify.c | 103 ++++++++++++++++++-----------
|
||||
libports/ports.h | 18 +++--
|
||||
3 files changed, 138 insertions(+), 66 deletions(-)
|
||||
|
||||
diff --git a/libports/interrupt-notified-rpcs.c b/libports/interrupt-notified-rpcs.c
|
||||
index 49a15d0c..a301004b 100644
|
||||
--- a/libports/interrupt-notified-rpcs.c
|
||||
+++ b/libports/interrupt-notified-rpcs.c
|
||||
@@ -18,10 +18,18 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
+#include <stddef.h>
|
||||
#include "ports.h"
|
||||
|
||||
-/* A linked list of ports for which notification has been requested. */
|
||||
-struct ports_notify *_ports_notifications;
|
||||
+/* CWE-407 fix (hurd-0002/0003): hash table of active notification entries,
|
||||
+ keyed on mach_port_t. Replaces the former _ports_notifications linked list
|
||||
+ whose O(N) linear scan fired on every RPC setup and every port-death event.
|
||||
+ Multiple entries with the same port but different 'what' values are chained
|
||||
+ via ports_notify.next/prevp from the primary htable entry.
|
||||
+ locp_offset auto-maintains htable_locp in each primary ports_notify entry
|
||||
+ for O(1) removal via hurd_ihash_locp_remove. */
|
||||
+struct hurd_ihash _ports_notify_htable =
|
||||
+ HURD_IHASH_INITIALIZER (offsetof (struct ports_notify, htable_locp));
|
||||
|
||||
/* Free lists for notify structures. */
|
||||
struct ports_notify *_ports_free_ports_notifies;
|
||||
@@ -32,25 +40,31 @@ void
|
||||
ports_interrupt_notified_rpcs (void *object,
|
||||
mach_port_t port, mach_msg_id_t what)
|
||||
{
|
||||
- if (_ports_notifications)
|
||||
- {
|
||||
- struct ports_notify *np;
|
||||
+ struct ports_notify *np;
|
||||
+
|
||||
+ pthread_mutex_lock (&_ports_lock);
|
||||
+
|
||||
+ /* CWE-407 fix: O(1) hash lookup by port instead of O(N) list scan. */
|
||||
+ np = hurd_ihash_find (&_ports_notify_htable, (hurd_ihash_key_t) port);
|
||||
|
||||
- pthread_mutex_lock (&_ports_lock);
|
||||
- for (np = _ports_notifications; np; np = np->next)
|
||||
- if (np->port == port && np->what == what)
|
||||
+ /* Walk the short per-port chain to find the matching 'what' value.
|
||||
+ In practice each port has at most one notification type so this
|
||||
+ terminates in O(1). */
|
||||
+ while (np && np->what != what)
|
||||
+ np = np->next;
|
||||
+
|
||||
+ if (np)
|
||||
+ {
|
||||
+ struct rpc_notify *req;
|
||||
+ for (req = np->reqs; req; req = req->next_req)
|
||||
+ if (req->pending)
|
||||
{
|
||||
- struct rpc_notify *req;
|
||||
- for (req = np->reqs; req; req = req->next_req)
|
||||
- if (req->pending)
|
||||
- {
|
||||
- req->pending--;
|
||||
- hurd_thread_cancel (req->rpc->thread);
|
||||
- }
|
||||
- break;
|
||||
+ req->pending--;
|
||||
+ hurd_thread_cancel (req->rpc->thread);
|
||||
}
|
||||
- pthread_mutex_unlock (&_ports_lock);
|
||||
}
|
||||
+
|
||||
+ pthread_mutex_unlock (&_ports_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -64,19 +78,38 @@ remove_req (struct rpc_notify *req)
|
||||
*req->prev_req_p = req->next_req;
|
||||
|
||||
if (np->reqs == 0)
|
||||
- /* Now NP has no more reqests, so we can free it too. */
|
||||
+ /* Now NP has no more requests, so we can free it too. */
|
||||
{
|
||||
- /* Take NP out of the active list... */
|
||||
- if (np->next)
|
||||
- np->next->prevp = np->prevp;
|
||||
- *np->prevp = np->next;
|
||||
+ if (np->htable_locp)
|
||||
+ {
|
||||
+ /* NP is the primary htable entry for this port. Remove it first,
|
||||
+ then promote the next per-port entry (if any) as the new primary. */
|
||||
+ hurd_ihash_locp_remove (&_ports_notify_htable, np->htable_locp);
|
||||
+ np->htable_locp = NULL;
|
||||
+ if (np->next)
|
||||
+ {
|
||||
+ struct ports_notify *successor = np->next;
|
||||
+ successor->prevp = NULL;
|
||||
+ /* Re-add successor as the htable entry; ihash auto-sets
|
||||
+ successor->htable_locp via the locp_offset. */
|
||||
+ hurd_ihash_add (&_ports_notify_htable,
|
||||
+ (hurd_ihash_key_t) successor->port, successor);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* NP is in the per-port chain, not the htable primary entry. */
|
||||
+ if (np->next)
|
||||
+ np->next->prevp = np->prevp;
|
||||
+ *np->prevp = np->next;
|
||||
+ }
|
||||
|
||||
- /* And put it on the free list. */
|
||||
+ /* Put NP on the free list. */
|
||||
np->next = _ports_free_ports_notifies;
|
||||
_ports_free_ports_notifies = np;
|
||||
|
||||
if (np->pending)
|
||||
- /* And cancel the associated notification. */
|
||||
+ /* Cancel the associated notification. */
|
||||
{
|
||||
mach_port_t old;
|
||||
error_t err =
|
||||
@@ -86,7 +119,7 @@ remove_req (struct rpc_notify *req)
|
||||
&old);
|
||||
if (! err && old != MACH_PORT_NULL)
|
||||
mach_port_deallocate (mach_task_self (), old);
|
||||
- }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/libports/interrupt-on-notify.c b/libports/interrupt-on-notify.c
|
||||
index b358e840..69b904ef 100644
|
||||
--- a/libports/interrupt-on-notify.c
|
||||
+++ b/libports/interrupt-on-notify.c
|
||||
@@ -60,43 +60,72 @@ ports_interrupt_rpc_on_notification (void *object,
|
||||
pthread_mutex_lock (&_ports_lock);
|
||||
}
|
||||
|
||||
- /* Find any existing entry for PORT/WHAT. */
|
||||
- for (pn = _ports_notifications; pn; pn = pn->next)
|
||||
- if (pn->port == port && pn->what == what)
|
||||
- break;
|
||||
-
|
||||
- if (! pn)
|
||||
- /* A notification on a new port. */
|
||||
- {
|
||||
- pn = _ports_free_ports_notifies;
|
||||
-
|
||||
- if (pn)
|
||||
- _ports_free_ports_notifies = pn->next;
|
||||
- else
|
||||
- {
|
||||
- pn = malloc (sizeof (struct ports_notify));
|
||||
- if (! pn)
|
||||
- /* sigh. Free what we've alloced and return. */
|
||||
- {
|
||||
- new_req->next = _ports_free_rpc_notifies;
|
||||
- _ports_free_rpc_notifies = new_req;
|
||||
- pthread_mutex_unlock (&_ports_lock);
|
||||
- return ENOMEM;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- pn->reqs = 0;
|
||||
- pn->port = port;
|
||||
- pn->what = what;
|
||||
- pn->pending = 0;
|
||||
- pthread_mutex_init (&pn->lock, NULL);
|
||||
-
|
||||
- pn->next = _ports_notifications;
|
||||
- pn->prevp = &_ports_notifications;
|
||||
- if (_ports_notifications)
|
||||
- _ports_notifications->prevp = &pn->next;
|
||||
- _ports_notifications = pn;
|
||||
- }
|
||||
+ /* CWE-407 fix (hurd-0002): O(1) hash lookup by port instead of O(N) scan.
|
||||
+ Walk the short per-port chain to find the matching 'what' value. */
|
||||
+ pn = hurd_ihash_find (&_ports_notify_htable, (hurd_ihash_key_t) port);
|
||||
+ {
|
||||
+ struct ports_notify *head = pn;
|
||||
+ while (pn && pn->what != what)
|
||||
+ pn = pn->next;
|
||||
+
|
||||
+ if (! pn)
|
||||
+ /* No existing entry for (PORT, WHAT) — allocate a new one. */
|
||||
+ {
|
||||
+ struct ports_notify *new_pn = _ports_free_ports_notifies;
|
||||
+
|
||||
+ if (new_pn)
|
||||
+ _ports_free_ports_notifies = new_pn->next;
|
||||
+ else
|
||||
+ {
|
||||
+ new_pn = malloc (sizeof (struct ports_notify));
|
||||
+ if (! new_pn)
|
||||
+ /* sigh. Free what we've alloced and return. */
|
||||
+ {
|
||||
+ new_req->next = _ports_free_rpc_notifies;
|
||||
+ _ports_free_rpc_notifies = new_req;
|
||||
+ pthread_mutex_unlock (&_ports_lock);
|
||||
+ return ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ new_pn->reqs = 0;
|
||||
+ new_pn->port = port;
|
||||
+ new_pn->what = what;
|
||||
+ new_pn->pending = 0;
|
||||
+ new_pn->htable_locp = NULL;
|
||||
+ pthread_mutex_init (&new_pn->lock, NULL);
|
||||
+
|
||||
+ if (! head)
|
||||
+ {
|
||||
+ /* First entry for this port — add to the hash table. */
|
||||
+ /* hurd_ihash_add auto-sets new_pn->htable_locp via locp_offset. */
|
||||
+ error_t herr = hurd_ihash_add (&_ports_notify_htable,
|
||||
+ (hurd_ihash_key_t) port, new_pn);
|
||||
+ if (herr)
|
||||
+ {
|
||||
+ new_pn->next = _ports_free_ports_notifies;
|
||||
+ _ports_free_ports_notifies = new_pn;
|
||||
+ new_req->next = _ports_free_rpc_notifies;
|
||||
+ _ports_free_rpc_notifies = new_req;
|
||||
+ pthread_mutex_unlock (&_ports_lock);
|
||||
+ return herr;
|
||||
+ }
|
||||
+ new_pn->next = NULL;
|
||||
+ new_pn->prevp = NULL;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Prepend to the per-port chain after the htable primary entry. */
|
||||
+ new_pn->next = head->next;
|
||||
+ new_pn->prevp = &head->next;
|
||||
+ if (head->next)
|
||||
+ head->next->prevp = &new_pn->next;
|
||||
+ head->next = new_pn;
|
||||
+ }
|
||||
+
|
||||
+ pn = new_pn;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
for (req = rpc->notifies; req; req = req->next)
|
||||
if (req->notify == pn)
|
||||
diff --git a/libports/ports.h b/libports/ports.h
|
||||
index 9299bc40..1b6705e3 100644
|
||||
--- a/libports/ports.h
|
||||
+++ b/libports/ports.h
|
||||
@@ -121,7 +121,10 @@ struct rpc_notify
|
||||
struct rpc_notify **prev_req_p; /* who points to this rpc_notify. */
|
||||
};
|
||||
|
||||
-/* A notification request on a (not necessarily registered) port. */
|
||||
+/* A notification request on a (not necessarily registered) port.
|
||||
+ CWE-407 fix (hurd-0002/0003): entries are now indexed by _ports_notify_htable
|
||||
+ keyed on mach_port_t for O(1) lookup. next/prevp chain entries with the
|
||||
+ same port but different 'what' values (rare; typically only one per port). */
|
||||
struct ports_notify
|
||||
{
|
||||
mach_port_t port; /* */
|
||||
@@ -130,11 +133,18 @@ struct ports_notify
|
||||
pthread_mutex_t lock;
|
||||
|
||||
struct rpc_notify *reqs; /* Which rpcs are notified by this port. */
|
||||
- struct ports_notify *next, **prevp; /* Linked list of all notified ports. */
|
||||
+ /* Per-port chain: entries with the same port but different 'what'. */
|
||||
+ struct ports_notify *next, **prevp;
|
||||
+ /* Hash table location for O(1) removal (only set on the first entry
|
||||
+ for a given port — the one stored directly in the htable). */
|
||||
+ hurd_ihash_locp_t htable_locp;
|
||||
};
|
||||
|
||||
-/* A linked list of ports that have had notification requested. */
|
||||
-extern struct ports_notify *_ports_notifications;
|
||||
+/* Hash table of active notification entries, keyed on mach_port_t.
|
||||
+ CWE-407 fix (hurd-0002/0003): replaces O(N) linked-list scan with O(1)
|
||||
+ port lookup. Multiple entries with the same port (different 'what') are
|
||||
+ chained via ports_notify.next/prevp from the htable's stored entry. */
|
||||
+extern struct hurd_ihash _ports_notify_htable;
|
||||
|
||||
/* Free lists for notify structures. */
|
||||
extern struct ports_notify *_ports_free_ports_notifies;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue