File 0059-LU-16634-misc-standardize-iocontrol-param-handling.patch of Package lustre_2_12

From 5eae8514f5f1730fe93d55d348400f5ecf681078 Mon Sep 17 00:00:00 2001
From: Andreas Dilger <adilger@whamcloud.com>
Date: Sun, 19 Mar 2023 20:22:10 -0600
Subject: [PATCH] LU-16634 misc: standardize iocontrol param handling

Validate uarg and karg early in iocontrol processing where needed.
This needs kernel interop for 4.20+ kernels for access_ok(), but
this can be checked by #ifdef and does not need an autoconf test.

Fix incorrect definition of OBD_IOC_BARRIER to match reality.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Reported-by: Tao Lyu <tao.lyu@epfl.ch>
Change-Id: I1a0d2f839949debf346aa15c65b0f407e9ce7057
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50314
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Arshad Hussain <arshad.hussain@aeoncomputing.com>
Reviewed-by: Vitaliy Kuznetsov <vkuznetsov@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
---
 lustre/include/lustre_compat.h                  |    6 +
 lustre/include/uapi/linux/lustre/lustre_ioctl.h |    3 
 lustre/llite/file.c                             |   76 +++++++++++++-----------
 lustre/llite/llite_lib.c                        |    7 ++
 lustre/lod/lod_dev.c                            |    1 
 lustre/lov/lov_obd.c                            |   42 ++++++++++---
 lustre/mdc/mdc_request.c                        |   21 ++++--
 lustre/mdd/mdd_device.c                         |    5 +
 lustre/mdt/mdt_handler.c                        |   39 ++++++------
 lustre/mgs/mgs_handler.c                        |   23 ++++---
 lustre/obdclass/class_obd.c                     |   21 +++---
 lustre/obdecho/echo_client.c                    |    5 +
 lustre/ofd/ofd_obd.c                            |   34 ++++++----
 lustre/osc/osc_request.c                        |   25 ++++++-
 lustre/osp/osp_dev.c                            |    8 ++
 lustre/tests/group_lock_test.c                  |   16 ++---
 16 files changed, 212 insertions(+), 120 deletions(-)

--- a/lustre/include/lustre_compat.h
+++ b/lustre/include/lustre_compat.h
@@ -644,6 +644,12 @@ __generic_file_write_iter(struct kiocb *
 }
 #endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
 
