Commit 0a6bb8ca authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

nvmf: process in-band authentication



The target will request the host to authenticate if its dhchap_key is
set.  Until the authentication is completed, any commands besides
AUTHENTICATION_{SEND,RECV} will result in an AUTH_REQUIRED error.

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I8e68f0b81d841bfdc2e42b8f1bfad00af7058b25
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/22656


Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 3f4f8ad0
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_request) == 776, "Incorrect size");
enum spdk_nvmf_qpair_state {
	SPDK_NVMF_QPAIR_UNINITIALIZED = 0,
	SPDK_NVMF_QPAIR_CONNECTING,
	SPDK_NVMF_QPAIR_AUTHENTICATING,
	SPDK_NVMF_QPAIR_ENABLED,
	SPDK_NVMF_QPAIR_DEACTIVATING,
	SPDK_NVMF_QPAIR_ERROR,
@@ -132,6 +133,8 @@ enum spdk_nvmf_qpair_state {

typedef void (*spdk_nvmf_state_change_done)(void *cb_arg, int status);

struct spdk_nvmf_qpair_auth;

struct spdk_nvmf_qpair {
	uint8_t					state; /* ref spdk_nvmf_qpair_state */
	uint8_t					rsvd;
@@ -158,6 +161,7 @@ struct spdk_nvmf_qpair {
	bool					disconnect_started;

	uint16_t				trace_id;
	struct spdk_nvmf_qpair_auth		*auth;
};

struct spdk_nvmf_transport_poll_group {
@@ -476,6 +480,7 @@ static inline bool
spdk_nvmf_qpair_is_active(struct spdk_nvmf_qpair *qpair)
{
	return qpair->state == SPDK_NVMF_QPAIR_CONNECTING ||
	       qpair->state == SPDK_NVMF_QPAIR_AUTHENTICATING ||
	       qpair->state == SPDK_NVMF_QPAIR_ENABLED;
}

+2 −1
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@ SO_VER := 18
SO_MINOR := 0

C_SRCS = ctrlr.c ctrlr_discovery.c ctrlr_bdev.c \
	 subsystem.c nvmf.c nvmf_rpc.c transport.c tcp.c
	 subsystem.c nvmf.c nvmf_rpc.c transport.c tcp.c \
	 auth.c

C_SRCS-$(CONFIG_RDMA) += rdma.c
LIBNAME = nvmf

lib/nvmf/auth.c

0 → 100644
+92 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) 2024 Intel Corporation
 */

#include "spdk/log.h"
#include "spdk/stdinc.h"

#include "nvmf_internal.h"

#define AUTH_ERRLOG(q, fmt, ...) \
	SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, \
		    (q)->qid, ## __VA_ARGS__)
#define AUTH_DEBUGLOG(q, fmt, ...) \
	SPDK_DEBUGLOG(nvmf_auth, "[%s:%s:%u] " fmt, \
		      (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, (q)->qid, ## __VA_ARGS__)

enum nvmf_qpair_auth_state {
	NVMF_QPAIR_AUTH_NEGOTIATE,
};

struct spdk_nvmf_qpair_auth {
	enum nvmf_qpair_auth_state state;
};

static void
nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int dnr)
{
	struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;

	response->status.sct = sct;
	response->status.sc = sc;
	response->status.dnr = dnr;

	spdk_nvmf_request_complete(req);
}

__attribute__((unused)) static const char *
nvmf_auth_get_state_name(enum nvmf_qpair_auth_state state)
{
	static const char *state_names[] = {
		[NVMF_QPAIR_AUTH_NEGOTIATE] = "negotiate",
	};

	return state_names[state];
}

static void
nvmf_auth_set_state(struct spdk_nvmf_qpair *qpair, enum nvmf_qpair_auth_state state)
{
	struct spdk_nvmf_qpair_auth *auth = qpair->auth;

	if (auth->state == state) {
		return;
	}

	AUTH_DEBUGLOG(qpair, "auth state: %s\n", nvmf_auth_get_state_name(state));
	auth->state = state;
}

int
nvmf_auth_request_exec(struct spdk_nvmf_request *req)
{
	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
				   SPDK_NVME_SC_INVALID_OPCODE, 1);

	return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS;
}

int
nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair)
{
	struct spdk_nvmf_qpair_auth *auth;

	assert(qpair->auth == NULL);
	auth = calloc(1, sizeof(*qpair->auth));
	if (auth == NULL) {
		return -ENOMEM;
	}

	qpair->auth = auth;
	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE);

	return 0;
}

void
nvmf_qpair_auth_destroy(struct spdk_nvmf_qpair *qpair)
{
	free(qpair->auth);
	qpair->auth = NULL;
}
SPDK_LOG_REGISTER_COMPONENT(nvmf_auth)
+53 −9
Original line number Diff line number Diff line
@@ -239,13 +239,27 @@ nvmf_ctrlr_send_connect_rsp(void *ctx)
	struct spdk_nvmf_qpair *qpair = req->qpair;
	struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
	struct spdk_nvmf_fabric_connect_rsp *rsp = &req->rsp->connect_rsp;
	int rc;

