libs/libc/aio/lio_listio: fix the heap use-after-free bug

1. the lio_sigsetup() method use a universal sighand instance across all
aiocb instances, but inside the lio_sighandler() method, if one aiocb is
handle finished, then this method will free the sighand instance that
come along with current aiocb instance. thus when handle next aiocb
instance, use-after-free crash will happen. in order to solve this
problem, we make each aiocb instance have their own sighand instance
2. make the lio_listio implementation can pass the
ltp/open_posix_testsuite/lio_listio testcases
3. the modification are referred to https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html

Signed-off-by: guoshichao <guoshichao@xiaomi.com>
This commit is contained in:
guoshichao 2023-06-19 17:52:39 +08:00 committed by Xiang Xiao
parent 0dba857028
commit 9efa398c69

View file

@ -215,55 +215,25 @@ static int lio_sigsetup(FAR struct aiocb * const *list, int nent,
FAR struct sigevent *sig)
{
FAR struct aiocb *aiocbp;
FAR struct lio_sighand_s *sighand;
struct lio_sighand_s sighand;
sigset_t set;
struct sigaction act;
int status;
int i;
/* Allocate a structure to pass data to the signal handler */
sighand = lib_zalloc(sizeof(struct lio_sighand_s));
if (!sighand)
{
ferr("ERROR: lib_zalloc failed\n");
return -ENOMEM;
}
/* Initialize the allocated structure */
sighand->list = list;
sighand->sig = *sig;
sighand->nent = nent;
sighand->pid = _SCHED_GETPID();
/* Save this structure as the private data attached to each aiocb */
for (i = 0; i < nent; i++)
{
/* Skip over NULL entries in the list */
aiocbp = list[i];
if (aiocbp)
{
FAR void *priv = NULL;
/* Check if I/O is pending for this entry */
if (aiocbp->aio_result == -EINPROGRESS)
{
priv = (FAR void *)sighand;
}
aiocbp->aio_priv = priv;
}
}
memset(&sighand, 0, sizeof(struct lio_sighand_s));
sighand.list = list;
sighand.sig = *sig;
sighand.nent = nent;
sighand.pid = _SCHED_GETPID();
/* Make sure that SIGPOLL is not blocked */
sigemptyset(&set);
sigaddset(&set, SIGPOLL);
status = sigprocmask(SIG_UNBLOCK, &set, &sighand->oprocmask);
status = sigprocmask(SIG_UNBLOCK, &set, &sighand.oprocmask);
if (status != OK)
{
int errcode = get_errno();
@ -282,7 +252,7 @@ static int lio_sigsetup(FAR struct aiocb * const *list, int nent,
sigfillset(&act.sa_mask);
sigdelset(&act.sa_mask, SIGPOLL);
status = sigaction(SIGPOLL, &act, &sighand->oact);
status = sigaction(SIGPOLL, &act, &sighand.oact);
if (status != OK)
{
int errcode = get_errno();
@ -293,6 +263,36 @@ static int lio_sigsetup(FAR struct aiocb * const *list, int nent,
return -errcode;
}
/* Save this structure as the private data attached to each aiocb */
for (i = 0; i < nent; i++)
{
/* Skip over NULL entries in the list */
aiocbp = list[i];
if (aiocbp)
{
FAR void *priv = NULL;
/* Check if I/O is pending for this entry */
if (aiocbp->aio_result == -EINPROGRESS)
{
priv = lib_zalloc(sizeof(struct lio_sighand_s));
if (!priv)
{
ferr("ERROR: lib_zalloc failed\n");
return -ENOMEM;
}
memcpy(priv, (FAR void *)&sighand,
sizeof(struct lio_sighand_s));
}
aiocbp->aio_priv = priv;
}
}
return OK;
}
@ -517,7 +517,12 @@ int lio_listio(int mode, FAR struct aiocb * const list[], int nent,
int ret;
int i;
DEBUGASSERT(mode == LIO_WAIT || mode == LIO_NOWAIT);
if (mode != LIO_WAIT && mode != LIO_NOWAIT)
{
set_errno(EINVAL);
return ERROR;
}
DEBUGASSERT(list);
nqueued = 0; /* No I/O operations yet queued */