device: capture manager (not Iwd_Device) in reply contexts
A device can be removed (rfkill, hot-unplug, iwd restart) while a Scan/Disconnect/ConnectHiddenNetwork/GetOrderedNetworks call is in flight, after which the reply would dereference a freed Iwd_Device. The manager outlives every sub-object and exposes the network hash needed by GetOrderedNetworks, so pass it directly instead. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
11b21c8fd9
commit
1d4d125a93
1 changed files with 22 additions and 18 deletions
|
|
@ -148,10 +148,15 @@ iwd_device_free(Iwd_Device *d)
|
||||||
|
|
||||||
/* Reply to Station.GetOrderedNetworks: a(on) — list of (object_path, RSSI).
|
/* Reply to Station.GetOrderedNetworks: a(on) — list of (object_path, RSSI).
|
||||||
* RSSI is a 16-bit signed value in 100*dBm units. */
|
* RSSI is a 16-bit signed value in 100*dBm units. */
|
||||||
|
/* Reply callbacks must not hold a raw Iwd_Device back-ref: a device can be
|
||||||
|
* removed (rfkill, hot-unplug, iwd restart) while a call is in flight, and
|
||||||
|
* the reply would then UAF. The manager outlives every sub-object, so we
|
||||||
|
* pass it directly. Network lookups go through the live hash, which is
|
||||||
|
* safe even after the originating device is gone. */
|
||||||
static void
|
static void
|
||||||
_on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
_on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
||||||
{
|
{
|
||||||
Iwd_Device *d = data;
|
Iwd_Manager *m = data;
|
||||||
const char *en, *em;
|
const char *en, *em;
|
||||||
if (eldbus_message_error_get(msg, &en, &em)) return;
|
if (eldbus_message_error_get(msg, &en, &em)) return;
|
||||||
|
|
||||||
|
|
@ -159,7 +164,7 @@ _on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EI
|
||||||
if (!eldbus_message_arguments_get(msg, "a(on)", &array) || !array)
|
if (!eldbus_message_arguments_get(msg, "a(on)", &array) || !array)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const Eina_Hash *nets = d->manager ? iwd_manager_networks(d->manager) : NULL;
|
const Eina_Hash *nets = m ? iwd_manager_networks(m) : NULL;
|
||||||
Eldbus_Message_Iter *entry;
|
Eldbus_Message_Iter *entry;
|
||||||
Eina_Bool any = EINA_FALSE;
|
Eina_Bool any = EINA_FALSE;
|
||||||
while (eldbus_message_iter_get_and_next(array, 'r', &entry))
|
while (eldbus_message_iter_get_and_next(array, 'r', &entry))
|
||||||
|
|
@ -174,7 +179,7 @@ _on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EI
|
||||||
n->have_signal = EINA_TRUE;
|
n->have_signal = EINA_TRUE;
|
||||||
any = EINA_TRUE;
|
any = EINA_TRUE;
|
||||||
}
|
}
|
||||||
if (any && d->manager) iwd_manager_notify(d->manager);
|
if (any && m) iwd_manager_notify(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -182,13 +187,13 @@ _refresh_signals(Iwd_Device *d)
|
||||||
{
|
{
|
||||||
if (!d || !d->station_proxy) return;
|
if (!d || !d->station_proxy) return;
|
||||||
eldbus_proxy_call(d->station_proxy, "GetOrderedNetworks",
|
eldbus_proxy_call(d->station_proxy, "GetOrderedNetworks",
|
||||||
_on_ordered_networks, d, -1, "");
|
_on_ordered_networks, d->manager, -1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_on_scan_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
_on_scan_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
||||||
{
|
{
|
||||||
Iwd_Device *d = data;
|
Iwd_Manager *m = data;
|
||||||
const char *en, *em;
|
const char *en, *em;
|
||||||
if (!eldbus_message_error_get(msg, &en, &em)) return;
|
if (!eldbus_message_error_get(msg, &en, &em)) return;
|
||||||
/* "AlreadyExists" / "InProgress" is the normal race when two scan
|
/* "AlreadyExists" / "InProgress" is the normal race when two scan
|
||||||
|
|
@ -196,38 +201,37 @@ _on_scan_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNU
|
||||||
if (en && (strstr(en, "InProgress") || strstr(en, "Busy") ||
|
if (en && (strstr(en, "InProgress") || strstr(en, "Busy") ||
|
||||||
strstr(en, "AlreadyExists")))
|
strstr(en, "AlreadyExists")))
|
||||||
return;
|
return;
|
||||||
if (d->manager)
|
if (m) iwd_manager_report_error(m, "Scan failed: %s", em ? em : en);
|
||||||
iwd_manager_report_error(d->manager, "Scan failed: %s", em ? em : en);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
iwd_device_scan(Iwd_Device *d)
|
iwd_device_scan(Iwd_Device *d)
|
||||||
{
|
{
|
||||||
if (!d || !d->station_proxy) return;
|
if (!d || !d->station_proxy) return;
|
||||||
eldbus_proxy_call(d->station_proxy, "Scan", _on_scan_reply, d, -1, "");
|
eldbus_proxy_call(d->station_proxy, "Scan", _on_scan_reply, d->manager, -1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_on_disconnect_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
_on_disconnect_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
|
||||||
{
|
{
|
||||||
Iwd_Device *d = data;
|
Iwd_Manager *m = data;
|
||||||
const char *en, *em;
|
const char *en, *em;
|
||||||
if (eldbus_message_error_get(msg, &en, &em) && d->manager)
|
if (eldbus_message_error_get(msg, &en, &em) && m)
|
||||||
iwd_manager_report_error(d->manager,
|
iwd_manager_report_error(m, "Disconnect failed: %s", em ? em : en);
|
||||||
"Disconnect failed: %s", em ? em : en);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
iwd_device_disconnect(Iwd_Device *d)
|
iwd_device_disconnect(Iwd_Device *d)
|
||||||
{
|
{
|
||||||
if (!d || !d->station_proxy) return;
|
if (!d || !d->station_proxy) return;
|
||||||
eldbus_proxy_call(d->station_proxy, "Disconnect", _on_disconnect_reply, d, -1, "");
|
eldbus_proxy_call(d->station_proxy, "Disconnect",
|
||||||
|
_on_disconnect_reply, d->manager, -1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Iwd_Device *d;
|
Iwd_Manager *m;
|
||||||
char *ssid;
|
char *ssid;
|
||||||
} _Connect_Hidden_Ctx;
|
} _Connect_Hidden_Ctx;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -235,8 +239,8 @@ _on_connect_hidden_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *
|
||||||
{
|
{
|
||||||
_Connect_Hidden_Ctx *ctx = data;
|
_Connect_Hidden_Ctx *ctx = data;
|
||||||
const char *en, *em;
|
const char *en, *em;
|
||||||
if (eldbus_message_error_get(msg, &en, &em) && ctx->d->manager)
|
if (eldbus_message_error_get(msg, &en, &em) && ctx->m)
|
||||||
iwd_manager_report_error(ctx->d->manager,
|
iwd_manager_report_error(ctx->m,
|
||||||
"Connect to hidden '%s' failed: %s",
|
"Connect to hidden '%s' failed: %s",
|
||||||
ctx->ssid ? ctx->ssid : "?", em ? em : en);
|
ctx->ssid ? ctx->ssid : "?", em ? em : en);
|
||||||
free(ctx->ssid);
|
free(ctx->ssid);
|
||||||
|
|
@ -249,7 +253,7 @@ iwd_device_connect_hidden(Iwd_Device *d, const char *ssid)
|
||||||
if (!d || !d->station_proxy || !ssid || !*ssid) return;
|
if (!d || !d->station_proxy || !ssid || !*ssid) return;
|
||||||
_Connect_Hidden_Ctx *ctx = calloc(1, sizeof(*ctx));
|
_Connect_Hidden_Ctx *ctx = calloc(1, sizeof(*ctx));
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
ctx->d = d;
|
ctx->m = d->manager;
|
||||||
ctx->ssid = strdup(ssid);
|
ctx->ssid = strdup(ssid);
|
||||||
eldbus_proxy_call(d->station_proxy, "ConnectHiddenNetwork",
|
eldbus_proxy_call(d->station_proxy, "ConnectHiddenNetwork",
|
||||||
_on_connect_hidden_reply, ctx, -1, "s", ssid);
|
_on_connect_hidden_reply, ctx, -1, "s", ssid);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue