Commit aa03cfe9 authored by Jens Axboe's avatar Jens Axboe
Browse files

Merge tag 'nvme-7.1-2026-04-24' of git://git.infradead.org/nvme into block-7.1

Pull NVMe fixes from Keith:

"- Target data transfer size confiruation (Aurelien)
 - Enable P2P for RDMA (Shivaji Kant)
 - TCP target updates (Maurizio, Alistair, Chaitanya, Shivam Kumar)
 - TCP host updates (Alistair, Chaitanya)
 - Authentication updates (Alistair, Daniel, Chris Leech)
 - Multipath fixes (John Garry)
 - New quirks (Alan Cui, Tao Jiang)
 - Apple driver fix (Fedor Pchelkin)
 - PCI admin doorbell update fix (Keith)"

* tag 'nvme-7.1-2026-04-24' of git://git.infradead.org/nvme: (22 commits)
  nvme-auth: Hash DH shared secret to create session key
  nvme-pci: fix missed admin queue sq doorbell write
  nvme-auth: Include SC_C in RVAL controller hash
  nvme-tcp: teardown circular locking fixes
  nvmet-tcp: Don't clear tls_key when freeing sq
  Revert "nvmet-tcp: Don't free SQ on authentication success"
  nvme: skip trace completion for host path errors
  nvme-pci: add quirk for Memblaze Pblaze5 (0x1c5f:0x0555)
  nvme-multipath: put module reference when delayed removal work is canceled
  nvme: expose TLS mode
  nvme-apple: drop invalid put of admin queue reference count
  nvme-core: fix parameter name in comment
  nvmet: avoid recursive nvmet-wq flush in nvmet_ctrl_free
  nvme-multipath: drop head pointer check in nvme_mpath_clear_current_path()
  nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung PM981/983/970 EVO Plus )
  nvmet-tcp: fix race between ICReq handling and queue teardown
  nvmet-tcp: remove redundant calls to nvmet_tcp_fatal_error()
  nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its callers
  nvme: enable PCI P2PDMA support for RDMA transport
  nvmet: introduce new mdts configuration entry
  ...
parents 254f4963 bd7b7ce9
Loading
Loading
Loading
Loading
+74 −20
Original line number Diff line number Diff line
@@ -351,18 +351,29 @@ struct nvme_dhchap_key *nvme_auth_transform_key(
}
EXPORT_SYMBOL_GPL(nvme_auth_transform_key);

/**
 * nvme_auth_augmented_challenge() - Compute the augmented DH-HMAC-CHAP challenge
 * @hmac_id: Hash algorithm identifier
 * @skey: Session key
 * @skey_len: Length of @skey
 * @challenge: Challenge value
 * @aug: Output buffer for the augmented challenge
 * @hlen: Hash output length (length of @challenge and @aug)
 *
 * NVMe base specification 8.3.5.5.4: The augmented challenge is computed
 * applying the HMAC function using the hash function H() selected by the
 * HashID parameter ... with the hash of the ephemeral DH key ... as HMAC key
 * to the challenge C (i.e., Ca = HMAC(H(g^xy mod p), C)).
 *
 * As the session key skey is already H(g^xy mod p) per section 8.3.5.5.9, use
 * it directly as the HMAC key without additional hashing.
 *
 * Return: 0 on success, negative errno on failure.
 */
int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len,
				  const u8 *challenge, u8 *aug, size_t hlen)
{
	u8 hashed_key[NVME_AUTH_MAX_DIGEST_SIZE];
	int ret;

	ret = nvme_auth_hash(hmac_id, skey, skey_len, hashed_key);
	if (ret)
		return ret;
	ret = nvme_auth_hmac(hmac_id, hashed_key, hlen, challenge, hlen, aug);
	memzero_explicit(hashed_key, sizeof(hashed_key));
	return ret;
	return nvme_auth_hmac(hmac_id, skey, skey_len, challenge, hlen, aug);
}
EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);

@@ -403,33 +414,76 @@ int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);

int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
		const u8 *ctrl_key, size_t ctrl_key_len,
		u8 *sess_key, size_t sess_key_len)
/**
 * nvme_auth_gen_session_key() - Generate an ephemeral session key
 * @dh_tfm: Diffie-Hellman transform with local private key already set
 * @public_key: Peer's public key
 * @public_key_len: Length of @public_key
 * @sess_key: Output buffer for the session key
 * @sess_key_len: Size of @sess_key buffer
 * @hash_id: Hash algorithm identifier
 *
 * NVMe base specification 8.3.5.5.9: The session key Ks shall be computed from
 * the ephemeral DH key (i.e., g^xy mod p) ... by applying the hash function
 * H() selected by the HashID parameter ... (i.e., Ks = H(g^xy mod p)).
 *
 * Return: 0 on success, negative errno on failure.
 */
