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:
parent
0dba857028
commit
9efa398c69
1 changed files with 44 additions and 39 deletions
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue