DF-3762 / trigger.c
/* * DF-3762 trigger — logic replication of the unchecked-PHY-read defect in * sys/dev/netif/ig_hal/e1000_phy.c:e1000_link_stall_workaround_hv() (line 3848). * * The real function does: * * u16 data; // uninit (line 3840) * hw->phy.ops.read_reg(hw, PHY_CONTROL, &data); // return IGNORED (3848) * if (data & PHY_CONTROL_LB) // uninit read (3849) * return E1000_SUCCESS; * * When read_reg fails (e1000_read_phy_reg_hv -> e1000_read_phy_reg_mdic * MDIC timeout/error: -E1000_ERR_PHY), it returns WITHOUT writing *data. * The caller then branches on uninitialized kernel stack. * * This harness replicates the exact call/decision structure with an * instrumented shim so the defect is provable on any machine, no e1000 * hardware needed (the guest is virtio-only: no em/emx/igb NIC present, * so the in-kernel path cannot be executed there). * * Build: cc -O2 -o trigger trigger.c * Run: ./trigger * Success criterion: prints "decision on UNINITIALIZED data" and exits 1. */ #include <stdio.h> #include <stdint.h> #include <stdbool.h> typedef int32_t s32; typedef uint16_t u16; #define E1000_SUCCESS 0 #define E1000_ERR_PHY 2 #define PHY_CONTROL_LB (1 << 14) /* instrumented stand-in for e1000_read_phy_reg_mdic() failure path */ static bool shim_wrote_data; static s32 read_reg_fails(int reg_offset, u16 *data) { (void)reg_offset; /* failure: returns error WITHOUT touching *data — exactly like * e1000_read_phy_reg_mdic() lines 322-335 of e1000_phy.c */ shim_wrote_data = false; return -E1000_ERR_PHY; } /* verbatim decision structure of e1000_link_stall_workaround_hv() */ static s32 link_stall_workaround_hv(u16 *stack_probe) { u16 data; /* line 3840: uninitialized */ s32 ret_val = E1000_SUCCESS; shim_wrote_data = true; /* will be cleared by the failing read */ read_reg_fails(0, &data); /* line 3848: return value dropped */ *stack_probe = data; /* observe what the branch below sees */ if (data & PHY_CONTROL_LB) /* line 3849: decision on garbage */ return E1000_SUCCESS; /* ... 200ms stall + PHY register writes follow in the real code ... */ return ret_val; } int main(void) { u16 observed = 0xA5A5; /* sentinel: differs from any legit probe */ s32 r = link_stall_workaround_hv(&observed); printf("read_reg wrote *data: %s\n", shim_wrote_data ? "yes" : "NO (failed)"); printf("branch observed data: 0x%04x\n", observed); if (!shim_wrote_data) { printf("decision on UNINITIALIZED data: loopback-check branched on 0x%04x\n", observed); printf("DEFECT CONFIRMED (logic replication; hardware path requires e1000 NIC)\n"); return 1; } (void)r; return 0; } |