Skip to content

Commit 29b151c

Browse files
flaviensigaw
authored andcommitted
libnvme: parse NBFT Security Profile descriptors
Security Profile descriptors are skipped by the current reader. The associated subsystem records lose their security requirements. Parse fields enabled by descriptor flags and keep inactive fields clear. Add a valid parser fixture. Document pointer ownership. Signed-off-by: Flavien Solt <flavien@nus.edu.sg>
1 parent 73da15f commit 29b151c

6 files changed

Lines changed: 159 additions & 1 deletion

File tree

libnvme/src/nvme/nbft.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,34 @@ static int __get_heap_obj(struct libnvme_global_ctx *ctx,
151151
descriptor->obj, is_string, \
152152
output)
153153

154+
/* Point at a raw (non-string) heap object and return its length. */
155+
static int __get_heap_obj_raw(struct libnvme_global_ctx *ctx,
156+
struct nbft_header *header, const char *filename,
157+
const char *descriptorname, const char *fieldname,
158+
struct nbft_heap_obj obj, unsigned char **output, __u16 *length)
159+
{
160+
__u16 obj_length = le16_to_cpu(obj.length);
161+
162+
*output = NULL;
163+
*length = 0;
164+
if (obj_length == 0)
165+
return 0;
166+
if (!in_heap(header, obj)) {
167+
libnvme_msg(ctx, LIBNVME_LOG_DEBUG,
168+
"file %s: field '%s' in descriptor '%s' has invalid offset or length\n",
169+
filename, fieldname, descriptorname);
170+
return -EINVAL;
171+
}
172+
*output = (unsigned char *)header + le32_to_cpu(obj.offset);
173+
*length = obj_length;
174+
return 0;
175+
}
176+
177+
#define get_heap_obj_raw(descriptor, obj, output, length) \
178+
__get_heap_obj_raw(ctx, header, nbft->filename, \
179+
stringify(descriptor), stringify(obj), \
180+
descriptor->obj, output, length)
181+
154182
static struct libnbft_discovery *discovery_from_index(struct libnbft_info *nbft,
155183
int i)
156184
{
@@ -583,7 +611,63 @@ static int read_security(struct libnvme_global_ctx *ctx, struct libnbft_info *nb
583611
struct nbft_security *raw_security,
584612
struct libnbft_security **s)
585613
{
586-
return -EINVAL;
614+
struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
615+
struct libnbft_security *security;
616+
__u16 flags = le16_to_cpu(raw_security->flags);
617+
int ret;
618+
619+
if (!(flags & NBFT_SECURITY_VALID))
620+
return -EINVAL;
621+
verify(ctx, raw_security->structure_id == NBFT_DESC_SECURITY,
622+
"invalid ID in security descriptor");
623+
624+
security = calloc(1, sizeof(*security));
625+
if (!security)
626+
return -ENOMEM;
627+
628+
security->index = raw_security->index;
629+
security->flags = flags;
630+
security->secret_type = raw_security->secret_type;
631+
632+
/* Policy lists point into the raw NBFT heap when enabled. */
633+
ret = 0;
634+
if ((flags & NBFT_SECURITY_SEC_POLICY_LIST_MASK) !=
635+
NBFT_SECURITY_SEC_POLICY_LIST_NOT_SUPPORTED)
636+
ret = get_heap_obj_raw(raw_security, sec_chan_alg_obj,
637+
&security->sec_chan_algs,
638+
&security->sec_chan_algs_len);
639+
if (!ret && (flags & NBFT_SECURITY_AUTH_POLICY_LIST_MASK) !=
640+
NBFT_SECURITY_AUTH_POLICY_LIST_NOT_SUPPORTED)
641+
ret = get_heap_obj_raw(raw_security, auth_proto_obj,
642+
&security->auth_protocols,
643+
&security->auth_protocols_len);
644+
if (!ret && (flags & NBFT_SECURITY_CIPHER_RESTRICTED))
645+
ret = get_heap_obj_raw(raw_security, cipher_suite_obj,
646+
&security->cipher_suites,
647+
&security->cipher_suites_len);
648+
if (!ret && (flags & NBFT_SECURITY_AUTH_DH_GROUPS_RESTRICTED))
649+
ret = get_heap_obj_raw(raw_security, dh_grp_obj,
650+
&security->dh_groups,
651+
&security->dh_groups_len);
652+
if (!ret && (flags & NBFT_SECURITY_SEC_HASH_FUNC_POLICY_LIST))
653+
ret = get_heap_obj_raw(raw_security, sec_hash_func_obj,
654+
&security->sec_hash_funcs,
655+
&security->sec_hash_funcs_len);
656+
if (ret) {
657+
free(security);
658+
return ret;
659+
}
660+
661+
/* The key URI also points into the heap. An absent URI is valid. */
662+
ret = get_heap_obj(ctx, raw_security, sec_keypath_obj, 1,
663+
&security->secret_keypath);
664+
if (ret && ret != -ENOENT) {
665+
free(security);
666+
return ret;
667+
}
668+
669+
*s = security;
670+
return 0;
587671
}
588672

589673
static void read_hfi_descriptors(struct libnvme_global_ctx *ctx,

libnvme/src/nvme/nbft.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ struct libnbft_discovery {
168168
* @secret_keypath: URI string for the secret key path. The type of
169169
* the URI is specified by @secret_type.
170170
* NULL if not present.
171+
*
172+
* All pointer fields refer to storage owned by the parent
173+
* &struct libnbft_info. They must not be freed separately.
171174
*/
172175
struct libnbft_security {
173176
int index;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
raw_nbft_size=641
2+
host.id=11111111111111111111111111111111
3+
host.nqn=nqn.2014-08.org.nvmexpress:uuid:11111111-1111-1111-1111-111111111111
4+
host.flags=0x17
5+
hfi_list[0]->index=1
6+
hfi_list[0]->transport=tcp
7+
hfi_list[0]->tcp_info.pci_sbdf=0
8+
hfi_list[0]->tcp_info.mac_addr=52540123456
9+
hfi_list[0]->tcp_info.vlan=0
10+
hfi_list[0]->tcp_info.ip_origin=0
11+
hfi_list[0]->tcp_info.ipaddr=10.0.2.15
12+
hfi_list[0]->tcp_info.subnet_mask_prefix=24
13+
hfi_list[0]->tcp_info.gateway_ipaddr=10.0.2.2
14+
hfi_list[0]->tcp_info.route_metric=500
15+
hfi_list[0]->tcp_info.primary_dns_ipaddr=::
16+
hfi_list[0]->tcp_info.secondary_dns_ipaddr=::
17+
hfi_list[0]->tcp_info.dhcp_server_ipaddr=
18+
hfi_list[0]->tcp_info.host_name=(null)
19+
hfi_list[0]->tcp_info.flags=0x03
20+
hfi_list[0]->tcp_info.pcie_seg_num=0
21+
hfi_list[0]->tcp_info.dhcp_iaid=0
22+
hfi_list[0]->tcp_info.dhcp_duid=
23+
hfi_list[0]->tcp_info.dhcp_duid_len=0
24+
security_list[0]->index=1
25+
security_list[0]->flags=3413
26+
security_list[0]->secret_type=2
27+
security_list[0]->sec_chan_algs_len=0
28+
security_list[0]->auth_protocols_len=0
29+
security_list[0]->cipher_suites_len=0
30+
security_list[0]->dh_groups_len=0
31+
security_list[0]->sec_hash_funcs_len=0
32+
security_list[0]->secret_keypath=(null)
33+
subsystem_ns_list[0]->index=1
34+
subsystem_ns_list[0]->security->index=1
35+
subsystem_ns_list[0]->num_hfis=1
36+
subsystem_ns_list[0]->hfis[0]->index=1
37+
subsystem_ns_list[0]->transport=tcp
38+
subsystem_ns_list[0]->traddr=127.0.0.1
39+
subsystem_ns_list[0]->trsvcid=4420
40+
subsystem_ns_list[0]->subsys_port_id=1
41+
subsystem_ns_list[0]->nsid=1
42+
subsystem_ns_list[0]->nid_type=3
43+
subsystem_ns_list[0]->nid=aaaaaaaaaaaaaaaaaaaaaaaaaaaa01
44+
subsystem_ns_list[0]->subsys_nqn=nqn.2026-06.example:synthetic-root
45+
subsystem_ns_list[0]->trflags=0x0007
46+
subsystem_ns_list[0]->controller_id=0
47+
subsystem_ns_list[0]->asqsz=0
48+
subsystem_ns_list[0]->dhcp_root_path_string=(null)
49+
subsystem_ns_list[0]->naed=0x00
50+
subsystem_ns_list[0]->cipeec=0x00
51+
subsystem_ns_list[0]->cto=0
52+
subsystem_ns_list[0]->nceec=0x00
53+
subsystem_ns_list[0]->flags=0x0085

libnvme/test/nbft/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ tables = [
2323
'NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery',
2424
'NBFT-mpath+disc-ipv4+6_half',
2525
'NBFT-ipv6-noip+disc',
26+
'NBFT-synthetic-security',
2627
'NBFT-empty'
2728
]
2829

libnvme/test/nbft/nbft-dump.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ static void print_nbft(struct libnbft_info *table)
6464

6565
for (sec = table->security_list, i = 0; sec && *sec; sec++, i++) {
6666
printf("security_list[%u]->index=%d\n", i, (*sec)->index);
67+
printf("security_list[%u]->flags=%"PRIu16"\n",
68+
i, (*sec)->flags);
69+
printf("security_list[%u]->secret_type=%u\n",
70+
i, (*sec)->secret_type);
71+
printf("security_list[%u]->sec_chan_algs_len=%"PRIu16"\n",
72+
i, (*sec)->sec_chan_algs_len);
73+
printf("security_list[%u]->auth_protocols_len=%"PRIu16"\n",
74+
i, (*sec)->auth_protocols_len);
75+
printf("security_list[%u]->cipher_suites_len=%"PRIu16"\n",
76+
i, (*sec)->cipher_suites_len);
77+
printf("security_list[%u]->dh_groups_len=%"PRIu16"\n",
78+
i, (*sec)->dh_groups_len);
79+
printf("security_list[%u]->sec_hash_funcs_len=%"PRIu16"\n",
80+
i, (*sec)->sec_hash_funcs_len);
81+
printf("security_list[%u]->secret_keypath=%s\n", i,
82+
(*sec)->secret_keypath ?
83+
(*sec)->secret_keypath : "(null)");
6784
}
6885

6986
for (disc = table->discovery_list, i = 0; disc && *disc; disc++, i++) {
641 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)