int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm,
		const u8 *public_key, size_t public_key_len,
		u8 *sess_key, size_t sess_key_len, u8 hash_id)
{
	struct kpp_request *req;
	struct crypto_wait wait;
	struct scatterlist src, dst;
	u8 *dh_secret;
	size_t dh_secret_len, hash_len;
	int ret;

	req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
	if (!req)
	hash_len = nvme_auth_hmac_hash_len(hash_id);
	if (!hash_len) {
		pr_warn("%s: invalid hash algorithm %d\n", __func__, hash_id);
		return -EINVAL;
	}

	if (sess_key_len != hash_len) {
		pr_warn("%s: sess_key buffer missized (%zu != %zu)\n",
			__func__, sess_key_len, hash_len);
		return -EINVAL;
	}

	dh_secret_len = crypto_kpp_maxsize(dh_tfm);
	dh_secret = kzalloc(dh_secret_len, GFP_KERNEL);
	if (!dh_secret)
		return -ENOMEM;

	req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
	if (!req) {
		ret = -ENOMEM;
		goto out_free_secret;
	}

	crypto_init_wait(&wait);
	sg_init_one(&src, ctrl_key, ctrl_key_len);
	kpp_request_set_input(req, &src, ctrl_key_len);
	sg_init_one(&dst, sess_key, sess_key_len);
	kpp_request_set_output(req, &dst, sess_key_len);
	sg_init_one(&src, public_key, public_key_len);
	kpp_request_set_input(req, &src, public_key_len);
	sg_init_one(&dst, dh_secret, dh_secret_len);
	kpp_request_set_output(req, &dst, dh_secret_len);
	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
				 crypto_req_done, &wait);

	ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);

	kpp_request_free(req);

	if (ret)
		goto out_free_secret;

	ret = nvme_auth_hash(hash_id, dh_secret, dh_secret_len, sess_key);

out_free_secret:
	kfree_sensitive(dh_secret);
	return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);
EXPORT_SYMBOL_GPL(nvme_auth_gen_session_key);

int nvme_auth_parse_key(const char *secret, struct nvme_dhchap_key **ret_key)
{
+1 −5
Original line number Diff line number Diff line
@@ -1267,11 +1267,7 @@ static int apple_nvme_get_address(struct nvme_ctrl *ctrl, char *buf, int size)

static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl)
{
	struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl);

	if (anv->ctrl.admin_q)
		blk_put_queue(anv->ctrl.admin_q);
	put_device(anv->dev);
	put_device(ctrl->dev);
}

static const struct nvme_ctrl_ops nvme_ctrl_ops = {
+9 −7
Original line number Diff line number Diff line
@@ -535,11 +535,12 @@ static int nvme_auth_dhchap_setup_ctrl_response(struct nvme_ctrl *ctrl,
	put_unaligned_le16(chap->transaction, buf);
	nvme_auth_hmac_update(&hmac, buf, 2);

	memset(buf, 0, 4);
	*buf = chap->sc_c;
	nvme_auth_hmac_update(&hmac, buf, 1);
	nvme_auth_hmac_update(&hmac, "Controller", 10);
	nvme_auth_hmac_update(&hmac, ctrl->opts->subsysnqn,
			      strlen(ctrl->opts->subsysnqn));
	memset(buf, 0, 4);
	nvme_auth_hmac_update(&hmac, buf, 1);
	nvme_auth_hmac_update(&hmac, ctrl->opts->host->nqn,
			      strlen(ctrl->opts->host->nqn));
@@ -587,7 +588,7 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
	}

gen_sesskey:
	chap->sess_key_len = chap->host_key_len;
	chap->sess_key_len = chap->hash_len;
	chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL);
	if (!chap->sess_key) {
		chap->sess_key_len = 0;
@@ -595,16 +596,17 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
		return -ENOMEM;
	}

	ret = nvme_auth_gen_shared_secret(chap->dh_tfm,
	ret = nvme_auth_gen_session_key(chap->dh_tfm,
					chap->ctrl_key, chap->ctrl_key_len,
					  chap->sess_key, chap->sess_key_len);
					chap->sess_key, chap->sess_key_len,
					chap->hash_id);
	if (ret) {
		dev_dbg(ctrl->device,
			"failed to generate shared secret, error %d\n", ret);
			"failed to generate session key, error %d\n", ret);
		chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
		return ret;
	}
	dev_dbg(ctrl->device, "shared secret %*ph\n",
	dev_dbg(ctrl->device, "session key %*ph\n",
		(int)chap->sess_key_len, chap->sess_key);
	return 0;
}
+11 −5
Original line number Diff line number Diff line
@@ -454,11 +454,10 @@ void nvme_end_req(struct request *req)
	blk_mq_end_request(req, status);
}

void nvme_complete_rq(struct request *req)
static void __nvme_complete_rq(struct request *req)
{
	struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;

	trace_nvme_complete_rq(req);
	nvme_cleanup_cmd(req);

	/*
@@ -493,6 +492,12 @@ void nvme_complete_rq(struct request *req)
		return;
	}
}

void nvme_complete_rq(struct request *req)
{
	trace_nvme_complete_rq(req);
	__nvme_complete_rq(req);
}
EXPORT_SYMBOL_GPL(nvme_complete_rq);

void nvme_complete_batch_req(struct request *req)
@@ -513,7 +518,7 @@ blk_status_t nvme_host_path_error(struct request *req)
{
	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
	blk_mq_set_request_complete(req);
	nvme_complete_rq(req);
	__nvme_complete_rq(req);
	return BLK_STS_OK;
}
EXPORT_SYMBOL_GPL(nvme_host_path_error);
@@ -3044,7 +3049,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = {
		 *
		 * The device is left in a state where it is also not possible
		 * to use "nvme set-feature" to disable APST, but booting with
		 * nvme_core.default_ps_max_latency=0 works.
		 * nvme_core.default_ps_max_latency_us=0 works.
		 */
		.vid = 0x1e0f,
		.mn = "KCD6XVUL6T40",
@@ -4083,7 +4088,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
	mutex_unlock(&ctrl->subsys->lock);

#ifdef CONFIG_NVME_MULTIPATH
	cancel_delayed_work(&head->remove_work);
	if (cancel_delayed_work(&head->remove_work))
		module_put(THIS_MODULE);
#endif
	return 0;

+1 −0
Original line number Diff line number Diff line
@@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module);

MODULE_DESCRIPTION("NVMe host FC transport driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("nvme-fc");
Loading