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.
diff --git a/src/write_queue.c b/src/write_queue.c
index cef40f8..80e6c42 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 @@
 			--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;
 }