	/* The qpair might have been disconnected in the meantime */
	assert(qpair->state == SPDK_NVMF_QPAIR_CONNECTING ||
	       qpair->state == SPDK_NVMF_QPAIR_DEACTIVATING);
	if (qpair->state == SPDK_NVMF_QPAIR_CONNECTING) {
		if (nvmf_subsystem_host_auth_required(ctrlr->subsys, ctrlr->hostnqn)) {
			rc = nvmf_qpair_auth_init(qpair);
			if (rc != 0) {
				rsp->status.sct = SPDK_NVME_SCT_GENERIC;
				rsp->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
				spdk_nvmf_request_complete(req);
				spdk_nvmf_qpair_disconnect(qpair);
				return;
			}
			rsp->status_code_specific.success.authreq.atr = 1;
			nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_AUTHENTICATING);
		} else {
			nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED);
		}
	}

	SPDK_DEBUGLOG(nvmf, "connect capsule response: cntlid = 0x%04x\n", ctrlr->cntlid);

@@ -3773,6 +3787,9 @@ nvmf_ctrlr_process_fabrics_cmd(struct spdk_nvmf_request *req)
			return nvmf_property_set(req);
		case SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET:
			return nvmf_property_get(req);
		case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
		case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
			return nvmf_auth_request_exec(req);
		default:
			SPDK_DEBUGLOG(nvmf, "unknown fctype 0x%02x\n",
				      cap_hdr->fctype);
@@ -3781,14 +3798,22 @@ nvmf_ctrlr_process_fabrics_cmd(struct spdk_nvmf_request *req)
			return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
		}
	} else {
		/* Controller session is established, and this is an I/O queue */
		/* For now, no I/O-specific Fabrics commands are implemented (other than Connect) */
		/*
		 * Controller session is established, and this is an I/O queue.
		 * Disallow everything besides authentication commands.
		 */
		switch (cap_hdr->fctype) {
		case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
		case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
			return nvmf_auth_request_exec(req);
		default:
			SPDK_DEBUGLOG(nvmf, "Unexpected I/O fctype 0x%x\n", cap_hdr->fctype);
			req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
			req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_INVALID_OPCODE;
			return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
		}
	}
}

static inline void
nvmf_ctrlr_queue_pending_async_event(struct spdk_nvmf_ctrlr *ctrlr,
@@ -4637,11 +4662,15 @@ static bool
nvmf_check_qpair_active(struct spdk_nvmf_request *req)
{
	struct spdk_nvmf_qpair *qpair = req->qpair;
	int sc, sct;

	if (spdk_likely(qpair->state == SPDK_NVMF_QPAIR_ENABLED)) {
		return true;
	}

	sct = SPDK_NVME_SCT_GENERIC;
	sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR;

	switch (qpair->state) {
	case SPDK_NVMF_QPAIR_CONNECTING:
		if (req->cmd->nvmf_cmd.opcode != SPDK_NVME_OPC_FABRIC) {
@@ -4655,14 +4684,29 @@ nvmf_check_qpair_active(struct spdk_nvmf_request *req)
			break;
		}
		return true;
	case SPDK_NVMF_QPAIR_AUTHENTICATING:
		sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		sc = SPDK_NVMF_FABRIC_SC_AUTH_REQUIRED;
		if (req->cmd->nvmf_cmd.opcode != SPDK_NVME_OPC_FABRIC) {
			SPDK_ERRLOG("Received command 0x%x on qid %u before authentication\n",
				    req->cmd->nvmf_cmd.opcode, qpair->qid);
			break;
		}
		if (req->cmd->nvmf_cmd.fctype != SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND &&
		    req->cmd->nvmf_cmd.fctype != SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV) {
			SPDK_ERRLOG("Received fctype 0x%x on qid %u before authentication\n",
				    req->cmd->nvmf_cmd.fctype, qpair->qid);
			break;
		}
		return true;
	default:
		SPDK_ERRLOG("Received command 0x%x on qid %u in state %d\n",
			    req->cmd->nvmf_cmd.opcode, qpair->qid, qpair->state);
		break;
	}

	req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
	req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR;
	req->rsp->nvme_cpl.status.sct = sct;
	req->rsp->nvme_cpl.status.sc = sc;
	TAILQ_INSERT_TAIL(&qpair->outstanding, req, link);
	_nvmf_request_complete(req);

+1 −0
Original line number Diff line number Diff line
@@ -1354,6 +1354,7 @@ _nvmf_qpair_destroy(void *ctx, int status)
		}
	}

	nvmf_qpair_auth_destroy(qpair);
	qpair_ctx->ctrlr = ctrlr;
	spdk_nvmf_poll_group_remove(qpair);
	nvmf_transport_qpair_fini(qpair, _nvmf_transport_qpair_fini_complete, qpair_ctx);
Loading