]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
channel: Protect flags in ast_waitfor_nandfds operation. 31/4931/1
authorJoshua Colp <jcolp@digium.com>
Mon, 13 Feb 2017 11:05:51 +0000 (11:05 +0000)
committerJoshua Colp <jcolp@digium.com>
Mon, 13 Feb 2017 11:09:22 +0000 (05:09 -0600)
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

index 92763f9113a468e31720a3221f165ea4a1b394d2..ac3e960a1f1ec6498097243069aa447b29331b13 100644 (file)
@@ -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;