osmo_io: Avoid potential double free when sending msgb

Ensure that a msgb  has the proper talloc parent:

All msgbs inside an iofd get the iofd as parent. Received msgbs are reparented
to iofd->msgb_alloc.ctx (which was set in osmo_iofd_setup()) before
being passed to the receive callback.

Before this change the code could fail for msgbs that are submitted via uring
where the (failed) write returns after the iofd has already been
osmo_iofd_free()d. free()ing the iofd is deferred until the write
completes, but the (iofd) parent context could have been free()d in the
meantime.

Change-Id: I3a279b55a3adff96948120683c844e1508d0ba94
This commit is contained in:
Daniel Willmann 2023-08-10 10:47:25 +02:00
parent 2b34e92d0e
commit 012d9044a2
1 changed files with 15 additions and 8 deletions

View File

@ -93,17 +93,23 @@ static __attribute__((constructor(103))) void on_dso_load_osmo_io(void)
* \returns the newly allocated msghdr or NULL in case of error */
struct iofd_msghdr *iofd_msghdr_alloc(struct osmo_io_fd *iofd, enum iofd_msg_action action, struct msgb *msg)
{
struct iofd_msghdr *hdr = talloc_zero(iofd, struct iofd_msghdr);
if (!hdr)
return NULL;
bool free_msg = false;
struct iofd_msghdr *hdr;
if (!msg) {
msg = iofd_msgb_alloc(iofd);
if (!msg) {
talloc_free(hdr);
if (!msg)
return NULL;
}
free_msg = true;
} else {
talloc_steal(iofd->msgb_alloc.ctx, msg);
talloc_steal(iofd, msg);
}
hdr = talloc_zero(msg, struct iofd_msghdr);
if (!hdr) {
if (free_msg)
talloc_free(msg);
return NULL;
}
hdr->action = action;
@ -129,7 +135,7 @@ struct msgb *iofd_msgb_alloc(struct osmo_io_fd *iofd)
uint16_t headroom = iofd->msgb_alloc.headroom;
OSMO_ASSERT(iofd->msgb_alloc.size < 0xffff - headroom);
return msgb_alloc_headroom_c(iofd->msgb_alloc.ctx,
return msgb_alloc_headroom_c(iofd,
iofd->msgb_alloc.size + headroom, headroom,
iofd->name ? : "iofd_msgb");
}
@ -304,6 +310,7 @@ void iofd_handle_segmented_read(struct osmo_io_fd *iofd, struct msgb *msg, int r
void iofd_handle_recv(struct osmo_io_fd *iofd, struct msgb *msg, int rc, struct iofd_msghdr *hdr)
{
talloc_steal(iofd->msgb_alloc.ctx, msg);
switch (iofd->mode) {
case OSMO_IO_FD_MODE_READ_WRITE:
iofd_handle_segmented_read(iofd, msg, rc);