From ff1a307801994e18a87929898225f09d31f3e1fa Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 9 Jan 2021 20:23:05 -0700 Subject: [PATCH] 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 with 022ca2fc7fe08d51f33a1d23a9be49e6d132914e. 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: 022ca2fc7fe08d51f33a1d23a9be49e6d132914e Reviewed by: jhb, tmunro, 0mp Differential Revision: 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. diff --git a/sys/sys/aio.h b/sys/sys/aio.h index dbfbadcd1254..ee928b8bf846 100644 --- a/sys/sys/aio.h +++ b/sys/sys/aio.h @@ -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 diff --git a/tests/sys/aio/lio_test.c b/tests/sys/aio/lio_test.c index b6965cc9a4ee..fb519aac978d 100644 --- a/tests/sys/aio/lio_test.c +++ b/tests/sys/aio/lio_test.c @@ -26,8 +26,11 @@ * $FreeBSD$ */ +#define _WANT_ALL_LIO_OPCODES + #include #include +#include #include #include @@ -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()); }