This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new af53d7a178 libs/libc/aio/lio_listio: fix the heap use-after-free bug
af53d7a178 is described below
commit af53d7a178da3bf398fddb2ae3fffca63ed701bc
Author: guoshichao <[email protected]>
AuthorDate: Mon Jun 19 17:52:39 2023 +0800
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 <[email protected]>
---
libs/libc/aio/lio_listio.c | 83 ++++++++++++++++++++++++----------------------
1 file changed, 44 insertions(+), 39 deletions(-)
diff --git a/libs/libc/aio/lio_listio.c b/libs/libc/aio/lio_listio.c
index ae1b2f4d13..d54e5e2526 100644
--- a/libs/libc/aio/lio_listio.c
+++ b/libs/libc/aio/lio_listio.c
@@ -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 */