+#ifdef VERIFY_WRITE /* removed in kernel commit v4.20-10979-g96d4f267e40f */
+#define ll_access_ok(ptr, len) access_ok(VERIFY_WRITE, ptr, len)
+#else
+#define ll_access_ok(ptr, len) access_ok(ptr, len)
+#endif
+
 static inline void __user *get_vmf_address(struct vm_fault *vmf)
 {
 #ifdef HAVE_VM_FAULT_ADDRESS
--- a/lustre/include/uapi/linux/lustre/lustre_ioctl.h
+++ b/lustre/include/uapi/linux/lustre/lustre_ioctl.h
@@ -235,7 +235,8 @@ static inline __u32 obd_ioctl_packlen(st
 /*	lustre/lustre_user.h	240-249 */
 /* was	LIBCFS_IOC_DEBUG_MASK	_IOWR('f', 250, long) until 2.11 */
 
-#define OBD_IOC_BARRIER		_IOWR('f', 261, OBD_IOC_DATA_TYPE)
+/* OBD_IOC_BARRIER wrongly defined as _IOWR('f', 261, OBD_IOC_DATA_TYPE) */
+#define OBD_IOC_BARRIER		_IOWR('g', 5, OBD_IOC_DATA_TYPE)
 
 #define IOC_OSC_SET_ACTIVE	_IOWR('h', 21, void *)
 
--- a/lustre/llite/file.c
+++ b/lustre/llite/file.c
@@ -2103,11 +2103,15 @@ out_lump:
 
 static int ll_file_getstripe(struct inode *inode, void __user *lum, size_t size)
 {
-	struct lu_env	*env;
-	__u16		refcheck;
-	int		rc;
+	struct lu_env *env;
+	__u16 refcheck;
+	int rc;
 	ENTRY;
 
+	/* exit before doing any work if pointer is bad */
+	if (unlikely(!ll_access_ok(lum, sizeof(struct lov_user_md))))
+		RETURN(-EFAULT);
+
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
 		RETURN(PTR_ERR(env));
@@ -3175,15 +3179,15 @@ static long ll_file_unlock_lease(struct
 		bias = MDS_CLOSE_RESYNC_DONE;
 		break;
 	case LL_LEASE_LAYOUT_MERGE: {
-		int fd;
+		__u32 fdv;
 		if (ioc->lil_count != 1)
 			GOTO(out, rc = -EINVAL);
 
 		uarg += sizeof(*ioc);
-		if (copy_from_user(&fd, uarg, sizeof(__u32)))
+		if (copy_from_user(&fdv, uarg, sizeof(fdv)))
 			GOTO(out, rc = -EFAULT);
 
-		layout_file = fget(fd);
+		layout_file = fget(fdv);
 		if (!layout_file)
 			GOTO(out, rc = -EBADF);
 
@@ -3194,21 +3198,23 @@ static long ll_file_unlock_lease(struct
 		data = file_inode(layout_file);
 		bias = MDS_CLOSE_LAYOUT_MERGE;
 		break;
-	}
+		}
 	case LL_LEASE_LAYOUT_SPLIT: {
-		int fdv;
-		int mirror_id;
+		__u32 fdv;
+		__u32 mirror_id;
 
 		if (ioc->lil_count != 2)
 			GOTO(out, rc = -EINVAL);
 
 		uarg += sizeof(*ioc);
-		if (copy_from_user(&fdv, uarg, sizeof(__u32)))
+		if (copy_from_user(&fdv, uarg, sizeof(fdv)))
 			GOTO(out, rc = -EFAULT);
 
-		uarg += sizeof(__u32);
-		if (copy_from_user(&mirror_id, uarg, sizeof(__u32)))
+		uarg += sizeof(fdv);
+		if (copy_from_user(&mirror_id, uarg, sizeof(mirror_id)))
 			GOTO(out, rc = -EFAULT);
+		if (mirror_id >= MIRROR_ID_NEG)
+			GOTO(out, rc = -EINVAL);
 
 		layout_file = fget(fdv);
 		if (!layout_file)
@@ -3339,6 +3345,9 @@ ll_file_ioctl(struct file *file, unsigne
 	if (_IOC_TYPE(cmd) == 'T' || _IOC_TYPE(cmd) == 't') /* tty ioctls */
 		RETURN(-ENOTTY);
 
+	/* can't do a generic karg == NULL check here, since it is too noisy and
+	 * we need to return -ENOTTY for unsupported ioctls instead of -EINVAL.
+	 */
 	switch (cmd) {
 	case LL_IOC_GETFLAGS:
 		/* Get the current value of the file flags */
@@ -3440,6 +3449,9 @@ out:
 		struct hsm_user_state *hus;
 		int rc;
 
+		if (!ll_access_ok(uarg, sizeof(*hus)))
+			RETURN(-EFAULT);
+
 		OBD_ALLOC_PTR(hus);
 		if (hus == NULL)
 			RETURN(-ENOMEM);
@@ -3447,17 +3459,16 @@ out:
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, hus);
 		if (IS_ERR(op_data)) {
-			OBD_FREE_PTR(hus);
-			RETURN(PTR_ERR(op_data));
-		}
-
-		rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
-				   op_data, NULL);
+			rc = PTR_ERR(op_data);
+		} else {
+			rc = obd_iocontrol(cmd, ll_i2mdexp(inode),
+					   sizeof(*op_data), op_data, NULL);
 
-		if (copy_to_user(uarg, hus, sizeof(*hus)))
-			rc = -EFAULT;
+			if (copy_to_user(uarg, hus, sizeof(*hus)))
+				rc = -EFAULT;
 
-		ll_finish_md_op_data(op_data);
+			ll_finish_md_op_data(op_data);
+		}
 		OBD_FREE_PTR(hus);
 		RETURN(rc);
 	}
@@ -3469,12 +3480,10 @@ out:
 		if (hss == NULL)
 			RETURN(-ENOMEM);
 
-		if (copy_from_user(hss, uarg, sizeof(*hss))) {
-			OBD_FREE_PTR(hss);
-			RETURN(-EFAULT);
-		}
-
-		rc = ll_hsm_state_set(inode, hss);
+		if (copy_from_user(hss, uarg, sizeof(*hss)))
+			rc = -EFAULT;
+		else
+			rc = ll_hsm_state_set(inode, hss);
 
 		OBD_FREE_PTR(hss);
 		RETURN(rc);
@@ -3484,6 +3493,9 @@ out:
 		struct hsm_current_action	*hca;
 		int				 rc;
 
+		if (!ll_access_ok(uarg, sizeof(*hca)))
+			RETURN(-EFAULT);
+
 		OBD_ALLOC_PTR(hca);
 		if (hca == NULL)
 			RETURN(-ENOMEM);
@@ -3548,12 +3560,10 @@ out:
 		if (hui == NULL)
 			RETURN(-ENOMEM);
 
-		if (copy_from_user(hui, uarg, sizeof(*hui))) {
-			OBD_FREE_PTR(hui);
-			RETURN(-EFAULT);
-		}
-
-		rc = ll_hsm_import(inode, file, hui);
+		if (copy_from_user(hui, uarg, sizeof(*hui)))
+			rc = -EFAULT;
+		else
+			rc = ll_hsm_import(inode, file, hui);
 
 		OBD_FREE_PTR(hui);
 		RETURN(rc);
--- a/lustre/llite/llite_lib.c
+++ b/lustre/llite/llite_lib.c
@@ -40,6 +40,7 @@
 #include <linux/statfs.h>
 #include <linux/time.h>
 #include <linux/types.h>
+#include <linux/uaccess.h>
 #include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/user_namespace.h>
@@ -2175,6 +2176,9 @@ int ll_iocontrol(struct inode *inode, st
 		struct mdt_body *body;
 		struct md_op_data *op_data;
 
+		if (!ll_access_ok(uarg, sizeof(int)))
+			RETURN(-EFAULT);
+
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, NULL);
 		if (IS_ERR(op_data))
@@ -2250,6 +2254,9 @@ int ll_iocontrol(struct inode *inode, st
 	case IOC_OBD_STATFS:
 		RETURN(ll_obd_statfs(inode, uarg));
 	case LL_IOC_GET_MDTIDX: {
+		if (!ll_access_ok(uarg, sizeof(rc)))
+			RETURN(-EFAULT);
+
 		rc = ll_get_mdt_idx(inode);
 		if (rc < 0)
 			RETURN(rc);
--- a/lustre/lod/lod_dev.c
+++ b/lustre/lod/lod_dev.c
@@ -1987,6 +1987,7 @@ static int lod_obd_disconnect(struct obd
 	ENTRY;
 
 	/* Only disconnect the underlying layers on the final disconnect. */
+
 	spin_lock(&lod->lod_connects_lock);
 	lod->lod_connects--;
 	if (lod->lod_connects != 0) {
--- a/lustre/lov/lov_obd.c
+++ b/lustre/lov/lov_obd.c
@@ -980,15 +980,28 @@ static int lov_iocontrol(unsigned int cm
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       exp->exp_obd->obd_name, cmd, len, karg, uarg);
 
+	/* exit early for unknown ioctl types */
+	if (unlikely(_IOC_TYPE(cmd) != 'f' && cmd != IOC_OSC_SET_ACTIVE))
+		RETURN(OBD_IOC_DEBUG(D_IOCTL, obd->obd_name, cmd, "unknown",
+				     -ENOTTY));
+
+	/* can't do a generic karg == NULL check here, since it is too noisy and
+	 * we need to return -ENOTTY for unsupported ioctls instead of -EINVAL.
+	 */
 	switch (cmd) {
 	case IOC_OBD_STATFS: {
-		struct obd_ioctl_data *data = karg;
+		struct obd_ioctl_data *data;
 		struct obd_device *osc_obd;
 		struct obd_statfs stat_buf = {0};
 		struct obd_import *imp;
 		__u32 index;
 		__u32 flags;
 
+		if (unlikely(karg == NULL))
+			RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=null",
+					     -EINVAL));
+		data = karg;
+
 		memcpy(&index, data->ioc_inlbuf2, sizeof(index));
 		if (index >= count)
 			RETURN(-ENODEV);
@@ -1073,10 +1086,15 @@ static int lov_iocontrol(unsigned int cm
                 break;
         }
         case OBD_IOC_QUOTACTL: {
-                struct if_quotactl *qctl = karg;
+                struct if_quotactl *qctl;
                 struct lov_tgt_desc *tgt = NULL;
                 struct obd_quotactl *oqctl;
 
+		if (unlikely(karg == NULL))
+			RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=null",
+					     -EINVAL));
+		qctl = karg;
+
 		if (qctl->qc_valid == QC_OSTIDX) {
 			if (count <= qctl->qc_idx)
 				RETURN(-EINVAL);
@@ -1147,17 +1165,21 @@ static int lov_iocontrol(unsigned int cm
 						      err);
 					if (!rc)
 						rc = err;
+
+					if (err == -ENOTTY)
+						break;
 				}
 			} else {
-                                set = 1;
-                        }
-                }
-                if (!set && !rc)
-                        rc = -EIO;
-        }
-        }
+				set = 1;
+			}
+		}
+		if (!set && !rc)
+			rc = -EIO;
+		break;
+	}
+	}
 
