poll: fix thread_cancel() caused poll used after free

pthread 0          pthread1
fd 0
poll_setup
wait
                   cancel(thread 0)
                   fd 0 close
                   fd 0 notify (sem used after free)
poll_teardown

Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
ligd 2024-02-05 22:55:13 +08:00 committed by Xiang Xiao
parent ff1b54bff3
commit fab9369093

View File

@ -35,11 +35,22 @@
#include <nuttx/cancelpt.h>
#include <nuttx/fs/fs.h>
#include <nuttx/net/net.h>
#include <nuttx/tls.h>
#include <arch/irq.h>
#include "inode/inode.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct pollfd_s
{
FAR struct pollfd *fds;
nfds_t nfds;
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -160,6 +171,22 @@ static inline int poll_teardown(FAR struct pollfd *fds, nfds_t nfds,
return ret;
}
/****************************************************************************
* Name: poll_cleanup
*
* Description:
* Setup the poll operation for each descriptor in the list.
*
****************************************************************************/
static void poll_cleanup(FAR void *arg)
{
FAR struct pollfd_s *fdsinfo = (FAR struct pollfd_s *)arg;
int count;
poll_teardown(fdsinfo->fds, fdsinfo->nfds, &count, OK);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -414,10 +441,22 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
kfds = fds;
#endif
/* Set up the poll structure */
nxsem_init(&sem, 0, 0);
ret = poll_setup(kfds, nfds, &sem);
if (ret >= 0)
{
struct pollfd_s fdsinfo;
/* Push a cancellation point onto the stack. This will be called if
* the thread is canceled.
*/
fdsinfo.fds = kfds;
fdsinfo.nfds = nfds;
tls_cleanup_push(tls_get_info(), poll_cleanup, &fdsinfo);
if (timeout == 0)
{
/* Poll returns immediately whether we have a poll event or not. */
@ -474,6 +513,10 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
{
ret = ret2;
}
/* Pop the cancellation point */
tls_cleanup_pop(tls_get_info(), 0);
}
nxsem_destroy(&sem);