Skip to content

Commit 5679a32

Browse files
round4: candidates 1-4 are fork drafts #18-#21
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8874ee0 commit 5679a32

1 file changed

Lines changed: 9 additions & 4 deletions

File tree

‎analysis-reports/round4/candidates.md‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ The rules are those in [`../pr-tracker.md`](../pr-tracker.md#what-the-maintainer
1414
In-flight upstream work to avoid duplicating: #133 (CI), #134 (strip.py), #135
1515
(`homa_rpc_alloc_server` `waiting_for_bufs`), #136 (`homa_sock_destroy` shutdown).
1616

17+
**Status (2026-10-28):** 1–4 are fork drafts #18–#21. Each was done test-first: the
18+
new test failed on `main`, then passed with the fix. The full unit suite is 885/885 in
19+
both IPv6 and `--ipv4` modes, `homa.ko` compiles with and without `__STRIP__` on 7.3,
20+
and checkpatch is clean.
21+
1722
## Batch (8)
1823

1924
| # | Branch (proposed) | Where | Bug | Reach | Test | Confidence |
2025
|---|---|---|---|---|---|---|
21-
| 1 | `fix/qdisc-bypass-ipv6-hash` | `homa_qdisc.c` `homa_qdisc_can_bypass` | The IPv6 daddr hash for `skb` XORs words `[0]^[2]^[3]`; the loop over deferred packets uses `[0]^[1]^[2]^[3]`. For any address with a non-zero word 1 they never match, so a TCP packet bypasses deferred packets of the **same flow** and gets reordered. The existing test uses IPv4-mapped addresses (word 1 = 0), which hides it | any IPv6 TCP traffic through the Homa qdisc | yes: `homa_qdisc_can_bypass__ipv6_address_uses_all_words` (real v6 address) | high (verified) |
22-
| 2 | `fix/hijack-gro-ipv6-tcp` | `homa_hijack.c` `homa_hijack_gro_receive` | Non-hijacked packets always go to `tcp_net_offload` (IPv4) `gro_receive`, even when they arrived through `hook_tcp6_net_offload`. `tcp6_net_offload` is saved but never used. IPv6 TCP packets go through `tcp4_gro_receive`, which reads the v6 header as an `iphdr` (pseudo-header checksum, fraglist lookup) | every IPv6 TCP packet once homa is loaded (`homa_hijack_init` runs at load) | yes: an IPv6 pass-through test expecting `unit_tcp6_gro_receive` (the fixture already installs it) | high (verified) |
23-
| 3 | `fix/rpc-get-info-private-flag` | `homa_rpc.c` `homa_rpc_get_info` | `rpc->flags & RPC_PRIVATE`, but `RPC_PRIVATE` is a **bit number** (2), so this tests bit 1, `APP_NEEDS_LOCK`. HOMAIOCINFO misreports `HOMA_RPC_PRIVATE`. The existing test sets `flags \|= RPC_PRIVATE`, which hides it | any HOMAIOCINFO caller | fix the existing test to `set_bit(RPC_PRIVATE, ...)` (red before the fix) | high (verified) |
24-
| 4 | `fix/qdisc-destroy-next-qdisc` | `homa_qdisc.c` `homa_qdisc_destroy` | `list_del_init(&q->defer_links)` leaves the round-robin cursor `qdev->next_qdisc` able to point at `q`, and the pacer then does `list_entry(next_qdisc)` on the freed qdisc. **Use-after-free.** Fix: advance the cursor before the unlink, under the qdev lock already held | `tc qdisc replace` or delete of one queue while TCP is deferred on others | yes: defer on q1/q2/q3, cursor at q2, destroy q2, the pacer sends from q3 | high (verified) |
26+
| 1 | `fix/qdisc-bypass-ipv6-hash` (fork #18) | `homa_qdisc.c` `homa_qdisc_can_bypass` | The IPv6 daddr hash for `skb` XORs words `[0]^[2]^[3]`; the loop over deferred packets uses `[0]^[1]^[2]^[3]`. For any address with a non-zero word 1 they never match, so a TCP packet bypasses deferred packets of the **same flow** and gets reordered. The existing test uses IPv4-mapped addresses (word 1 = 0), which hides it | any IPv6 TCP traffic through the Homa qdisc | yes: `homa_qdisc_can_bypass__ipv6_address_uses_all_words` (real v6 address) | high (verified) |
27+
| 2 | `fix/hijack-gro-ipv6-tcp` (fork #19) | `homa_hijack.c` `homa_hijack_gro_receive` | Non-hijacked packets always go to `tcp_net_offload` (IPv4) `gro_receive`, even when they arrived through `hook_tcp6_net_offload`. `tcp6_net_offload` is saved but never used. IPv6 TCP packets go through `tcp4_gro_receive`, which reads the v6 header as an `iphdr` (pseudo-header checksum, fraglist lookup) | every IPv6 TCP packet once homa is loaded (`homa_hijack_init` runs at load) | yes: an IPv6 pass-through test expecting `unit_tcp6_gro_receive` (the fixture already installs it) | high (verified) |
28+
| 3 | `fix/rpc-get-info-private-flag` (fork #20) | `homa_rpc.c` `homa_rpc_get_info` | `rpc->flags & RPC_PRIVATE`, but `RPC_PRIVATE` is a **bit number** (2), so this tests bit 1, `APP_NEEDS_LOCK`. HOMAIOCINFO misreports `HOMA_RPC_PRIVATE`. The existing test sets `flags \|= RPC_PRIVATE`, which hides it | any HOMAIOCINFO caller | fix the existing test to `set_bit(RPC_PRIVATE, ...)` (red before the fix) | high (verified) |
29+
| 4 | `fix/qdisc-destroy-next-qdisc` (fork #21) | `homa_qdisc.c` `homa_qdisc_destroy` | `list_del_init(&q->defer_links)` leaves the round-robin cursor `qdev->next_qdisc` able to point at `q`, and the pacer then does `list_entry(next_qdisc)` on the freed qdisc. **Use-after-free.** Fix: advance the cursor before the unlink, under the qdev lock already held | `tc qdisc replace` or delete of one queue while TCP is deferred on others | yes: defer on q1/q2/q3, cursor at q2, destroy q2, the pacer sends from q3 | high (verified) |
2530
| 5 | `fix/qdisc-unknown-link-speed` | `homa_qdisc.c` `homa_qdev_update_sysctl` | `get_link_ksettings` succeeds with `speed = SPEED_UNKNOWN` (-1), as on virtio-net or a link that is down. Then `link_mbps = -1`, `max_nic_queue_bytes < 0`, and everything is deferred and never sent. Speed 0 gives `do_div(tmp, 0)`. Fix: keep `homa->link_mbps` unless the speed is valid | Homa qdisc on virtio or a link that is down | yes: copy `__cant_get_link_speed_from_dev` with `mock_link_mbps = SPEED_UNKNOWN` | high |
2631
| 6 | `fix/qdisc-destroy-after-init-failure` | `homa_qdisc.c` `homa_qdisc_destroy` | The kernel calls `ops->destroy` even when `ops->init` fails (`qdisc_create`). If `homa_qdisc_qdev_get` failed, `q->qdev` is NULL and destroy oopses. Fix: `if (!q->qdev) return;` | an allocation or kthread failure while attaching the qdisc | yes: extend `homa_qdisc_init__cant_create_new_qdisc_dev` | high correctness, low impact |
2732
| 7 | `fix/softirq-cores-bounds` | `homa_plumbing.c` `homa_sysctl_softirq_cores`, `homa_offload.c` `homa_offload_init` | The sysctl checks `core >= nr_cpu_ids` but not negatives. The default `gen3_softirq_cores[0] = i ^ 1` equals `nr_cpu_ids` on the last CPU when the CPU count is odd. Both reach `per_cpu(homa_offload_core, core)` out of bounds under GEN3 | root sysctl; GEN3 gro_policy on an odd CPU count | yes for the sysctl rejection | high bug; needs root or non-default policy |

0 commit comments

Comments
 (0)