aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Willmann <dwillmann@sysmocom.de>2014-06-10 10:02:24 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-06-22 16:40:59 +0200
commitbd8a89debc48bb6696c58a346b463d8df18febb2 (patch)
treed5acb3d829b04de4aa978b294071d6f9e0ec06b1 /src
parent92107dfd3b99ab0dbb0f4770286454ad94a36de2 (diff)
write_queue: Avoid possible use-after-free if fd is read-/writable
If the FD is both readable and writable and the read callback closes the connection (and frees the surrounding structure) we shouldn't call the write callback (or check anything else in the read fd). With this patch callback functions can return -EBADFD if they don't want the FD to be handled any more.
Diffstat (limited to 'src')
-rw-r--r--src/write_queue.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/write_queue.c b/src/write_queue.c
index cef40f83..80e6c42e 100644
--- a/src/write_queue.c
+++ b/src/write_queue.c
@@ -21,6 +21,7 @@
*
*/
+#include <errno.h>
#include <osmocom/core/write_queue.h>
/*! \addtogroup write_queue
@@ -39,14 +40,21 @@
int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what)
{
struct osmo_wqueue *queue;
+ int rc;
queue = container_of(fd, struct osmo_wqueue, bfd);
- if (what & BSC_FD_READ)
- queue->read_cb(fd);
+ if (what & BSC_FD_READ) {
+ rc = queue->read_cb(fd);
+ if (rc == -EBADFD)
+ goto err_badfd;
+ }
- if (what & BSC_FD_EXCEPT)
- queue->except_cb(fd);
+ if (what & BSC_FD_EXCEPT) {
+ rc = queue->except_cb(fd);
+ if (rc == -EBADFD)
+ goto err_badfd;
+ }
if (what & BSC_FD_WRITE) {
struct msgb *msg;
@@ -58,14 +66,19 @@ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what)
--queue->current_length;
msg = msgb_dequeue(&queue->msg_queue);
- queue->write_cb(fd, msg);
+ rc = queue->write_cb(fd, msg);
msgb_free(msg);
+ if (rc == -EBADFD)
+ goto err_badfd;
+
if (!llist_empty(&queue->msg_queue))
fd->when |= BSC_FD_WRITE;
}
}
+err_badfd:
+ /* Return value is not checked in osmo_select_main() */
return 0;
}