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$
|
||||
.\"
|
||||
.Dd January 2, 2021
|
||||
.Dd January 11, 2021
|
||||
.Dt AIO_RETURN 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -75,6 +75,12 @@ The
|
||||
.Fa iocb
|
||||
argument
|
||||
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
|
||||
.Sh SEE ALSO
|
||||
.Xr aio_cancel 2 ,
|
||||
|
@ -1556,16 +1556,26 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
|
||||
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);
|
||||
|
||||
/* Save userspace address of the job info. */
|
||||
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
|
||||
* file descriptor.
|
||||
|
@ -43,7 +43,7 @@
|
||||
#define LIO_NOP 0x0
|
||||
#define LIO_WRITE 0x1
|
||||
#define LIO_READ 0x2
|
||||
#ifdef _KERNEL
|
||||
#if defined(_KERNEL) || defined(_WANT_ALL_LIO_OPCODES)
|
||||
#define LIO_SYNC 0x3
|
||||
#define LIO_MLOCK 0x4
|
||||
#define LIO_WRITEV 0x5
|
||||
|
@ -26,8 +26,11 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define _WANT_ALL_LIO_OPCODES
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <aio.h>
|
||||
#include <fcntl.h>
|
||||
@ -198,6 +201,53 @@ ATF_TC_BODY(lio_listio_empty_nowait_thread, tc)
|
||||
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)
|
||||
{
|
||||
@ -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_thread);
|
||||
ATF_TP_ADD_TC(tp, lio_listio_empty_wait);
|
||||
ATF_TP_ADD_TC(tp, lio_listio_invalid_opcode);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user