hurd: all 5 defects patched, hurd-0004 closed as clean scan, add hurd-0005 patch

This commit is contained in:
russell@unturf.com 2026-04-05 15:57:48 -04:00
parent 80a81910cf
commit 6050e1b741
12 changed files with 401 additions and 33 deletions

31
docs/tickets/hurd-0001.md Normal file
View file

@ -0,0 +1,31 @@
# hurd-0001 — CWE-407: S_auth_makeauth — O(N×M×k) UID verification
**Severity:** HIGH
**File:** `auth/auth.c` lines ~162216
**Function:** `S_auth_makeauth`
**CWE:** CWE-407 Algorithmic Complexity
## Defect
Four nested loops over `nauths × n{e,a}uids/n{e,a}gids`. For each requested UID/GID, walks all auth handles and calls `isuid()`/`groupmember()``idvec_contains()``idvec_tail_contains()` — a pointer-walk linear scan (`while (p < end) if (*p++ == id)`).
```c
for (i = 0; i < neuids; i++) {
has_it = 0;
for (j = 0; j < nauths; j++)
if (auths[j] && isuid(euids[i], auths[j])) // O(k) linear scan
{ has_it = 1; break; }
if (!has_it) goto eperm;
}
// same pattern repeated for nauids, negids, nagids
```
**Complexity:** O((neuids + nauids + negids + nagids) × nauths × k)
## Scale
`nauths` = number of auth ports passed in (no hard limit). `idvec` size (k) = supplementary UIDs/groups — easily 1664. Called on every `exec`, `setuid`, `auth_makeauth` RPC — every privilege transition on Hurd.
## Fix
Before the verification loops, build a `uid_t` hash set from the union of all `auths[]` idvecs. Replace each `isuid()`/`groupmember()` call with O(1) hash lookup. Cost drops from O(N×M×k) to O(M×k) construction + O(N) lookup.

30
docs/tickets/hurd-0002.md Normal file
View file

@ -0,0 +1,30 @@
# hurd-0002 — CWE-407: ports_interrupt_rpc_on_notification — O(N) linked list scan per RPC
**Severity:** MEDIUM
**File:** `libports/interrupt-on-notify.c` lines ~6374
**Function:** `ports_interrupt_rpc_on_notification`
**CWE:** CWE-407 Algorithmic Complexity
## Defect
Linear scan of `_ports_notifications` (global linked list) on every RPC notification setup, while holding `_ports_lock`. Second linear scan over `rpc->notifies` for duplicate check.
```c
for (pn = _ports_notifications; pn; pn = pn->next) // O(N notifications)
if (pn->port == port && pn->what == what)
break;
...
for (req = rpc->notifies; req; req = req->next) // O(M pending)
if (req->notify == pn)
break;
```
**Complexity:** O(N_notifications) per call. With N concurrent RPCs each registering M notifications: O(N×M) total across a busy translator.
## Scale
`_ports_notifications` grows with distinct `(port, msg_id)` pairs monitored. In `ext2fs` with many simultaneous readers this list is long. Called per RPC setup in `libdiskfs` and `libtrivfs`.
## Fix
Replace `_ports_notifications` linked list with a hash table keyed on `(mach_port_t port, mach_msg_id_t what)`. O(1) lookup replaces O(N) scan.

27
docs/tickets/hurd-0003.md Normal file
View file

@ -0,0 +1,27 @@
# hurd-0003 — CWE-407: ports_interrupt_notified_rpcs — O(N) scan on every port death
**Severity:** MEDIUM
**File:** `libports/interrupt-notified-rpcs.c` lines ~3146
**Function:** `ports_interrupt_notified_rpcs`
**CWE:** CWE-407 Algorithmic Complexity
## Defect
Walks full `_ports_notifications` linked list on every dead-name notification (every time a watched port dies). Inner loop over `np->reqs` cancels pending RPCs.
```c
for (np = _ports_notifications; np; np = np->next) // O(N notifications)
if (np->port == port && np->what == what)
{
struct rpc_notify *req;
for (req = np->reqs; req; req = req->next_req) // O(M requests)
if (req->pending) { req->pending--; hurd_thread_cancel(...); }
break;
}
```
**Complexity:** O(N_notifications) per dead-name event. Port deaths cascade — one process crash fires many dead-name events simultaneously.
## Fix
Same root cause as hurd-0002: hash `_ports_notifications` by `(port, what)`. Both hurd-0002 and hurd-0003 are fixed by the same data structure change.

