From 831abecd6a3f7296f54de2492d33dbc4b60bc657 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 25 Oct 2014 12:23:37 +0200 Subject: [PATCH] kernel: Fix unbalanced release of sync object in FD select race. When a file descriptor is closed between being selected and adding the select info to its IO context, the select info needs to be cleaned up. This is done by deselect_select_infos() which unconditionally also put the select_sync associated with the infos. In this special case we do not yet hold a reference to the select_sync however, so avoid putting the corresponding sync object. Fixes #11098, #10763 and #10230. --- src/system/kernel/fs/fd.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index 1b1bcc451a..18292f0222 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -41,7 +41,7 @@ static struct file_descriptor* get_fd_locked(struct io_context* context, int fd); static struct file_descriptor* remove_fd(struct io_context* context, int fd); static void deselect_select_infos(file_descriptor* descriptor, - select_info* infos); + select_info* infos, bool putSyncObjects); struct FDGetterLocking { @@ -367,7 +367,7 @@ remove_fd(struct io_context* context, int fd) mutex_unlock(&context->io_mutex); if (selectInfos != NULL) - deselect_select_infos(descriptor, selectInfos); + deselect_select_infos(descriptor, selectInfos, true); return disconnected ? NULL : descriptor; } @@ -457,7 +457,7 @@ dup2_fd(int oldfd, int newfd, bool kernel) // Say bye bye to the evicted fd if (evicted) { - deselect_select_infos(evicted, selectInfos); + deselect_select_infos(evicted, selectInfos, true); close_fd(evicted); put_fd(evicted); } @@ -525,7 +525,8 @@ fd_ioctl(bool kernelFD, int fd, uint32 op, void* buffer, size_t length) static void -deselect_select_infos(file_descriptor* descriptor, select_info* infos) +deselect_select_infos(file_descriptor* descriptor, select_info* infos, + bool putSyncObjects) { TRACE(("deselect_select_infos(%p, %p)\n", descriptor, infos)); @@ -546,7 +547,9 @@ deselect_select_infos(file_descriptor* descriptor, select_info* infos) notify_select_events(info, B_EVENT_INVALID); info = info->next; - put_select_sync(sync); + + if (putSyncObjects) + put_select_sync(sync); } } @@ -601,7 +604,7 @@ select_fd(int32 fd, struct select_info* info, bool kernel) // Someone close()d the index in the meantime. deselect() all // events. info->next = NULL; - deselect_select_infos(descriptor, info); + deselect_select_infos(descriptor, info, false); // Release our open reference of the descriptor. close_fd(descriptor);