Skip to content

WiFi: fix dangling pointer in setHostname / softAPsetHostname - #412

Open
tomasgvivo wants to merge 1 commit into
libretiny-eu:masterfrom
tomasgvivo:fix/hostname-dangling-pointer
Open

tomasgvivo wants to merge 1 commit into
libretiny-eu:masterfrom
tomasgvivo:fix/hostname-dangling-pointer

Conversation

@tomasgvivo

Copy link
Copy Markdown

netif_set_hostname() assigns the pointer it is given — it does not copy:

#define netif_set_hostname(netif, name) \
    do { if((netif) != NULL) { (netif)->hostname = name; }} while(0)

Every WiFiClass hostname setter passes the caller's pointer straight through,
so netif->hostname ends up aliasing memory the caller owns. Callers can't
reasonably satisfy that contract, and the convenience overload actively
violates it:

inline bool hostname(const String &aHostname) {
    return setHostname(aHostname.c_str());
}

That takes .c_str() of a String temporary, destroyed on return. So
WiFi.hostname("my-device") leaves netif->hostname dangling. The name is read
much later, when DHCP builds option 12 — by which point the memory has been
reused, and the device advertises whatever now occupies it.

Observed

On an RTL8720CF (realtek-amb), a device calling WiFi.hostname() advertised
its own WiFi SSID as the DHCP hostname, visible in the router's lease table.
The SSID string had landed in the freed block. Being a use-after-free the
symptom varies with heap state — a stack buffer, or a String member later
reassigned, fails the same way but may look fine for a while. setHostname()
returns true regardless, so nothing signals a problem.

Fix

Store the hostname in fixed storage owned by WiFiClass and hand lwIP a pointer
to that. Separate STA and AP buffers, since both netifs can be up at once.

Affects all three cores with a WiFi implementation — realtek-amb,
beken-72xx, lightning-ln882h — STA and AP in each, six call sites.

Testing

Verified on hardware for realtek-amb only (RTL8720CF, Broadlink RM4 mini),
which is the only device I have. Before the fix the DHCP lease showed the SSID;
after it, with the firmware deliberately calling the previously-dangling
hostname(const String &) overload and nothing else changed, the lease shows
the intended name:

00:E0:4C:B7:23:00   192.168.30.189   rm4mini-b72300

Compile-tested through both setHostname(const char *) and
hostname(const String &).

beken-72xx and lightning-ln882h are unverified — I have no hardware for
either. Those changes are mechanically identical to the Realtek one, but I'd
appreciate a second pair of eyes, or a test from someone with the hardware,
before they're trusted.

Note

LT_HOSTNAME_SIZE is 64 (63-octet practical DNS label limit plus NUL). Longer
names are truncated rather than rejected; happy to change that if you'd prefer
an explicit failure. I also kept the fix inside the existing per-core
setHostname() implementations rather than restructuring — let me know if
you'd rather it lived somewhere else.

netif_set_hostname() assigns the pointer it is given -- it does not copy:

    #define netif_set_hostname(netif, name) \
        do { if((netif) != NULL) { (netif)->hostname = name; }} while(0)

Every WiFiClass hostname setter passed the caller's pointer straight through,
so netif->hostname was left aliasing memory the caller owns. Callers cannot
reasonably satisfy that contract, and the convenience overload actively
violates it:

    inline bool hostname(const String &aHostname) {
        return setHostname(aHostname.c_str());
    }

That takes .c_str() of a String temporary which is destroyed on return, so
WiFi.hostname("my-device") leaves netif->hostname dangling. The name is read
later, when DHCP builds option 12, by which point the memory has been reused --
so the device advertises whatever now occupies it. Observed in the field on
realtek-amb (RTL8720CF): a device calling WiFi.hostname() advertised the WiFi
SSID as its DHCP hostname, because the SSID string had landed in the freed
block. It is a use-after-free, so the symptom varies with heap state; a stack
buffer or a String member that is later reassigned fails the same way.

Store the hostname in fixed storage owned by WiFiClass instead, and hand lwIP
a pointer to that. Separate STA and AP buffers, since both netifs can be up at
once. Affects all three cores with a WiFi implementation:

    realtek-amb, beken-72xx, lightning-ln882h

Compile-tested on realtek-amb (RTL8720CF) via both setHostname(const char *)
and hostname(const String &).

Signed-off-by: Tomas Gonzalez Vivo <1284744+tomasgvivo@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant