git: c4c1d79338a3 - releng/12.3 - mpr/mps/mpt: verify cfg page ioctl lengths

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Wed, 06 Apr 2022 03:04:49 UTC
The branch releng/12.3 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=c4c1d79338a30d6dcc0fa0cf6d65f1f0bc7a101c

commit c4c1d79338a30d6dcc0fa0cf6d65f1f0bc7a101c
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2022-04-05 23:21:30 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2022-04-05 23:29:20 +0000

    mpr/mps/mpt: verify cfg page ioctl lengths
    
    *_CFG_PAGE ioctl handlers in the mpr, mps, and mpt drivers allocated a
    buffer of a caller-specified size, but copied to it a fixed size header.
    Add checks that the size is at least the required minimum.
    
    Note that the device nodes are owned by root:operator with 0640
    permissions so the ioctls are not available to unprivileged users.
    
    This change includes suggestions from scottl, markj and mav.
    
    Two of the mpt cases were reported by Lucas Leong (@_wmliang_) of
    Trend Micro Zero Day Initiative; scottl reported the third case in mpt.
    Same issue found in mpr and mps after discussion with imp.
    
    Reported by:    Lucas Leong (@_wmliang_), Trend Micro Zero Day Initiative
    Reviewed by:    imp, mav
    MFC after:      3 days
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D34692
    
    (cherry picked from commit 8276c4149b5fc7c755d6b244fbbf6dae1939f087)
    (cherry picked from commit 56d0638c738e3f9b7fbc7f78bd49590523e01ada)
    
    Approved by:    so
    Security:       CVE-2022-23086
    Security:       FreeBSD-SA-22:06.ioctl
---
 sys/dev/mpr/mpr_user.c | 13 +++++++++++++
 sys/dev/mps/mps_user.c | 13 +++++++++++++
 sys/dev/mpt/mpt_user.c | 13 +++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c
index 3995d01154f7..53b3f94ea152 100644
--- a/sys/dev/mpr/mpr_user.c
+++ b/sys/dev/mpr/mpr_user.c
@@ -2272,6 +2272,10 @@ mpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		mpr_unlock(sc);
 		break;
 	case MPRIO_READ_CFG_PAGE:
+		if (page_req->len < (int)sizeof(MPI2_CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK | M_ZERO);
 		error = copyin(page_req->buf, mpr_page,
 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
@@ -2290,6 +2294,11 @@ mpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		mpr_unlock(sc);
 		break;
 	case MPRIO_READ_EXT_CFG_PAGE:
+		if (ext_page_req->len <
+		    (int)sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mpr_page = malloc(ext_page_req->len, M_MPRUSER,
 		    M_WAITOK | M_ZERO);
 		error = copyin(ext_page_req->buf, mpr_page,
@@ -2304,6 +2313,10 @@ mpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		error = copyout(mpr_page, ext_page_req->buf, ext_page_req->len);
 		break;
 	case MPRIO_WRITE_CFG_PAGE:
+		if (page_req->len < (int)sizeof(MPI2_CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK|M_ZERO);
 		error = copyin(page_req->buf, mpr_page, page_req->len);
 		if (error)
diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c
index ab4d1d2d86f3..e7e376288961 100644
--- a/sys/dev/mps/mps_user.c
+++ b/sys/dev/mps/mps_user.c
@@ -2175,6 +2175,10 @@ mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		mps_unlock(sc);
 		break;
 	case MPSIO_READ_CFG_PAGE:
+		if (page_req->len < (int)sizeof(MPI2_CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
 		error = copyin(page_req->buf, mps_page,
 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
@@ -2193,6 +2197,11 @@ mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		mps_unlock(sc);
 		break;
 	case MPSIO_READ_EXT_CFG_PAGE:
+		if (ext_page_req->len <
+		    (int)sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
 		error = copyin(ext_page_req->buf, mps_page,
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -2206,6 +2215,10 @@ mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 		error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
 		break;
 	case MPSIO_WRITE_CFG_PAGE:
+		if (page_req->len < (int)sizeof(MPI2_CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
 		error = copyin(page_req->buf, mps_page, page_req->len);
 		if (error)
diff --git a/sys/dev/mpt/mpt_user.c b/sys/dev/mpt/mpt_user.c
index 80fef9e491bf..cc5a914ef90f 100644
--- a/sys/dev/mpt/mpt_user.c
+++ b/sys/dev/mpt/mpt_user.c
@@ -672,6 +672,10 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
 	case MPTIO_READ_CFG_PAGE32:
 #endif
 	case MPTIO_READ_CFG_PAGE:
+		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
 		if (error)
 			break;
@@ -698,6 +702,11 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
 	case MPTIO_READ_EXT_CFG_PAGE32:
 #endif
 	case MPTIO_READ_EXT_CFG_PAGE:
+		if (ext_page_req->len <
+		    (int)sizeof(CONFIG_EXTENDED_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
 		if (error)
 			break;
@@ -717,6 +726,10 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
 	case MPTIO_WRITE_CFG_PAGE32:
 #endif
 	case MPTIO_WRITE_CFG_PAGE:
+		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
+			error = EINVAL;
+			break;
+		}
 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
 		if (error)
 			break;