nvmf/subsystem: spdk_nvmf_valid_nqn fits nvme spec
Added tighter regulations to the NVMe-oF nqn checking to conform with the nvme 1.3 spec. including, adding checks for valid nqn's in the case of a generic uuid based nqn and checking for reverse domain name and colon prefixed strings in a user specific nqn. Unit tests included. Change-Id: I3ee4b269d0655ac9968699617e43e3297695c7ed Signed-off-by: Seth Howell <seth.howell@intel.com> Reviewed-on: https://review.gerrithub.io/393265 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
fce8466477
commit
b21fad1a80
@ -322,9 +322,15 @@ struct spdk_nvmf_fabric_prop_set_cmd {
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_prop_set_cmd) == 64, "Incorrect size");
|
||||
|
||||
#define SPDK_NVMF_NQN_MIN_LEN 11 /* The prefix in the spec is 11 characters */
|
||||
#define SPDK_NVMF_NQN_MAX_LEN 223
|
||||
#define SPDK_NVMF_NQN_UUID_PRE_LEN 32
|
||||
#define SPDK_NVMF_UUID_STRING_LEN 36
|
||||
#define SPDK_NVMF_NQN_UUID_PRE "nqn.2014-08.org.nvmexpress:uuid:"
|
||||
#define SPDK_NVMF_DISCOVERY_NQN "nqn.2014-08.org.nvmexpress.discovery"
|
||||
|
||||
#define SPDK_DOMAIN_LABEL_MAX_LEN 63 /* RFC 1034 max domain label length */
|
||||
|
||||
#define SPDK_NVMF_TRADDR_MAX_LEN 256
|
||||
#define SPDK_NVMF_TRSVCID_MAX_LEN 32
|
||||
|
||||
|
@ -45,29 +45,159 @@
|
||||
#include "spdk_internal/bdev.h"
|
||||
#include "spdk_internal/log.h"
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
/*
|
||||
* States for parsing valid domains in NQNs according to RFC 1034
|
||||
*/
|
||||
enum spdk_nvmf_nqn_domain_states {
|
||||
/* First character of a domain must be a letter */
|
||||
SPDK_NVMF_DOMAIN_ACCEPT_LETTER = 0,
|
||||
|
||||
/* Subsequent characters can be any of letter, digit, or hyphen */
|
||||
SPDK_NVMF_DOMAIN_ACCEPT_LDH = 1,
|
||||
|
||||
/* A domain label must end with either a letter or digit */
|
||||
SPDK_NVMF_DOMAIN_ACCEPT_ANY = 2
|
||||
};
|
||||
|
||||
static bool
|
||||
spdk_nvmf_valid_nqn(const char *nqn)
|
||||
{
|
||||
size_t len;
|
||||
uuid_t uuid_value;
|
||||
uint i;
|
||||
uint domain_label_length;
|
||||
char *reverse_domain_end;
|
||||
uint reverse_domain_end_index;
|
||||
enum spdk_nvmf_nqn_domain_states domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
|
||||
|
||||
/* Check for length requirements */
|
||||
len = strlen(nqn);
|
||||
if (len > SPDK_NVMF_NQN_MAX_LEN) {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The nqn must be at least as long as SPDK_NVMF_NQN_MIN_LEN to contain the necessary prefix. */
|
||||
if (len < SPDK_NVMF_NQN_MIN_LEN) {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\": length %zu < min %d\n", nqn, len, SPDK_NVMF_NQN_MIN_LEN);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check for discovery controller nqn */
|
||||
if (!strcmp(nqn, SPDK_NVMF_DISCOVERY_NQN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check for equality with the generic nqn structure of the form "nqn.2014-08.org.nvmexpress:uuid:11111111-2222-3333-4444-555555555555" */
|
||||
if (!strncmp(nqn, SPDK_NVMF_NQN_UUID_PRE, SPDK_NVMF_NQN_UUID_PRE_LEN)) {
|
||||
if (len != SPDK_NVMF_NQN_UUID_PRE_LEN + SPDK_NVMF_UUID_STRING_LEN) {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not the correct length\n", nqn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uuid_parse(&nqn[SPDK_NVMF_NQN_UUID_PRE_LEN], uuid_value) == -1) {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not formatted correctly\n", nqn);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the nqn does not match the uuid structure, the next several checks validate the form "nqn.yyyy-mm.reverse.domain:user-string" */
|
||||
|
||||
if (strncmp(nqn, "nqn.", 4) != 0) {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* yyyy-mm. */
|
||||
/* Check for yyyy-mm. */
|
||||
if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) &&
|
||||
nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) {
|
||||
SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn);
|
||||
return false;
|
||||
}
|
||||
|
||||
reverse_domain_end = strchr(nqn, ':');
|
||||
if (reverse_domain_end != NULL && (reverse_domain_end_index = reverse_domain_end - nqn) < len - 1) {
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid NQN \"%s\". NQN must contain user specified name with a ':' as a prefix.\n",
|
||||
nqn);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check for valid reverse domain */
|
||||
domain_label_length = 0;
|
||||
for (i = 12; i < reverse_domain_end_index; i++) {
|
||||
if (domain_label_length > SPDK_DOMAIN_LABEL_MAX_LEN) {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". At least one Label is too long.\n", nqn);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (domain_state) {
|
||||
|
||||
case SPDK_NVMF_DOMAIN_ACCEPT_LETTER: {
|
||||
if (isalpha(nqn[i])) {
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
|
||||
domain_label_length++;
|
||||
break;
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must start with a letter.\n", nqn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case SPDK_NVMF_DOMAIN_ACCEPT_LDH: {
|
||||
if (isalpha(nqn[i]) || isdigit(nqn[i])) {
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
|
||||
domain_label_length++;
|
||||
break;
|
||||
} else if (nqn[i] == '-') {
|
||||
if (i == reverse_domain_end_index - 1) {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
|
||||
nqn);
|
||||
return false;
|
||||
}
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
|
||||
domain_label_length++;
|
||||
break;
|
||||
} else if (nqn[i] == '.') {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
|
||||
nqn);
|
||||
return false;
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
|
||||
nqn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case SPDK_NVMF_DOMAIN_ACCEPT_ANY: {
|
||||
if (isalpha(nqn[i]) || isdigit(nqn[i])) {
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
|
||||
domain_label_length++;
|
||||
break;
|
||||
} else if (nqn[i] == '-') {
|
||||
if (i == reverse_domain_end_index - 1) {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
|
||||
nqn);
|
||||
return false;
|
||||
}
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
|
||||
domain_label_length++;
|
||||
break;
|
||||
} else if (nqn[i] == '.') {
|
||||
domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
|
||||
domain_label_length = 0;
|
||||
break;
|
||||
} else {
|
||||
SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
|
||||
nqn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -244,6 +244,60 @@ nvmf_test_create_subsystem(void)
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_subsystem_destroy(subsystem);
|
||||
|
||||
/* valid name with complex reverse domain */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
|
||||
/* Valid name discovery controller */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
|
||||
|
||||
/* Invalid name, no user supplied string */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Valid name, only contains top-level domain name */
|
||||
strncpy(nqn, "nqn.2016-06.io:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
|
||||
/* Invalid name, domain label > 63 characters */
|
||||
strncpy(nqn,
|
||||
"nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub",
|
||||
sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid name, domain label starts with digit */
|
||||
strncpy(nqn, "nqn.2016-06.io.3spdk:sub", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid name, domain label starts with - */
|
||||
strncpy(nqn, "nqn.2016-06.io.-spdk:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid name, domain label ends with - */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk-:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid name, domain label with multiple consecutive periods */
|
||||
strncpy(nqn, "nqn.2016-06.io..spdk:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Longest valid name */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:", sizeof(nqn));
|
||||
memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn));
|
||||
@ -254,7 +308,7 @@ nvmf_test_create_subsystem(void)
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_subsystem_destroy(subsystem);
|
||||
|
||||
/* Name that is one byte longer than allowed */
|
||||
/* Invalid name, too long */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:", sizeof(nqn));
|
||||
memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn));
|
||||
nqn[224] = '\0';
|
||||
@ -262,6 +316,29 @@ nvmf_test_create_subsystem(void)
|
||||
subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
CU_ASSERT(subsystem == NULL);
|
||||
|
||||
/* Valid name using uuid format */
|
||||
strncpy(nqn, "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
|
||||
/* Invalid uuid (too long) */
|
||||
strncpy(nqn, "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef",
|
||||
sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid uuid (dashes placed incorrectly) */
|
||||
strncpy(nqn, "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
/* Invalid uuid (invalid characters in uuid) */
|
||||
strncpy(nqn, "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem == NULL);
|
||||
|
||||
free(tgt.subsystems);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user