lio_listio: validate aio_lio_opcode
Previously, we would accept any kind of LIO_* opcode, including ones that were intended for in-kernel use only like LIO_SYNC (which is not defined in userland). The situation became more serious with022ca2fc7f
. After that revision, setting aio_lio_opcode to LIO_WRITEV or LIO_READV would trigger an assertion. Note that POSIX does not specify what should happen if aio_lio_opcode is invalid. MFC-with:022ca2fc7f
Reviewed by: jhb, tmunro, 0mp Differential Revision: <https://reviews.freebsd.org/D28078
This commit is contained in:
parent
292808246d
commit
ff1a307801
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 2, 2021
|
.Dd January 11, 2021
|
||||||
.Dt AIO_RETURN 2
|
.Dt AIO_RETURN 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -75,6 +75,12 @@ The
|
|||||||
.Fa iocb
|
.Fa iocb
|
||||||
argument
|
argument
|
||||||
does not reference a completed asynchronous I/O request.
|
does not reference a completed asynchronous I/O request.
|
||||||
|
.It Bq Er EINVAL
|
||||||
|
The I/O operation was submitted with
|
||||||
|
.Fn lio_listio ,
|
||||||
|
and the value of the
|
||||||
|
.Fa aio_lio_opcode
|
||||||
|
is invalid.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr aio_cancel 2 ,
|
.Xr aio_cancel 2 ,
|
||||||
|
@ -1556,16 +1556,26 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
|
|||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the opcode. */
|
||||||
|
if (type == LIO_NOP) {
|
||||||
|
switch (job->uaiocb.aio_lio_opcode) {
|
||||||
|
case LIO_WRITE:
|
||||||
|
case LIO_NOP:
|
||||||
|
case LIO_READ:
|
||||||
|
opcode = job->uaiocb.aio_lio_opcode;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
opcode = job->uaiocb.aio_lio_opcode = type;
|
||||||
|
|
||||||
ksiginfo_init(&job->ksi);
|
ksiginfo_init(&job->ksi);
|
||||||
|
|
||||||
/* Save userspace address of the job info. */
|
/* Save userspace address of the job info. */
|
||||||
job->ujob = ujob;
|
job->ujob = ujob;
|
||||||
|
|
||||||
/* Get the opcode. */
|
|
||||||
if (type != LIO_NOP)
|
|
||||||
job->uaiocb.aio_lio_opcode = type;
|
|
||||||
opcode = job->uaiocb.aio_lio_opcode;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate the opcode and fetch the file object for the specified
|
* Validate the opcode and fetch the file object for the specified
|
||||||
* file descriptor.
|
* file descriptor.
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
#define LIO_NOP 0x0
|
#define LIO_NOP 0x0
|
||||||
#define LIO_WRITE 0x1
|
#define LIO_WRITE 0x1
|
||||||
#define LIO_READ 0x2
|
#define LIO_READ 0x2
|
||||||
#ifdef _KERNEL
|
#if defined(_KERNEL) || defined(_WANT_ALL_LIO_OPCODES)
|
||||||
#define LIO_SYNC 0x3
|
#define LIO_SYNC 0x3
|
||||||
#define LIO_MLOCK 0x4
|
#define LIO_MLOCK 0x4
|
||||||
#define LIO_WRITEV 0x5
|
#define LIO_WRITEV 0x5
|
||||||
|
@ -26,8 +26,11 @@
|
|||||||
* $FreeBSD$
|
* $FreeBSD$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _WANT_ALL_LIO_OPCODES
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/event.h>
|
#include <sys/event.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <aio.h>
|
#include <aio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -198,6 +201,53 @@ ATF_TC_BODY(lio_listio_empty_nowait_thread, tc)
|
|||||||
ATF_REQUIRE_EQ(0, sem_destroy(&completions));
|
ATF_REQUIRE_EQ(0, sem_destroy(&completions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only select opcodes are allowed with lio_listio
|
||||||
|
*/
|
||||||
|
ATF_TC_WITHOUT_HEAD(lio_listio_invalid_opcode);
|
||||||
|
ATF_TC_BODY(lio_listio_invalid_opcode, tc)
|
||||||
|
{
|
||||||
|
struct aiocb sync_cb, mlock_cb, writev_cb, readv_cb;
|
||||||
|
struct aiocb *list[] = {&sync_cb, &mlock_cb, &writev_cb, &readv_cb};
|
||||||
|
struct iovec iov;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open("testfile", O_CREAT | O_RDWR);
|
||||||
|
ATF_REQUIRE_MSG(fd >= 0, "open: %s", strerror(errno));
|
||||||
|
|
||||||
|
bzero(&sync_cb, sizeof(sync_cb));
|
||||||
|
sync_cb.aio_fildes = fd;
|
||||||
|
sync_cb.aio_lio_opcode = LIO_SYNC;
|
||||||
|
|
||||||
|
bzero(&mlock_cb, sizeof(mlock_cb));
|
||||||
|
mlock_cb.aio_lio_opcode = LIO_MLOCK;
|
||||||
|
|
||||||
|
iov.iov_base = NULL;
|
||||||
|
iov.iov_len = 0;
|
||||||
|
|
||||||
|
bzero(&readv_cb, sizeof(readv_cb));
|
||||||
|
readv_cb.aio_fildes = fd;
|
||||||
|
readv_cb.aio_lio_opcode = LIO_READV;
|
||||||
|
readv_cb.aio_iov = &iov;
|
||||||
|
readv_cb.aio_iovcnt = 1;
|
||||||
|
|
||||||
|
bzero(&writev_cb, sizeof(writev_cb));
|
||||||
|
writev_cb.aio_fildes = fd;
|
||||||
|
writev_cb.aio_lio_opcode = LIO_WRITEV;
|
||||||
|
writev_cb.aio_iov = &iov;
|
||||||
|
writev_cb.aio_iovcnt = 1;
|
||||||
|
|
||||||
|
ATF_CHECK_ERRNO(EIO, lio_listio(LIO_WAIT, list, nitems(list), NULL));
|
||||||
|
ATF_CHECK_EQ(EINVAL, aio_error(&sync_cb));
|
||||||
|
ATF_CHECK_ERRNO(EINVAL, aio_return(&sync_cb) < 0);
|
||||||
|
ATF_CHECK_EQ(EINVAL, aio_error(&mlock_cb));
|
||||||
|
ATF_CHECK_ERRNO(EINVAL, aio_return(&mlock_cb) < 0);
|
||||||
|
ATF_CHECK_EQ(EINVAL, aio_error(&readv_cb));
|
||||||
|
ATF_CHECK_ERRNO(EINVAL, aio_return(&readv_cb) < 0);
|
||||||
|
ATF_CHECK_EQ(EINVAL, aio_error(&writev_cb));
|
||||||
|
ATF_CHECK_ERRNO(EINVAL, aio_return(&writev_cb) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ATF_TP_ADD_TCS(tp)
|
ATF_TP_ADD_TCS(tp)
|
||||||
{
|
{
|
||||||
@ -207,6 +257,7 @@ ATF_TP_ADD_TCS(tp)
|
|||||||
ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_signal);
|
ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_signal);
|
||||||
ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_thread);
|
ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_thread);
|
||||||
ATF_TP_ADD_TC(tp, lio_listio_empty_wait);
|
ATF_TP_ADD_TC(tp, lio_listio_empty_wait);
|
||||||
|
ATF_TP_ADD_TC(tp, lio_listio_invalid_opcode);
|
||||||
|
|
||||||
return (atf_no_error());
|
return (atf_no_error());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user