-        RETURN(rc);
+	RETURN(rc);
 }
 
 static int lov_get_info(const struct lu_env *env, struct obd_export *exp,
--- a/lustre/mdc/mdc_request.c
+++ b/lustre/mdc/mdc_request.c
@@ -2065,7 +2065,7 @@ static int mdc_iocontrol(unsigned int cm
 			 void *karg, void __user *uarg)
 {
 	struct obd_device *obd = exp->exp_obd;
-	struct obd_ioctl_data *data = karg;
+	struct obd_ioctl_data *data;
 	struct obd_import *imp = obd->u.cli.cl_import;
 	int rc;
 
@@ -2073,6 +2073,19 @@ static int mdc_iocontrol(unsigned int cm
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       obd->obd_name, cmd, len, karg, uarg);
 
+	/* handle commands that do not need @karg first */
+	switch (cmd) {
+	case LL_IOC_GET_CONNECT_FLAGS:
+		if (copy_to_user(uarg, exp_connect_flags_ptr(exp),
+				 sizeof(*exp_connect_flags_ptr(exp))))
+			RETURN(-EFAULT);
+		RETURN(0);
+	}
+
+	if (unlikely(karg == NULL))
+		RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", -EINVAL));
+	data = karg;
+
 	if (!try_module_get(THIS_MODULE)) {
 		CERROR("%s: cannot get module '%s'\n", obd->obd_name,
 		       module_name(THIS_MODULE));
@@ -2165,12 +2178,6 @@ static int mdc_iocontrol(unsigned int cm
 		OBD_FREE_PTR(oqctl);
 		GOTO(out, rc);
 	}
-	case LL_IOC_GET_CONNECT_FLAGS:
-		if (copy_to_user(uarg, exp_connect_flags_ptr(exp),
-				 sizeof(*exp_connect_flags_ptr(exp))))
-			GOTO(out, rc = -EFAULT);
-
-		GOTO(out, rc = 0);
 	case LL_IOC_LOV_SWAP_LAYOUTS:
 		rc = mdc_ioc_swap_layouts(exp, karg);
 		GOTO(out, rc);
--- a/lustre/mdd/mdd_device.c
+++ b/lustre/mdd/mdd_device.c
@@ -1924,12 +1924,15 @@ static int mdd_iocontrol(const struct lu
 {
 	struct mdd_device *mdd = lu2mdd_dev(&m->md_lu_dev);
 	struct obd_device *obd = mdd2obd_dev(mdd);
-	struct obd_ioctl_data *data = karg;
+	struct obd_ioctl_data *data;
 	int rc = -EINVAL;
 
 	ENTRY;
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK\n",
 	       obd->obd_name, cmd, len, karg);
+	if (unlikely(karg == NULL))
+		RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", rc));
+	data = karg;
 
 	/* Doesn't use obd_ioctl_data */
 	switch (cmd) {
--- a/lustre/mdt/mdt_handler.c
+++ b/lustre/mdt/mdt_handler.c
@@ -6781,9 +6781,10 @@ static int mdt_iocontrol(unsigned int cm
 	struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
 	struct dt_device *dt = mdt->mdt_bottom;
 	struct lu_env env;
+	struct obd_ioctl_data *data;
 	int rc;
 
-	ENTRY;
+        ENTRY;
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       obd->obd_name, cmd, len, karg, uarg);
 
@@ -6791,6 +6792,7 @@ static int mdt_iocontrol(unsigned int cm
 	if (rc)
 		RETURN(rc);
 
+	/* handle commands that don't use @karg first */
 	switch (cmd) {
 		struct obd_ioctl_data *data = karg;
 
@@ -6800,39 +6802,41 @@ static int mdt_iocontrol(unsigned int cm
 			wake_up(&obd->obd_next_transno_waitq);
 		if (rc == 0)
 			rc = dt_ro(&env, dt);
-		break;
+		GOTO(out, rc);
 	case OBD_IOC_ABORT_RECOVERY:
-		CWARN("%s: Aborting client recovery\n", obd->obd_name);
+		LCONSOLE_WARN("%s: Aborting recovery for device\n",
+				      mdt_obd_name(mdt));
 		obd->obd_abort_recovery = 1;
 		target_stop_recovery_thread(obd);
 		rc = 0;
-		break;
+		GOTO(out, rc);
+	}
+
+	if (unlikely(karg == NULL)) {
+		OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", rc = -EINVAL);
+		GOTO(out, rc);
+	}
+	data = karg;
+
+	switch (cmd) {
         case OBD_IOC_CHANGELOG_REG:
         case OBD_IOC_CHANGELOG_DEREG:
         case OBD_IOC_CHANGELOG_CLEAR:
-		rc = mdt->mdt_child->md_ops->mdo_iocontrol(&env,
-							   mdt->mdt_child,
+		rc = mdt->mdt_child->md_ops->mdo_iocontrol(&env, mdt->mdt_child,
 							   cmd, len, karg);
                 break;
 	case OBD_IOC_START_LFSCK: {
 		struct md_device *next = mdt->mdt_child;
-		struct obd_ioctl_data *data = karg;
 		struct lfsck_start_param lsp;
 
-		if (unlikely(data == NULL)) {
-			rc = -EINVAL;
-			break;
-		}
-
 		lsp.lsp_start = (struct lfsck_start *)(data->ioc_inlbuf1);
 		lsp.lsp_index_valid = 0;
 		rc = next->md_ops->mdo_iocontrol(&env, next, cmd, 0, &lsp);
 		break;
 	}
 	case OBD_IOC_STOP_LFSCK: {
-		struct md_device	*next = mdt->mdt_child;
-		struct obd_ioctl_data	*data = karg;
-		struct lfsck_stop	 stop;
+		struct md_device *next = mdt->mdt_child;
+		struct lfsck_stop stop;
 
 		stop.ls_status = LS_STOPPED;
 		/* Old lfsck utils may pass NULL @stop. */
@@ -6846,8 +6850,7 @@ static int mdt_iocontrol(unsigned int cm
 		break;
 	}
 	case OBD_IOC_QUERY_LFSCK: {
-		struct md_device	*next = mdt->mdt_child;
-		struct obd_ioctl_data	*data = karg;
+		struct md_device *next = mdt->mdt_child;
 
 		rc = next->md_ops->mdo_iocontrol(&env, next, cmd, 0,
 						 data->ioc_inlbuf1);
@@ -6877,7 +6880,7 @@ static int mdt_iocontrol(unsigned int cm
 		rc = OBD_IOC_ERROR(obd->obd_name, cmd, "unrecognized", -ENOTTY);
 		break;
 	}
-
+out:
         lu_env_fini(&env);
         RETURN(rc);
 }
--- a/lustre/mgs/mgs_handler.c
+++ b/lustre/mgs/mgs_handler.c
@@ -996,13 +996,16 @@ static int mgs_iocontrol(unsigned int cm
 {
 	struct obd_device *obd = exp->exp_obd;
 	struct mgs_device *mgs = exp2mgs_dev(exp);
-	struct obd_ioctl_data *data = karg;
+	struct obd_ioctl_data *data;
 	struct lu_env env;
 	int rc = -EINVAL;
 
 	ENTRY;
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       obd->obd_name, cmd, len, karg, uarg);
+	if (unlikely(karg == NULL))
+		RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", rc));
+	data = karg;
 
 	rc = lu_env_init(&env, LCT_MG_THREAD);
 	if (rc)
@@ -1072,8 +1075,8 @@ out_free:
 		rc = mgs_replace_nids(&env, mgs, data->ioc_inlbuf1,
 				      data->ioc_inlbuf2);
 		if (rc)
-			CERROR("%s: error replacing nids: rc = %d\n",
-			       obd->obd_name, rc);
+			CERROR("%s: error replacing NIDs for '%s': rc = %d\n",
+			       obd->obd_name, data->ioc_inlbuf1, rc);
 
 		break;
 	case OBD_IOC_CLEAR_CONFIGS:
@@ -1124,20 +1127,20 @@ out_free:
 		break;
 	case OBD_IOC_LLOG_CANCEL:
 	case OBD_IOC_LLOG_REMOVE:
-        case OBD_IOC_LLOG_CHECK:
-        case OBD_IOC_LLOG_INFO:
-        case OBD_IOC_LLOG_PRINT: {
-                struct llog_ctxt *ctxt;
+	case OBD_IOC_LLOG_CHECK:
+	case OBD_IOC_LLOG_INFO:
+	case OBD_IOC_LLOG_PRINT: {
+		struct llog_ctxt *ctxt;
 
 		ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
 		rc = llog_ioctl(&env, ctxt, cmd, data);
 		llog_ctxt_put(ctxt);
 		break;
-        }
-        default:
+	}
+	default:
 		rc = OBD_IOC_ERROR(obd->obd_name, cmd, "unrecognized", -ENOTTY);
 		break;
-        }
+	}
 out:
 	lu_env_fini(&env);
 	RETURN(rc);
--- a/lustre/obdclass/class_obd.c
+++ b/lustre/obdclass/class_obd.c
@@ -278,16 +278,11 @@ int obd_ioctl_getdata(char **buf, int *l
 	*len = hdr.ioc_len;
 	data = (struct obd_ioctl_data *)*buf;
 
-	if (copy_from_user(*buf, arg, hdr.ioc_len)) {
-		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		RETURN(-EFAULT);
-	}
+	if (copy_from_user(*buf, arg, hdr.ioc_len))
+		GOTO(out_free, rc = -EFAULT);
 
-	if (obd_ioctl_is_invalid(data)) {
-		CERROR("ioctl not correctly formatted\n");
-		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		RETURN(-EINVAL);
-	}
+	if (obd_ioctl_is_invalid(data))
+		GOTO(out_free, rc = -EINVAL);
 
 	if (data->ioc_inllen1) {
 		data->ioc_inlbuf1 = &data->ioc_bulk[0];
@@ -308,6 +303,10 @@ int obd_ioctl_getdata(char **buf, int *l
 		data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
 
 	RETURN(0);
+
+out_free:
+	OBD_FREE_LARGE(data, *len);
+	RETURN(rc);
 }
 EXPORT_SYMBOL(obd_ioctl_getdata);
 
@@ -320,6 +319,10 @@ int class_handle_ioctl(unsigned int cmd,
 
 	ENTRY;
 	CDEBUG(D_IOCTL, "obdclass: cmd=%x len=%u uarg=%pK\n", cmd, len, uarg);
+	if (unlikely(_IOC_TYPE(cmd) != 'f' && cmd != IOC_OSC_SET_ACTIVE &&
+		     cmd != OBD_IOC_BARRIER))
+		RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "unknown", -ENOTTY));
+
 	rc = obd_ioctl_getdata(&buf, &len, uarg);
 	if (rc) {
 		CERROR("%s: ioctl data error: rc = %d\n", current->comm, rc);
--- a/lustre/obdecho/echo_client.c
+++ b/lustre/obdecho/echo_client.c
@@ -2747,7 +2747,7 @@ echo_client_iocontrol(unsigned int cmd,
         struct echo_device *ed = obd2echo_dev(obd);
         struct echo_client_obd *ec = ed->ed_ec;
         struct echo_object *eco;
-        struct obd_ioctl_data *data = karg;
+        struct obd_ioctl_data *data;
         struct lu_env *env;
         struct obdo *oa;
         struct lu_fid fid;
@@ -2760,6 +2760,9 @@ echo_client_iocontrol(unsigned int cmd,
 	ENTRY;
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       exp->exp_obd->obd_name, cmd, len, karg, uarg);
+	if (unlikely(karg == NULL))
+		RETURN(OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", rc));
+	data = karg;
 
 	oa = &data->ioc_obdo1;
 	if (!(oa->o_valid & OBD_MD_FLGROUP)) {
--- a/lustre/ofd/ofd_obd.c
+++ b/lustre/ofd/ofd_obd.c
@@ -1258,8 +1258,7 @@ static int ofd_ioc_get_obj_version(const
 	int rc = 0;
 
 	ENTRY;
-
-	if (!data->ioc_inlbuf2 || data->ioc_inllen2 != sizeof(version))
+	if (!data || !data->ioc_inlbuf2 || data->ioc_inllen2 != sizeof(version))
 		GOTO(out, rc = -EINVAL);
 
 	if (data->ioc_inlbuf1 && data->ioc_inllen1 == sizeof(fid)) {
@@ -1329,6 +1328,7 @@ static int ofd_iocontrol(unsigned int cm
 	struct lu_env env;
 	struct ofd_device *ofd = ofd_exp(exp);
 	struct obd_device *obd = ofd_obd(ofd);
+	struct obd_ioctl_data *data;
 	int rc;
 
 	ENTRY;
@@ -1338,38 +1338,42 @@ static int ofd_iocontrol(unsigned int cm
 	if (rc)
 		RETURN(rc);
 
+	/* handle commands that don't use @karg first */
+	rc = -EINVAL;
 	switch (cmd) {
 	case OBD_IOC_ABORT_RECOVERY:
-		CWARN("%s: Aborting recovery\n", obd->obd_name);
+		LCONSOLE_WARN("%s: Aborting recovery\n", obd->obd_name);
 		obd->obd_abort_recovery = 1;
 		target_stop_recovery_thread(obd);
-		break;
+		GOTO(out, rc);
 	case OBD_IOC_SYNC:
 		CDEBUG(D_RPCTRACE, "syncing ost %s\n", obd->obd_name);
 		rc = dt_sync(&env, ofd->ofd_osd);
-		break;
+		GOTO(out, rc);
 	case OBD_IOC_SET_READONLY:
 		rc = dt_sync(&env, ofd->ofd_osd);
 		if (rc == 0)
 			rc = dt_ro(&env, ofd->ofd_osd);
-		break;
+		GOTO(out, rc);
+	}
+
+	if (unlikely(karg == NULL)) {
+		OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL", rc = -EINVAL);
+		GOTO(out, rc);
+	}
+	data = karg;
+
+	switch (cmd) {
 	case OBD_IOC_START_LFSCK: {
-		struct obd_ioctl_data *data = karg;
 		struct lfsck_start_param lsp;
 
-		if (unlikely(!data)) {
-			rc = -EINVAL;
-			break;
-		}
-
 		lsp.lsp_start = (struct lfsck_start *)(data->ioc_inlbuf1);
 		lsp.lsp_index_valid = 0;
 		rc = lfsck_start(&env, ofd->ofd_osd, &lsp);
 		break;
 	}
 	case OBD_IOC_STOP_LFSCK: {
-		struct obd_ioctl_data *data = karg;
-		struct lfsck_stop      stop;
+		struct lfsck_stop stop;
 
 		stop.ls_status = LS_STOPPED;
 		/* Old lfsck utils may pass NULL @stop. */
@@ -1389,7 +1393,7 @@ static int ofd_iocontrol(unsigned int cm
 		rc = OBD_IOC_ERROR(obd->obd_name, cmd, "unrecognized", -ENOTTY);
 		break;
 	}
-
+out:
 	lu_env_fini(&env);
 	RETURN(rc);
 }
--- a/lustre/osc/osc_request.c
+++ b/lustre/osc/osc_request.c
@@ -2837,8 +2837,8 @@ static int osc_iocontrol(unsigned int cm
 			 void *karg, void __user *uarg)
 {
         struct obd_device *obd = exp->exp_obd;
-        struct obd_ioctl_data *data = karg;
-        int err = 0;
+        struct obd_ioctl_data *data;
+        int err;
         ENTRY;
 
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
@@ -2847,16 +2847,29 @@ static int osc_iocontrol(unsigned int cm
 	if (!try_module_get(THIS_MODULE)) {
 		CERROR("%s: cannot get module '%s'\n", obd->obd_name,
 		       module_name(THIS_MODULE));
-		return -EINVAL;
+		RETURN(-EINVAL);
 	}
+
         switch (cmd) {
         case OBD_IOC_CLIENT_RECOVER:
+                if (unlikely(karg == NULL)) {
+                        OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL",
+                                      err = -EINVAL);
+                        break;
+                }
+                data = karg;
                 err = ptlrpc_recover_import(obd->u.cli.cl_import,
                                             data->ioc_inlbuf1, 0);
                 if (err > 0)
                         err = 0;
                 GOTO(out, err);
         case IOC_OSC_SET_ACTIVE:
+                if (unlikely(karg == NULL)) {
+                        OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL",
+                                      err = -EINVAL);
+                        break;
+                }
+                data = karg;
                 err = ptlrpc_set_import_active(obd->u.cli.cl_import,
                                                data->ioc_offset);
                 GOTO(out, err);
@@ -2864,9 +2877,9 @@ static int osc_iocontrol(unsigned int cm
                 err = ptlrpc_obd_ping(obd);
                 GOTO(out, err);
 	default:
-		rc = OBD_IOC_DEBUG(D_IOCTL, obd->obd_name, cmd, "unrecognized",
-				   -ENOTTY);
-		GOTO(out, err = -ENOTTY);
+		err = OBD_IOC_DEBUG(D_IOCTL, obd->obd_name, cmd, "unrecognized",
+				    -ENOTTY);
+		GOTO(out, err);
 	}
 out:
 	module_put(THIS_MODULE);
--- a/lustre/osp/osp_dev.c
+++ b/lustre/osp/osp_dev.c
@@ -1648,12 +1648,18 @@ static int osp_iocontrol(unsigned int cm
 {
 	struct obd_device *obd = exp->exp_obd;
 	struct osp_device *d;
-	struct obd_ioctl_data *data = karg;
+	struct obd_ioctl_data *data;
 	int rc = -EINVAL;
 
 	ENTRY;
 	CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
 	       exp->exp_obd->obd_name, cmd, len, karg, uarg);
+	if (unlikely(karg == NULL)) {
+		CERROR("%s: iocontrol from '%s' cmd=%x karg=NULL: rc = %d\n",
+		       obd->obd_name, current->comm, cmd, rc);
+		RETURN(rc);
+	}
+	data = karg;
 
 	LASSERT(obd->obd_lu_dev);
 	d = lu2osp_dev(obd->obd_lu_dev);
--- a/lustre/tests/group_lock_test.c
+++ b/lustre/tests/group_lock_test.c
@@ -286,23 +286,23 @@ static void helper_test20(int fd)
 
 	gid = 1234;
 	rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
-	ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
-		rc, strerror(errno));
+	ASSERTF(rc == -1 && (errno == ENOTTY || errno == EINVAL),
+		"unexpected retval: %d %s", rc, strerror(errno));
 
 	gid = 0;
 	rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
-	ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
-		rc, strerror(errno));
+	ASSERTF(rc == -1 && (errno == ENOTTY || errno == EINVAL),
+		"unexpected retval: %d %s", rc, strerror(errno));
 
 	gid = 1;
 	rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
-	ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
-		rc, strerror(errno));
+	ASSERTF(rc == -1 && (errno == ENOTTY || errno == EINVAL),
+		"unexpected retval: %d %s", rc, strerror(errno));
 
 	gid = -1;
 	rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
-	ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
-		rc, strerror(errno));
+	ASSERTF(rc == -1 && (errno == ENOTTY || errno == EINVAL),
+		"unexpected retval: %d %s", rc, strerror(errno));
 }
 
 /* Test lock / unlock on a directory */
openSUSE Build Service is sponsored by