git: c48d0754a053 - stable/13 - CTL: Validate IOCTL parameters.

From: Alexander Motin <mav_at_FreeBSD.org>
Date: Wed, 14 Sep 2022 17:27:17 UTC
The branch stable/13 has been updated by mav:

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

commit c48d0754a05334cacbe6cd34871c10f3ef6f4d56
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2022-09-07 01:58:27 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2022-09-14 17:27:04 +0000

    CTL: Validate IOCTL parameters.
    
    It was possible to cause kernel panic by passing too large args_len
    or non-NULL result_nvl.
    
    Though since the /dev/cam/ctl device is accessible only by root and
    used only by limited number of tools it was not a big problem.
    
    PR:     266115
    PR:     266136
    Reported by:    Robert Morris <rtm@lcs.mit.edu>
    MFC after:      1 week
    
    (cherry picked from commit 0586be48a97c5af50ba4f578d33211f81cc57016)
---
 sys/cam/ctl/ctl.c       | 14 ++++++++++++++
 sys/cam/ctl/ctl_ioctl.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 2083059c6aee..097a5942650e 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -2977,6 +2977,12 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
 		}
 
 		if (lun_req->args != NULL) {
+			if (lun_req->args_len > CTL_MAX_ARGS_LEN) {
+				lun_req->status = CTL_LUN_ERROR;
+				snprintf(lun_req->error_str, sizeof(lun_req->error_str),
+				    "Too big args.");
+				break;
+			}
 			packed = malloc(lun_req->args_len, M_CTL, M_WAITOK);
 			if (copyin(lun_req->args, packed, lun_req->args_len) != 0) {
 				free(packed, M_CTL);
@@ -2998,6 +3004,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
 		} else
 			lun_req->args_nvl = nvlist_create(0);
 
+		lun_req->result_nvl = NULL;
 		retval = backend->ioctl(dev, cmd, addr, flag, td);
 		nvlist_destroy(lun_req->args_nvl);
 		lun_req->args_nvl = tmp_args_nvl;
@@ -3254,6 +3261,12 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
 		}
 
 		if (req->args != NULL) {
+			if (req->args_len > CTL_MAX_ARGS_LEN) {
+				req->status = CTL_LUN_ERROR;
+				snprintf(req->error_str, sizeof(req->error_str),
+				    "Too big args.");
+				break;
+			}
 			packed = malloc(req->args_len, M_CTL, M_WAITOK);
 			if (copyin(req->args, packed, req->args_len) != 0) {
 				free(packed, M_CTL);
@@ -3275,6 +3288,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
 		} else
 			req->args_nvl = nvlist_create(0);
 
+		req->result_nvl = NULL;
 		if (fe->ioctl)
 			retval = fe->ioctl(dev, cmd, addr, flag, td);
 		else
diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h
index 49c48afbd766..e9caa3f0982b 100644
--- a/sys/cam/ctl/ctl_ioctl.h
+++ b/sys/cam/ctl/ctl_ioctl.h
@@ -460,6 +460,7 @@ struct ctl_lun_req {
 	union ctl_lunreq_data	reqdata;
 	void *			args;
 	nvlist_t *		args_nvl;
+#define	CTL_MAX_ARGS_LEN	(1024 * 1024)
 	size_t			args_len;
 	void *			result;
 	nvlist_t *		result_nvl;