Skip to content

Commit 23d786d

Browse files
whitslackrustyrussell
authored andcommitted
connectd: avoid use-after-free upon multiple reconnections by a peer
`peer_reconnected` was freeing a `struct peer_reconnected` instance while a pointer to that instance was registered to be passed as an argument to the `retry_peer_connected` callback function. This caused a use-after-free crash when `retry_peer_connected` attempted to reparent the instance to the temporary context. Instead, never have `peer_reconnected` free a `struct peer_reconnected` instance, and only ever allow such an instance to be freed after the `retry_peer_connected` callback has finished with it. To ensure that the instance is freed even if the connection is closed before the callback can be invoked, parent the instance to the connection rather than to the daemon. Absent the need to free `struct peer_reconnected` instances outside of the `retry_peer_connected` callback, there is no use for the `reconnected` hashtable, so remove it as well. See: #5282 (comment) Fixes: #5282 Fixes: #5284 Changelog-Fixed: connectd no longer crashes when peers reconnect.
1 parent e46b0ff commit 23d786d

File tree

2 files changed

+13
-52
lines changed

2 files changed

+13
-52
lines changed

connectd/connectd.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ struct connecting {
9393
u32 seconds_waited;
9494
};
9595

96+
/*~ This is an ad-hoc marshalling structure where we store arguments so we
97+
* can call peer_connected again. */
98+
struct peer_reconnected {
99+
struct daemon *daemon;
100+
struct node_id id;
101+
struct wireaddr_internal addr;
102+
const struct wireaddr *remote_addr;
103+
struct crypto_state cs;
104+
const u8 *their_features;
105+
bool incoming;
106+
};
107+
96108
/*~ C programs should generally be written bottom-to-top, with the root
97109
* function at the bottom, and functions it calls above it. That avoids
98110
* us having to pre-declare functions; but in the case of mutual recursion
@@ -231,12 +243,6 @@ static struct io_plan *retry_peer_connected(struct io_conn *conn,
231243
true);
232244
}
233245

234-
/*~ A common use for destructors is to remove themselves from a data structure */
235-
static void destroy_peer_reconnected(struct peer_reconnected *pr)
236-
{
237-
peer_reconnected_htable_del(&pr->daemon->reconnected, pr);
238-
}
239-
240246
/*~ If we already know about this peer, we tell lightningd and it disconnects
241247
* the old one. We wait until it tells us that's happened. */
242248
static struct io_plan *peer_reconnected(struct io_conn *conn,
@@ -253,27 +259,18 @@ static struct io_plan *peer_reconnected(struct io_conn *conn,
253259

254260
status_peer_debug(id, "reconnect");
255261

256-
/* If we have a previous reconnection, we replace it. */
257-
pr = peer_reconnected_htable_get(&daemon->reconnected, id);
258-
if (pr) {
259-
peer_reconnected_htable_del(&daemon->reconnected, pr);
260-
tal_free(pr);
261-
}
262-
263262
/* Tell master to kill it: will send peer_disconnect */
264263
msg = towire_connectd_reconnected(NULL, id);
265264
daemon_conn_send(daemon->master, take(msg));
266265

267266
/* Save arguments for next time. */
268-
pr = tal(daemon, struct peer_reconnected);
267+
pr = tal(conn, struct peer_reconnected);
269268
pr->daemon = daemon;
270269
pr->id = *id;
271270
pr->cs = *cs;
272271
pr->addr = *addr;
273272
pr->remote_addr = tal_dup_or_null(pr, struct wireaddr, remote_addr);
274273
pr->incoming = incoming;
275-
peer_reconnected_htable_add(&daemon->reconnected, pr);
276-
tal_add_destructor(pr, destroy_peer_reconnected);
277274

278275
/*~ Note that tal_dup_talarr() will do handle the take() of features
279276
* (turning it into a simply tal_steal() in those cases). */
@@ -1989,7 +1986,6 @@ static void dev_connect_memleak(struct daemon *daemon, const u8 *msg)
19891986
/* Now delete daemon and those which it has pointers to. */
19901987
memleak_remove_region(memtable, daemon, sizeof(daemon));
19911988
memleak_remove_htable(memtable, &daemon->peers.raw);
1992-
memleak_remove_htable(memtable, &daemon->reconnected.raw);
19931989

19941990
found_leak = dump_memleak(memtable, memleak_status_broken);
19951991
daemon_conn_send(daemon->master,
@@ -2136,7 +2132,6 @@ int main(int argc, char *argv[])
21362132
/* Allocate and set up our simple top-level structure. */
21372133
daemon = tal(NULL, struct daemon);
21382134
peer_htable_init(&daemon->peers);
2139-
peer_reconnected_htable_init(&daemon->reconnected);
21402135
memleak_add_helper(daemon, memleak_daemon_cb);
21412136
list_head_init(&daemon->connecting);
21422137
timers_init(&daemon->timers, time_mono());

connectd/connectd.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -126,37 +126,6 @@ HTABLE_DEFINE_TYPE(struct peer,
126126
peer_eq_node_id,
127127
peer_htable);
128128

129-
/*~ This is an ad-hoc marshalling structure where we store arguments so we
130-
* can call peer_connected again. */
131-
struct peer_reconnected {
132-
struct daemon *daemon;
133-
struct node_id id;
134-
struct wireaddr_internal addr;
135-
const struct wireaddr *remote_addr;
136-
struct crypto_state cs;
137-
const u8 *their_features;
138-
bool incoming;
139-
};
140-
141-
static const struct node_id *
142-
peer_reconnected_keyof(const struct peer_reconnected *pr)
143-
{
144-
return &pr->id;
145-
}
146-
147-
static bool peer_reconnected_eq_node_id(const struct peer_reconnected *pr,
148-
const struct node_id *id)
149-
{
150-
return node_id_eq(&pr->id, id);
151-
}
152-
153-
/*~ This defines 'struct peer_reconnected_htable'. */
154-
HTABLE_DEFINE_TYPE(struct peer_reconnected,
155-
peer_reconnected_keyof,
156-
node_id_hash,
157-
peer_reconnected_eq_node_id,
158-
peer_reconnected_htable);
159-
160129
/*~ This is the global state, like `struct lightningd *ld` in lightningd. */
161130
struct daemon {
162131
/* Who am I? */
@@ -173,9 +142,6 @@ struct daemon {
173142
* have disconnected. */
174143
struct peer_htable peers;
175144

176-
/* Peers which have reconnected, waiting for us to kill existing conns */
177-
struct peer_reconnected_htable reconnected;
178-
179145
/* Peers we are trying to reach */
180146
struct list_head connecting;
181147

0 commit comments

Comments
 (0)