From 89871576b943058b65a7bfbe9df59fbe75f982dd Mon Sep 17 00:00:00 2001
From: Joshua Colp <jcolp@digium.com>
Date: Mon, 13 Feb 2017 11:05:51 +0000
Subject: [PATCH] channel: Protect flags in ast_waitfor_nandfds operation.

The ast_waitfor_nandfds operation will manipulate the flags
of channels passed in. This was previously done without
the channel lock being held. This could result in incorrect
values existing for the flags if another thread manipulated
the flags at the same time.

This change locks the channel during flag manipulation.

ASTERISK-26788

Change-Id: I2c5c8edec17c9bdad4a93291576838cb552ca5ed
---
 main/channel.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/main/channel.c b/main/channel.c
index 2349193365..2890cf0001 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3130,7 +3130,9 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 			fdmap[max].chan = x;  /* channel x is linked to this pfds */
 			max += ast_add_fd(&pfds[max], ast_channel_fd(c[x], y));
 		}
+		ast_channel_lock(c[x]);
 		CHECK_BLOCKING(c[x]);
+		ast_channel_unlock(c[x]);
 	}
 	/* Add the individual fds */
 	for (x = 0; x < nfds; x++) {
@@ -3157,7 +3159,9 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		res = ast_poll(pfds, max, rms);
 	}
 	for (x = 0; x < n; x++) {
+		ast_channel_lock(c[x]);
 		ast_clear_flag(ast_channel_flags(c[x]), AST_FLAG_BLOCKING);
+		ast_channel_unlock(c[x]);
 	}
 	if (res < 0) { /* Simulate a timeout if we were interrupted */
 		if (errno != EINTR) {
@@ -3193,12 +3197,14 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		}
 		if (fdmap[x].chan >= 0) {	/* this is a channel */
 			winner = c[fdmap[x].chan];	/* override previous winners */
+			ast_channel_lock(winner);
 			if (res & POLLPRI) {
 				ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
 			} else {
 				ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
 			}
 			ast_channel_fdno_set(winner, fdmap[x].fdno);
+			ast_channel_unlock(winner);
 		} else {			/* this is an fd */
 			if (outfd) {
 				*outfd = pfds[x].fd;
-- 
GitLab