[PATCH] nvme-auth: isolate auth to fabrics transports

Keith Busch kbusch at meta.com
Mon Dec 18 14:16:13 PST 2023


From: Keith Busch <kbusch at kernel.org>

Some transports don't use authentication, so contain the resources and
handling for it to fabrics that do use it.

Signed-off-by: Keith Busch <kbusch at kernel.org>
---
 drivers/nvme/host/auth.c  | 112 +++++++++++++++++++++++---------------
 drivers/nvme/host/core.c  |  23 ++++++--
 drivers/nvme/host/nvme.h  |  26 ++++++---
 drivers/nvme/host/sysfs.c |  24 ++++----
 4 files changed, 116 insertions(+), 69 deletions(-)

diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index 72c0525c75f50..023cac4cbc20b 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -312,7 +312,7 @@ static int nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
 	data->hl = chap->hash_len;
 	data->dhvlen = cpu_to_le16(chap->host_key_len);
 	memcpy(data->rval, chap->response, chap->hash_len);
-	if (ctrl->ctrl_key) {
+	if (ctrl->auth->ctrl_key) {
 		chap->bi_directional = true;
 		get_random_bytes(chap->c2, chap->hash_len);
 		data->cvalid = 1;
@@ -427,7 +427,8 @@ static int nvme_auth_dhchap_setup_host_response(struct nvme_ctrl *ctrl,
 		__func__, chap->qid, chap->s1, chap->transaction);
 
 	if (!chap->transformed_key) {
-		chap->transformed_key = nvme_auth_transform_key(ctrl->host_key,
+		chap->transformed_key = nvme_auth_transform_key(
+						ctrl->auth->host_key,
 						ctrl->opts->host->nqn);
 		if (IS_ERR(chap->transformed_key)) {
 			ret = PTR_ERR(chap->transformed_key);
@@ -510,7 +511,7 @@ static int nvme_auth_dhchap_setup_ctrl_response(struct nvme_ctrl *ctrl,
 	u8 buf[4], *challenge = chap->c2;
 	int ret;
 
-	transformed_key = nvme_auth_transform_key(ctrl->ctrl_key,
+	transformed_key = nvme_auth_transform_key(ctrl->auth->ctrl_key,
 				ctrl->opts->subsysnqn);
 	if (IS_ERR(transformed_key)) {
 		ret = PTR_ERR(transformed_key);
@@ -696,7 +697,7 @@ static void nvme_queue_auth_work(struct work_struct *work)
 		return;
 	}
 
-	chap->transaction = ctrl->transaction++;
+	chap->transaction = ctrl->auth->transaction++;
 
 	/* DH-HMAC-CHAP Step 1: send negotiate */
 	dev_dbg(ctrl->device, "%s: qid %d send negotiate\n",
@@ -755,9 +756,9 @@ static void nvme_queue_auth_work(struct work_struct *work)
 
 	dev_dbg(ctrl->device, "%s: qid %d host response\n",
 		__func__, chap->qid);
-	mutex_lock(&ctrl->dhchap_auth_mutex);
+	mutex_lock(&ctrl->auth->dhchap_auth_mutex);
 	ret = nvme_auth_dhchap_setup_host_response(ctrl, chap);
-	mutex_unlock(&ctrl->dhchap_auth_mutex);
+	mutex_unlock(&ctrl->auth->dhchap_auth_mutex);
 	if (ret) {
 		chap->error = ret;
 		goto fail2;
@@ -802,19 +803,19 @@ static void nvme_queue_auth_work(struct work_struct *work)
 		return;
 	}
 
-	mutex_lock(&ctrl->dhchap_auth_mutex);
-	if (ctrl->ctrl_key) {
+	mutex_lock(&ctrl->auth->dhchap_auth_mutex);
+	if (ctrl->auth->ctrl_key) {
 		dev_dbg(ctrl->device,
 			"%s: qid %d controller response\n",
 			__func__, chap->qid);
 		ret = nvme_auth_dhchap_setup_ctrl_response(ctrl, chap);
 		if (ret) {
-			mutex_unlock(&ctrl->dhchap_auth_mutex);
+			mutex_unlock(&ctrl->auth->dhchap_auth_mutex);
 			chap->error = ret;
 			goto fail2;
 		}
 	}
-	mutex_unlock(&ctrl->dhchap_auth_mutex);
+	mutex_unlock(&ctrl->auth->dhchap_auth_mutex);
 
 	ret = nvme_auth_process_dhchap_success1(ctrl, chap);
 	if (ret) {
@@ -855,18 +856,22 @@ static void nvme_queue_auth_work(struct work_struct *work)
 int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
 {
 	struct nvme_dhchap_queue_context *chap;
+	struct nvme_auth *auth = ctrl->auth;
 
-	if (!ctrl->host_key) {
+	if (!auth)
+		return -ENOTSUPP;
+
+	if (!auth->host_key) {
 		dev_warn(ctrl->device, "qid %d: no key\n", qid);
 		return -ENOKEY;
 	}
 
-	if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+	if (ctrl->opts->dhchap_ctrl_secret && !auth->ctrl_key) {
 		dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", qid);
 		return -ENOKEY;
 	}
 
-	chap = &ctrl->dhchap_ctxs[qid];
+	chap = &auth->dhchap_ctxs[qid];
 	cancel_work_sync(&chap->auth_work);
 	queue_work(nvme_auth_wq, &chap->auth_work);
 	return 0;
@@ -876,9 +881,13 @@ EXPORT_SYMBOL_GPL(nvme_auth_negotiate);
 int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid)
 {
 	struct nvme_dhchap_queue_context *chap;
+	struct nvme_auth *auth = ctrl->auth;
 	int ret;
 
-	chap = &ctrl->dhchap_ctxs[qid];
+	if (!auth)
+		return -ENOTSUPP;
+
+	chap = &auth->dhchap_ctxs[qid];
 	flush_work(&chap->auth_work);
 	ret = chap->error;
 	/* clear sensitive info */
@@ -889,8 +898,9 @@ EXPORT_SYMBOL_GPL(nvme_auth_wait);
 
 static void nvme_ctrl_auth_work(struct work_struct *work)
 {
-	struct nvme_ctrl *ctrl =
-		container_of(work, struct nvme_ctrl, dhchap_auth_work);
+	struct nvme_auth *auth =
+		container_of(work, struct nvme_auth, dhchap_auth_work);
+	struct nvme_ctrl *ctrl = auth->ctrl;
 	int ret, q;
 
 	/*
@@ -939,72 +949,86 @@ static void nvme_ctrl_auth_work(struct work_struct *work)
 int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
 {
 	struct nvme_dhchap_queue_context *chap;
+	struct nvme_auth *auth;
 	int i, ret;
 
-	mutex_init(&ctrl->dhchap_auth_mutex);
-	INIT_WORK(&ctrl->dhchap_auth_work, nvme_ctrl_auth_work);
-	if (!ctrl->opts)
+	if (!ctrl->opts || !(ctrl->ops->flags & NVME_F_FABRICS))
 		return 0;
+
+	auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+	if (!auth)
+		return -ENOMEM;
+
+	mutex_init(&auth->dhchap_auth_mutex);
+	INIT_WORK(&auth->dhchap_auth_work, nvme_ctrl_auth_work);
+
 	ret = nvme_auth_generate_key(ctrl->opts->dhchap_secret,
-			&ctrl->host_key);
+			&auth->host_key);
 	if (ret)
-		return ret;
+		goto err_free_auth;
 	ret = nvme_auth_generate_key(ctrl->opts->dhchap_ctrl_secret,
-			&ctrl->ctrl_key);
+			&auth->ctrl_key);
 	if (ret)
 		goto err_free_dhchap_secret;
 
 	if (!ctrl->opts->dhchap_secret && !ctrl->opts->dhchap_ctrl_secret)
-		return 0;
+		goto ok;
 
-	ctrl->dhchap_ctxs = kvcalloc(ctrl_max_dhchaps(ctrl),
+	auth->dhchap_ctxs = kvcalloc(ctrl_max_dhchaps(ctrl),
 				sizeof(*chap), GFP_KERNEL);
-	if (!ctrl->dhchap_ctxs) {
+	if (!auth->dhchap_ctxs) {
 		ret = -ENOMEM;
 		goto err_free_dhchap_ctrl_secret;
 	}
 
 	for (i = 0; i < ctrl_max_dhchaps(ctrl); i++) {
-		chap = &ctrl->dhchap_ctxs[i];
+		chap = &auth->dhchap_ctxs[i];
 		chap->qid = i;
 		chap->ctrl = ctrl;
 		INIT_WORK(&chap->auth_work, nvme_queue_auth_work);
 	}
 
+ok:
+	auth->ctrl = ctrl;
+	ctrl->auth = auth;
 	return 0;
 err_free_dhchap_ctrl_secret:
-	nvme_auth_free_key(ctrl->ctrl_key);
-	ctrl->ctrl_key = NULL;
+	nvme_auth_free_key(auth->ctrl_key);
 err_free_dhchap_secret:
-	nvme_auth_free_key(ctrl->host_key);
-	ctrl->host_key = NULL;
+	nvme_auth_free_key(auth->host_key);
+err_free_auth:
+	kfree(auth);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_auth_init_ctrl);
 
-void nvme_auth_stop(struct nvme_ctrl *ctrl)
+void __nvme_auth_stop(struct nvme_auth *auth)
 {
-	cancel_work_sync(&ctrl->dhchap_auth_work);
+	cancel_work_sync(&auth->dhchap_auth_work);
 }
-EXPORT_SYMBOL_GPL(nvme_auth_stop);
+EXPORT_SYMBOL_GPL(__nvme_auth_stop);
 
 void nvme_auth_free(struct nvme_ctrl *ctrl)
 {
+	struct nvme_auth *auth = ctrl->auth;
 	int i;
 
-	if (ctrl->dhchap_ctxs) {
+	if (!auth)
+		return;
+
+	if (auth->dhchap_ctxs) {
 		for (i = 0; i < ctrl_max_dhchaps(ctrl); i++)
-			nvme_auth_free_dhchap(&ctrl->dhchap_ctxs[i]);
-		kfree(ctrl->dhchap_ctxs);
-	}
-	if (ctrl->host_key) {
-		nvme_auth_free_key(ctrl->host_key);
-		ctrl->host_key = NULL;
-	}
-	if (ctrl->ctrl_key) {
-		nvme_auth_free_key(ctrl->ctrl_key);
-		ctrl->ctrl_key = NULL;
+			nvme_auth_free_dhchap(&auth->dhchap_ctxs[i]);
+		kfree(auth->dhchap_ctxs);
 	}
+
+	if (auth->host_key)
+		nvme_auth_free_key(auth->host_key);
+	if (auth->ctrl_key)
+		nvme_auth_free_key(auth->ctrl_key);
+
+	ctrl->auth = NULL;
+	kfree(auth);
 }
 EXPORT_SYMBOL_GPL(nvme_auth_free);
 
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 590cd4f097c22..1746ddc03595a 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -390,6 +390,22 @@ static inline void nvme_end_req(struct request *req)
 	blk_mq_end_request(req, status);
 }
 
+#ifdef CONFIG_NVME_HOST_AUTH
+static inline void nvme_auth_req(struct nvme_ctrl *ctrl, struct request *req)
+{
+	if (ctrl->auth) {
+		queue_work(nvme_wq, &ctrl->auth->dhchap_auth_work);
+		nvme_retry_req(req);
+	} else
+		nvme_end_req(req);
+}
+#else
+static inline void nvme_auth_req(struct nvme_ctrl *ctrl, struct request *req)
+{
+	nvme_end_req(req);
+}
+#endif
+
 void nvme_complete_rq(struct request *req)
 {
 	struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;
@@ -420,12 +436,7 @@ void nvme_complete_rq(struct request *req)
 		nvme_failover_req(req);
 		return;
 	case AUTHENTICATE:
-#ifdef CONFIG_NVME_HOST_AUTH
-		queue_work(nvme_wq, &ctrl->dhchap_auth_work);
-		nvme_retry_req(req);
-#else
-		nvme_end_req(req);
-#endif
+		nvme_auth_req(ctrl, req);
 		return;
 	}
 }
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 39a90b7cb1254..7476fa0215c3f 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -253,6 +253,16 @@ enum nvme_ctrl_flags {
 	NVME_CTRL_DIRTY_CAPABILITY	= 5,
 };
 
+struct nvme_auth {
+	struct nvme_ctrl *ctrl;
+	struct work_struct dhchap_auth_work;
+	struct mutex dhchap_auth_mutex;
+	struct nvme_dhchap_queue_context *dhchap_ctxs;
+	struct nvme_dhchap_key *host_key;
+	struct nvme_dhchap_key *ctrl_key;
+	u16 transaction;
+};
+
 struct nvme_ctrl {
 	bool comp_seen;
 	bool identified;
@@ -350,12 +360,7 @@ struct nvme_ctrl {
 #endif
 
 #ifdef CONFIG_NVME_HOST_AUTH
-	struct work_struct dhchap_auth_work;
-	struct mutex dhchap_auth_mutex;
-	struct nvme_dhchap_queue_context *dhchap_ctxs;
-	struct nvme_dhchap_key *host_key;
-	struct nvme_dhchap_key *ctrl_key;
-	u16 transaction;
+	struct nvme_auth *auth;
 #endif
 	struct key *tls_key;
 
@@ -1053,7 +1058,14 @@ static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl)
 int __init nvme_init_auth(void);
 void __exit nvme_exit_auth(void);
 int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl);
-void nvme_auth_stop(struct nvme_ctrl *ctrl);
+void __nvme_auth_stop(struct nvme_auth *auth);
+
+static inline void nvme_auth_stop(struct nvme_ctrl *ctrl)
+{
+	if (ctrl->auth)
+		__nvme_auth_stop(ctrl->auth);
+}
+
 int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid);
 int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid);
 void nvme_auth_free(struct nvme_ctrl *ctrl);
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index c6b7fbd4d34dd..a2f5f8a341866 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -451,16 +451,16 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
 		}
 		kfree(opts->dhchap_secret);
 		opts->dhchap_secret = dhchap_secret;
-		host_key = ctrl->host_key;
-		mutex_lock(&ctrl->dhchap_auth_mutex);
-		ctrl->host_key = key;
-		mutex_unlock(&ctrl->dhchap_auth_mutex);
+		host_key = ctrl->auth->host_key;
+		mutex_lock(&ctrl->auth->dhchap_auth_mutex);
+		ctrl->auth->host_key = key;
+		mutex_unlock(&ctrl->auth->dhchap_auth_mutex);
 		nvme_auth_free_key(host_key);
 	} else
 		kfree(dhchap_secret);
 	/* Start re-authentication */
 	dev_info(ctrl->device, "re-authenticating controller\n");
-	queue_work(nvme_wq, &ctrl->dhchap_auth_work);
+	queue_work(nvme_wq, &ctrl->auth->dhchap_auth_work);
 
 	return count;
 }
@@ -509,16 +509,16 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
 		}
 		kfree(opts->dhchap_ctrl_secret);
 		opts->dhchap_ctrl_secret = dhchap_secret;
-		ctrl_key = ctrl->ctrl_key;
-		mutex_lock(&ctrl->dhchap_auth_mutex);
-		ctrl->ctrl_key = key;
-		mutex_unlock(&ctrl->dhchap_auth_mutex);
+		ctrl_key = ctrl->auth->ctrl_key;
+		mutex_lock(&ctrl->auth->dhchap_auth_mutex);
+		ctrl->auth->ctrl_key = key;
+		mutex_unlock(&ctrl->auth->dhchap_auth_mutex);
 		nvme_auth_free_key(ctrl_key);
 	} else
 		kfree(dhchap_secret);
 	/* Start re-authentication */
 	dev_info(ctrl->device, "re-authenticating controller\n");
-	queue_work(nvme_wq, &ctrl->dhchap_auth_work);
+	queue_work(nvme_wq, &ctrl->auth->dhchap_auth_work);
 
 	return count;
 }
@@ -594,9 +594,9 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
 	if (a == &dev_attr_fast_io_fail_tmo.attr && !ctrl->opts)
 		return 0;
 #ifdef CONFIG_NVME_HOST_AUTH
-	if (a == &dev_attr_dhchap_secret.attr && !ctrl->opts)
+	if (a == &dev_attr_dhchap_secret.attr && !ctrl->auth)
 		return 0;
-	if (a == &dev_attr_dhchap_ctrl_secret.attr && !ctrl->opts)
+	if (a == &dev_attr_dhchap_ctrl_secret.attr && !ctrl->auth)
 		return 0;
 #endif
 #ifdef CONFIG_NVME_TCP_TLS
-- 
2.34.1




More information about the Linux-nvme mailing list