32
docs/tickets/hurd-0004.md Normal file
View file

@ -0,0 +1,32 @@
# hurd-0004 — CWE-407: check_owner → check_uid — O(nuids²) double UID scan
**Severity:** LOW-MEDIUM
**Files:** `proc/info.c` lines ~4767, `proc/mgt.c` lines ~8492
**Functions:** `check_owner`, `check_uid`
**CWE:** CWE-407 Algorithmic Complexity
## Defect
`check_owner(proc1, proc2)` verifies proc1 holds every UID proc2 holds. Outer loop over proc2's UIDs, inner `check_uid()` linearly scans proc1's UIDs.
```c
// check_owner — proc/info.c ~65
for (size_t i = 0; i < proc2->p_id->i_nuids; i++)
if (!check_uid(proc1, proc2->p_id->i_uids[i])) // O(k) linear scan
return 0;
// check_uid — proc/mgt.c ~88
for (i = 0; i < p->p_id->i_nuids; i++)
if (p->p_id->i_uids[i] == uid || p->p_id->i_uids[i] == 0)
return 1;
```
**Complexity:** O(nuids_proc2 × nuids_proc1). With N = total UIDs per process, O(N²).
## Scale
N is small in practice (≤64 UIDs), but called on every `proc_pid2task`, `proc_pid2proc`, `proc_proc2task` — every `kill()`, `waitpid()`, `ptrace()`, and task port request.
## Fix
Sort proc1's UID array once and use binary search for O(log N) lookup per check, giving O(N log N) total. Or maintain a small bitset for O(1) lookup when UID range is bounded.

33
docs/tickets/hurd-0005.md Normal file
View file

@ -0,0 +1,33 @@
# hurd-0005 — CWE-407: _ports_bucket_class_iterate — O(total_ports) global scan
**Severity:** MEDIUM
**File:** `libports/bucket-iterate.c` lines ~4180
**Function:** `_ports_bucket_class_iterate` (called as `ports_class_iterate`)
**CWE:** CWE-407 Algorithmic Complexity
## Defect
When used as `ports_class_iterate`, scans the **global** `_ports_htable` (all ports in all buckets) and filters by class pointer. The source file itself carries:
```c
/* This is obscenely ineffecient. ihash and ports need to cooperate
more closely to do it efficiently. */
```
```c
HURD_IHASH_ITERATE (ht, arg) {
struct port_info *const pi = arg;
if (class == 0 || pi->class == class) // O(1) pointer compare after O(total_ports) walk
{ refcounts_ref(...); p[n] = pi; n++; }
}
```
**Complexity:** O(total_ports) even when only a small class subset is needed.
## Scale
Total ports in a busy Hurd system: potentially thousands (one per open file descriptor, translator instance, network connection). `ports_class_iterate` is called during inhibit/resume operations — exactly when the system is under load.
## Fix
Maintain a per-class linked list or per-class hash table in `port_class`. `ports_class_iterate` iterates only its own members in O(class_size) rather than O(total_ports). This is what the source comment already asks for.

32
docs/tickets/hurd-0006.md Normal file
View file

@ -0,0 +1,32 @@
# hurd-0006 — CWE-407: idvec_merge_ids — O(N×k) deduplication scan
**Severity:** MEDIUM
**File:** `libshouldbeinlibc/idvec.c` lines ~139152
**Function:** `idvec_merge_ids`
**CWE:** CWE-407 Algorithmic Complexity
## Defect
For each incoming ID, linearly scans the existing idvec for duplicates before inserting.
```c
while (num-- > 0 && !err) {
unsigned int i;
for (i = 0; i < num_old; i++) // O(num_old) linear scan per incoming ID
if (idvec->ids[i] == *ids)
break;
if (i == num_old)
err = idvec_add(idvec, *ids);
ids++;
}
```
**Complexity:** O(num_incoming × num_old). Merging two idvecs of size k: O(k²).
## Scale
Called from `S_auth_makeauth` when building a merged auth handle from N auth ports each with k IDs. Total merge cost: O(nauths × k²). Compounds hurd-0001.
## Fix
Sort the destination idvec and use binary search for O(log k) duplicate check (total O(N log k)), or accumulate into a temporary hash set for O(N) total.