summaryrefslogtreecommitdiff
path: root/main/channel.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-02-13 11:05:51 +0000
committerJoshua Colp <jcolp@digium.com>2017-02-13 05:09:30 -0600
commit89871576b943058b65a7bfbe9df59fbe75f982dd (patch)
treed829716060f8bb8c88453a767171feadcc76598e /main/channel.c
parent648d181d2fb62284eb7a2284221b48240a0e876e (diff)
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
Diffstat (limited to 'main/channel.c')
-rw-r--r--main/channel.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/main/channel.c b/main/channel.c
index 234919336..2890cf000 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;