aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlon Zahavi <zahavi.alon@gmail.com>2023-11-28 11:15:26 +0000
committerAleksandr Nogikh <nogikh@google.com>2023-12-07 10:16:22 +0000
commit28b24332d95f2f7df44ec7e7a5e0025bcadc6277 (patch)
tree0fd034868b3b507331a8c1fe6acddf9bd5a8df1c
parent0a02ce36aee886cafdc6907db66a49859cf17caf (diff)
sys/linux, pkg/host, executor: add NVMe-oF/TCP subsystem support
Add new pseudo-syscall for creating a socket in init netns and connecting to NVMe-oF/TCP server on 127.0.0.1:4420. Also add descriptions for NVMe-oF/TCP.
-rw-r--r--executor/common_linux.h48
-rw-r--r--pkg/csource/generated.go47
-rw-r--r--pkg/host/syscalls_linux.go5
-rw-r--r--sys/linux/socket_nvme_of_tcp.txt632
-rw-r--r--sys/linux/socket_nvme_of_tcp.txt.const70
-rw-r--r--sys/linux/test/nvme6
-rw-r--r--sys/linux/test/nvme_h2c_pdu7
7 files changed, 811 insertions, 4 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 42d352a52..2f10ae3d6 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -730,7 +730,7 @@ static void initialize_tun(void)
}
#endif
-#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || __NR_syz_socket_connect_nvme_tcp
const int kInitNetNsFd = 201; // see kMaxFd
#endif
@@ -2484,6 +2484,50 @@ static long syz_init_net_socket(volatile long domain, volatile long type, volati
#endif
#endif
+#if SYZ_EXECUTOR || __NR_syz_socket_connect_nvme_tcp
+#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_socket_connect_nvme_tcp()
+{
+ struct sockaddr_in nvme_local_address;
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ return netns;
+ if (setns(kInitNetNsFd, 0))
+ return -1;
+ int sock = syscall(__NR_socket, AF_INET, SOCK_STREAM, 0x0);
+ int err = errno;
+ if (setns(netns, 0))
+ fail("setns(netns) failed");
+ close(netns);
+ errno = err;
+ // We only connect to an NVMe-oF/TCP server on 127.0.0.1:4420
+ nvme_local_address.sin_family = AF_INET;
+ nvme_local_address.sin_port = htobe16(4420);
+ nvme_local_address.sin_addr.s_addr = htobe32(0x7f000001);
+ err = syscall(__NR_connect, sock, &nvme_local_address, sizeof(nvme_local_address));
+ if (err != 0) {
+ close(sock);
+ return -1;
+ }
+ return sock;
+}
+#else
+static long syz_socket_connect_nvme_tcp()
+{
+ return syscall(__NR_socket, -1, 0, 0);
+}
+#endif
+#endif
+
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
#include <errno.h>
#include <fcntl.h>
@@ -3851,7 +3895,7 @@ static void sandbox_common()
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setsid();
-#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || __NR_syz_socket_connect_nvme_tcp
int netns = open("/proc/self/ns/net", O_RDONLY);
if (netns == -1)
fail("open(/proc/self/ns/net) failed");
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index 60a1ff964..4c3fae47c 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -3365,7 +3365,7 @@ static void initialize_tun(void)
}
#endif
-#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || __NR_syz_socket_connect_nvme_tcp
const int kInitNetNsFd = 201;
#endif
@@ -6296,6 +6296,49 @@ static long syz_init_net_socket(volatile long domain, volatile long type, volati
#endif
#endif
+#if SYZ_EXECUTOR || __NR_syz_socket_connect_nvme_tcp
+#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_socket_connect_nvme_tcp()
+{
+ struct sockaddr_in nvme_local_address;
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ return netns;
+ if (setns(kInitNetNsFd, 0))
+ return -1;
+ int sock = syscall(__NR_socket, AF_INET, SOCK_STREAM, 0x0);
+ int err = errno;
+ if (setns(netns, 0))
+ fail("setns(netns) failed");
+ close(netns);
+ errno = err;
+ nvme_local_address.sin_family = AF_INET;
+ nvme_local_address.sin_port = htobe16(4420);
+ nvme_local_address.sin_addr.s_addr = htobe32(0x7f000001);
+ err = syscall(__NR_connect, sock, &nvme_local_address, sizeof(nvme_local_address));
+ if (err != 0) {
+ close(sock);
+ return -1;
+ }
+ return sock;
+}
+#else
+static long syz_socket_connect_nvme_tcp()
+{
+ return syscall(__NR_socket, -1, 0, 0);
+}
+#endif
+#endif
+
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
#include <errno.h>
#include <fcntl.h>
@@ -9212,7 +9255,7 @@ static void sandbox_common()
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setsid();
-#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || __NR_syz_socket_connect_nvme_tcp
int netns = open("/proc/self/ns/net", O_RDONLY);
if (netns == -1)
fail("open(/proc/self/ns/net) failed");
diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go
index 7037dc001..b1bcbfb8b 100644
--- a/pkg/host/syscalls_linux.go
+++ b/pkg/host/syscalls_linux.go
@@ -230,6 +230,10 @@ func isSyzInitNetSocketSupported(c *prog.Syscall, target *prog.Target, sandbox s
return isSupportedSocket(c)
}
+func isSyzSocketConnectNvmeTCPSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
+ return onlySandboxNone(sandbox)
+}
+
func isSyzGenetlinkGetFamilyIDSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_GENERIC)
if fd == -1 {
@@ -322,6 +326,7 @@ var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool,
"syz_clone": alwaysSupported,
"syz_clone3": alwaysSupported,
"syz_pkey_set": isSyzPkeySetSupported,
+ "syz_socket_connect_nvme_tcp": isSyzSocketConnectNvmeTCPSupported,
}
func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
diff --git a/sys/linux/socket_nvme_of_tcp.txt b/sys/linux/socket_nvme_of_tcp.txt
new file mode 100644
index 000000000..0d256fe37
--- /dev/null
+++ b/sys/linux/socket_nvme_of_tcp.txt
@@ -0,0 +1,632 @@
+# Copyright 2018 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+include <linux/nvme-tcp.h>
+include <linux/sizes.h>
+include <linux/nvme.h>
+include <linux/socket.h>
+include <uapi/linux/in.h>
+include <linux/net.h>
+
+#########################################
+### Generic NVMe over TCP ###
+
+nvme_of_msg {
+ pdu nvme_tcp_pdu
+ payload optional[buffer[in]]
+} [packed]
+
+nvme_tcp_pdu [
+ icreq nvme_tcp_icreq_pdu
+ icresp nvme_tcp_icresp_pdu
+ cmd nvme_tcp_cmd_pdu
+ rsp nvme_tcp_rsp_pdu
+ r2t nvme_tcp_r2t_pdu
+ data_h2c nvme_tcp_data_pdu_h2c
+ data_h2c_hdigest nvme_tcp_data_pdu_h2c_hdigest
+ data_h2c_no_hdigest nvme_tcp_data_pdu_h2c_no_hdigest
+ data_c2h nvme_tcp_data_pdu_c2h
+]
+
+type nvme_tcp_hdr_t_const[PDU_TYPE, HLEN_SIZE] {
+ type const[PDU_TYPE, int8]
+ flags flags[nvme_tcp_pdu_flags, int8]
+ hlen const[HLEN_SIZE, int8]
+ pdo int8
+ plen int32
+} [packed]
+
+type nvme_tcp_hdr_t_const_pdo[PDU_TYPE, HLEN_SIZE, PDO_SIZE] {
+ type const[PDU_TYPE, int8]
+ flags flags[nvme_tcp_pdu_flags, int8]
+ hlen const[HLEN_SIZE, int8]
+ pdo const[PDO_SIZE, int8]
+ plen int32
+} [packed]
+
+type nvme_tcp_hdr_t_const_plen[PDU_TYPE, HLEN_SIZE, PLEN_SIZE] {
+ type const[PDU_TYPE, int8]
+ flags flags[nvme_tcp_pdu_flags, int8]
+ hlen const[HLEN_SIZE, int8]
+ pdo int8
+ plen const[PLEN_SIZE, int32]
+} [packed]
+
+nvme_tcp_pdu_flags = NVME_TCP_F_HDGST, NVME_TCP_F_DDGST, NVME_TCP_F_DATA_LAST, NVME_TCP_F_DATA_SUCCESS
+
+nvme_tcp_digest_option = NVME_TCP_HDR_DIGEST_ENABLE, NVME_TCP_DATA_DIGEST_ENABLE
+
+nvme_tcp_fatal_error_status = 0, NVME_TCP_FES_INVALID_PDU_HDR, NVME_TCP_FES_PDU_SEQ_ERR, NVME_TCP_FES_HDR_DIGEST_ERR, NVME_TCP_FES_DATA_OUT_OF_RANGE, NVME_TCP_FES_R2T_LIMIT_EXCEEDED, NVME_TCP_FES_DATA_LIMIT_EXCEEDED, NVME_TCP_FES_UNSUPPORTED_PARAM
+
+nvme_tcp_pfv = NVME_TCP_PFV_1_0
+
+define NVME_TCP_DATA_PDU_SIZE sizeof(struct nvme_tcp_data_pdu)
+define NVME_TCP_ICREQ_PDU_SIZE sizeof(struct nvme_tcp_icreq_pdu)
+define NVME_TCP_CMD_PDU_SIZE sizeof(struct nvme_tcp_cmd_pdu)
+define NVME_TCP_ICRESP_PDU_SIZE sizeof(struct nvme_tcp_icresp_pdu)
+
+define NVME_TCP_DISC_PORT 8009
+define NVME_TCP_ADMIN_CCSZ SZ_8K
+define NVME_TCP_DIGEST_LENGTH 4
+define NVME_TCP_MIN_MAXH2CDATA 4096
+
+### End of generic ###
+#########################################
+
+#########################################
+### nvme_tcp_data_pdu ###
+
+type nvme_tcp_data_pdu[HDR_TYPE] {
+ hdr HDR_TYPE
+ command_id int16
+ ttag int16
+ data_offset int32
+ data_length int32
+ rsvd array[int8, 4]
+} [size[NVME_TCP_DATA_PDU_SIZE]]
+
+type nvme_tcp_hdr_data_pdu_h2c nvme_tcp_hdr_t_const[nvme_tcp_h2c_data, NVME_TCP_DATA_PDU_SIZE]
+type nvme_tcp_data_pdu_h2c nvme_tcp_data_pdu[nvme_tcp_hdr_data_pdu_h2c]
+
+type nvme_tcp_hdr_data_pdu_h2c_hdigest nvme_tcp_hdr_t_const_pdo[nvme_tcp_h2c_data, NVME_TCP_DATA_PDU_SIZE, NVME_TCP_HDR_H2C_DIGEST_PDO_HDIGEST]
+type nvme_tcp_data_pdu_h2c_hdigest nvme_tcp_data_pdu[nvme_tcp_hdr_data_pdu_h2c_hdigest]
+
+type nvme_tcp_hdr_data_pdu_h2c_no_hdigest nvme_tcp_hdr_t_const_pdo[nvme_tcp_h2c_data, NVME_TCP_DATA_PDU_SIZE, NVME_TCP_HDR_H2C_DIGEST_PDO_NO_HDIGEST]
+type nvme_tcp_data_pdu_h2c_no_hdigest nvme_tcp_data_pdu[nvme_tcp_hdr_data_pdu_h2c_no_hdigest]
+
+type nvme_tcp_hdr_data_pdu_c2h nvme_tcp_hdr_t_const[nvme_tcp_c2h_data, NVME_TCP_DATA_PDU_SIZE]
+type nvme_tcp_data_pdu_c2h nvme_tcp_data_pdu[nvme_tcp_hdr_data_pdu_c2h]
+
+define NVME_TCP_HDR_H2C_DIGEST_PDO_HDIGEST NVME_TCP_DATA_PDU_SIZE + NVME_TCP_DIGEST_LENGTH
+define NVME_TCP_HDR_H2C_DIGEST_PDO_NO_HDIGEST NVME_TCP_DATA_PDU_SIZE
+define NVME_TCP_HDR_H2C_DIGEST_PLEN_HDIGEST_DDIGEST NVME_TCP_HDR_H2C_DIGEST_PDO_HDIGEST + NVME_TCP_DIGEST_LENGTH
+
+### End of nvme_tcp_r2t_pdu ###
+#########################################
+
+#########################################
+### nvme_tcp_r2t_pdu ###
+
+nvme_tcp_r2t_pdu {
+ hdr nvme_tcp_hdr_r2t_pdu
+ command_id int16
+ ttag int16
+ r2t_offset int32
+ r2t_length int32
+ rsvd array[const[0, int8], 4]
+} [size[NVME_TCP_DATA_PDU_SIZE]]
+
+type nvme_tcp_hdr_r2t_pdu nvme_tcp_hdr_t_const[nvme_tcp_r2t, NVME_TCP_DATA_PDU_SIZE]
+
+### End of nvme_tcp_r2t_pdu ###
+#########################################
+
+#########################################
+### nvme_tcp_rsp_pdu ###
+
+nvme_tcp_rsp_pdu {
+ hdr nvme_tcp_hdr_rsp_pdu
+ cqe nvme_completion
+} [size[NVME_TCP_DATA_PDU_SIZE]]
+
+nvme_completion {
+ result nvme_result
+ sq_head int16
+ sq_id int16
+ command_id int16
+ status flags[nvme_tcp_fatal_error_status, int16]
+} [packed]
+
+nvme_result [
+ u16 int16
+ u32 int32
+ u64 int64
+]
+
+type nvme_tcp_hdr_rsp_pdu nvme_tcp_hdr_t_const[nvme_tcp_rsp, NVME_TCP_DATA_PDU_SIZE]
+
+### End of nvme_tcp_rsp_pdu ###
+#########################################
+
+#########################################
+### nvme_tcp_icresp_pdu ###
+
+nvme_tcp_icresp_pdu {
+ hdr nvme_tcp_hdr_icresp_pdu
+ pfv flags[nvme_tcp_pfv, int16]
+# Linux NVMe driver only support cpda = 0
+ cpda const[0, int8]
+ digest flags[nvme_tcp_digest_option, int8]
+ maxdata int32
+ rsvd array[const[0, int8], 112]
+} [size[NVME_TCP_ICRESP_PDU_SIZE]]
+
+type nvme_tcp_hdr_icresp_pdu nvme_tcp_hdr_t_const[nvme_tcp_icresp, NVME_TCP_ICRESP_PDU_SIZE]
+
+### End of nvme_tcp_icresp_pdu ###
+#########################################
+
+#########################################
+### nvme_tcp_icreq_pdu ###
+
+nvme_tcp_icreq_pdu {
+ hdr nvme_tcp_hdr_icreq_pdu
+ pfv flags[nvme_tcp_pfv, int16]
+# Linux NVMe driver only support hcpda = 0
+ hpda const[0, int8]
+ digest flags[nvme_tcp_digest_option, int8]
+ maxr2t int32
+ rsvd array[const[0, int8], 112]
+} [size[NVME_TCP_ICREQ_PDU_SIZE]]
+
+type nvme_tcp_hdr_icreq_pdu nvme_tcp_hdr_t_const_plen[nvme_tcp_icreq, NVME_TCP_ICREQ_PDU_SIZE, NVME_TCP_ICREQ_PDU_SIZE]
+
+### End of nvme_tcp_icreq_pdu ###
+#########################################
+
+#########################################
+### nvme_tcp_cmd_pdu ###
+
+nvme_tcp_cmd_pdu {
+ hdr nvme_tcp_hdr_cmd_pdu
+ cmd nvme_command
+} [size[NVME_TCP_CMD_PDU_SIZE]]
+
+type nvme_tcp_hdr_cmd_pdu nvme_tcp_hdr_t_const_plen[nvme_tcp_cmd, NVME_TCP_CMD_PDU_SIZE, NVME_TCP_CMD_PDU_SIZE]
+
+nvme_command {
+ anon_union nvme_command_union
+}
+
+nvme_command_union [
+ common nvme_common_command
+ rw nvme_rw_command
+ identify nvme_identify
+ features nvme_features
+ create_cq nvme_create_cq
+ create_sq nvme_create_sq
+ delete_queue nvme_delete_queue
+ dlfw nvme_download_firmware
+ format nvme_format_cmd
+ dsm nvme_dsm_cmd
+ write_zeroes nvme_write_zeroes_cmd
+ zms nvme_zone_mgmt_send_cmd
+ zmr nvme_zone_mgmt_recv_cmd
+ abort nvme_abort_cmd
+ fabrics nvmf_common_command
+ connect nvmf_connect_command
+ prop_set nvmf_property_set_command
+ prop_get nvmf_property_get_command
+ auth_common nvmf_auth_common_command
+ auth_send nvmf_auth_send_command
+ auth_receive nvmf_auth_receive_command
+ dbbuf nvme_dbbuf
+ directive nvme_directive_cmd
+ get_log_page nvme_get_log_page_command
+]
+
+nvme_get_log_page_command {
+ opcode const[nvme_admin_get_log_page, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ lid int8
+ lsp int8
+ numdl int16
+ numdu int16
+ rsvd11 const[0, int16]
+ anon_union nvme_get_log_page_command_anon_union
+ rsvd14 array[const[0, int8], 3]
+ csi int8
+ rsvd15 const[0, int32]
+}
+
+nvme_get_log_page_command_anon_union [
+ anon_struct nvme_get_log_page_command_anon_union_anon_struct
+ lpo int64
+]
+
+nvme_get_log_page_command_anon_union_anon_struct {
+ lpol int32
+ lpou int32
+}
+
+nvme_download_firmware {
+ opcode const[nvme_admin_download_fw, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 5]
+ dptr nvme_data_ptr
+ numd int32
+ offset int32
+ rsvd12 array[const[0, int32], 4]
+}
+
+nvme_format_cmd {
+ opcode const[nvme_admin_format_nvm, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 4]
+ cdw10 int32
+ rsvd11 array[const[0, int32], 5]
+}
+
+nvme_dsm_cmd {
+ opcode const[nvme_cmd_dsm, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ nr int32
+ attributes int32
+ rsvd12 array[const[0, int32], 4]
+}
+
+nvme_write_zeroes_cmd {
+ opcode const[nvme_cmd_write_zeroes, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 const[0, int64]
+ metadata int64
+ dptr nvme_data_ptr
+ slba int64
+ length int16
+ control int16
+ dsmgmt int32
+ reftag int32
+ apptag int16
+ appmask int16
+}
+
+nvme_zone_mgmt_send_cmd {
+ opcode const[nvme_cmd_zone_mgmt_send, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ cdw2 array[int32, 2]
+ metadata int64
+ dptr nvme_data_ptr
+ slba int64
+ cdw12 int32
+ zsa int8
+ select_all int8
+ rsvd13 array[const[0, int8], 2]
+ cdw14 array[int32, 2]
+}
+
+nvme_zone_mgmt_recv_cmd {
+ opcode const[nvme_cmd_zone_mgmt_recv, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ slba int64
+ numd int32
+ zra int8
+ zrasf int8
+ pr int8
+ rsvd13 const[0, int8]
+ cdw14 array[int32, 2]
+}
+
+nvme_abort_cmd {
+ opcode const[nvme_admin_abort_cmd, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 9]
+ sqid int16
+ cid int16
+ rsvd11 array[const[0, int32], 5]
+}
+
+nvmf_common_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype int8
+ resv2 array[int8, 35]
+ ts array[int8, 24]
+}
+
+nvmf_connect_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 const[0x40, int8]
+ command_id const[0x0, int16]
+ fctype const[nvme_fabrics_type_connect, int8]
+ resv2 array[int8, 19]
+ dptr nvme_data_ptr
+ recfmt int16
+ qid int16
+ sqsize int16
+ cattr int8
+ resv3 int8
+ kato int32
+ resv4 array[int8, 12]
+}
+
+nvmf_property_set_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype const[nvme_fabrics_type_property_set, int8]
+ resv2 array[int8, 35]
+ attrib const[0x0, int8]
+ resv3 array[int8, 3]
+ offset int32
+ value int64
+ resv4 array[int8, 8]
+}
+
+nvmf_property_get_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype const[nvme_fabrics_type_property_get, int8]
+ resv2 array[int8, 35]
+ attrib int8
+ resv3 array[int8, 3]
+ offset int32
+ resv4 array[int8, 16]
+}
+
+nvmf_auth_common_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype int8
+ resv2 array[int8, 19]
+ dptr nvme_data_ptr
+ resv3 int8
+ spsp0 int8
+ spsp1 int8
+ secp int8
+ al_tl int32
+ resv4 array[int8, 16]
+}
+
+nvmf_auth_send_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype const[nvme_fabrics_type_auth_send, int8]
+ resv2 array[int8, 19]
+ dptr nvme_data_ptr
+ resv3 int8
+ spsp0 flags[sps_flags, int8]
+ spsp1 flags[sps_flags, int8]
+ secp flags[secp_flags, int8]
+ tl int32
+ resv4 array[int8, 16]
+}
+
+secp_flags = NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER, 0x0
+sps_flags = 0x1, 0x2
+
+nvmf_auth_receive_command {
+ opcode const[nvme_fabrics_command, int8]
+ resv1 int8
+ command_id int16
+ fctype const[nvme_fabrics_type_auth_receive, int8]
+ resv2 array[int8, 19]
+ dptr nvme_data_ptr
+ resv3 int8
+ spsp0 flags[sps_flags, int8]
+ spsp1 flags[sps_flags, int8]
+ secp flags[secp_flags, int8]
+ al int32
+ resv4 array[int8, 16]
+}
+
+nvme_dbbuf {
+ opcode const[nvme_admin_dbbuf, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 5]
+ prp1 int64
+ prp2 int64
+ rsvd12 array[const[0, int32], 6]
+}
+
+nvme_directive_cmd {
+ opcode flags[nvme_admin_directive_opcodes, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ numd int32
+ doper int8
+ dtype int8
+ dspec int16
+ endir int8
+ tdtype int8
+ rsvd15 const[0, int16]
+ rsvd16 array[int32, 3]
+}
+
+nvme_admin_directive_opcodes = nvme_admin_directive_send, nvme_admin_directive_recv
+#####################
+#####################
+
+nvme_delete_queue {
+ opcode const[nvme_admin_delete_cq, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 9]
+ qid int16
+ rsvd10 const[0, int16]
+ rsvd11 array[const[0, int32], 5]
+}
+
+nvme_create_sq {
+ opcode const[nvme_admin_create_sq, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 5]
+ prp1 int64
+ rsvd8 const[0, int64]
+ sqid int16
+ qsize int16
+ sq_flags int16
+ cqid int16
+ rsvd12 array[const[0, int32], 4]
+}
+
+nvme_create_cq {
+ opcode const[nvme_admin_create_cq, int8]
+ flags int8
+ command_id int16
+ rsvd1 array[const[0, int32], 5]
+ prp1 int64
+ rsvd8 const[0, int64]
+ cqid int16
+ qsize int16
+ cq_flags int16
+ irq_vector int16
+ rsvd12 array[const[0, int32], 4]
+}
+
+nvme_features {
+ opcode flags[nvme_features_opcodes, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ fid int32
+ dword11 int32
+ dword12 int32
+ dword13 int32
+ dword14 int32
+ dword15 int32
+}
+
+nvme_features_opcodes = nvme_admin_set_features, nvme_admin_get_features
+
+nvme_identify {
+ opcode const[nvme_admin_identify, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ rsvd2 array[const[0, int64], 2]
+ dptr nvme_data_ptr
+ cns int8
+ rsvd3 const[0, int8]
+ ctrlid int16
+ rsvd11 array[const[0, int8], 3]
+ csi int8
+ rsvd12 array[const[0, int32], 4]
+}
+
+nvme_common_command {
+ opcode flags[nvme_common_command_opcodes, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ cdw2 array[int32, 2]
+ metadata int64
+ dptr nvme_data_ptr
+ cdws cdws_struct_group
+}
+
+nvme_common_command_opcodes = nvme_cmd_resv_report, nvme_fabrics_command, nvme_cmd_write, nvme_admin_async_event, nvme_cmd_flush, nvme_cmd_read, nvme_cmd_write_zeroes, nvme_cmd_dsm, nvme_admin_security_recv, nvme_admin_security_send, nvme_cmd_flush, nvme_admin_get_log_page, nvme_admin_identify, nvme_admin_abort_cmd, nvme_admin_set_features, nvme_admin_get_features, nvme_admin_async_event, nvme_admin_keep_alive
+
+cdws_struct_group [
+ cdws_anon cdws_anon_struct
+ cdws cdws_anon_struct
+]
+
+cdws_anon_struct {
+ cdw10 int32
+ cdw11 int32
+ cdw12 int32
+ cdw13 int32
+ cdw14 int32
+ cdw15 int32
+}
+
+nvme_data_ptr [
+ anon_struct nvme_data_ptr_anon_struct
+ sgl nvme_sgl_desc
+ ksgl nvme_keyed_sgl_desc
+]
+
+nvme_data_ptr_anon_struct {
+ prp1 int64
+ prp2 int64
+} [packed]
+
+nvme_sgl_desc {
+ addr int64
+ length int32
+ rsvd array[const[0, int8], 3]
+ type int8
+} [packed]
+
+nvme_keyed_sgl_desc {
+ addr int64
+ length array[int8, 3]
+ key array[int8, 4]
+ type int8
+} [packed]
+
+nvme_rw_command {
+ opcode flags[nvme_opcodes_rw, int8]
+ flags int8
+ command_id int16
+ nsid int32
+ cdw2 int32
+ cdw3 int32
+ metadata int64
+ dptr nvme_data_ptr
+ slba int64
+ length int16
+ control int16
+ dsmgmt int32
+ reftag int32
+ apptag int16
+ appmask int16
+}
+
+nvme_opcodes_rw = nvme_cmd_write, nvme_cmd_read, nvme_cmd_zone_append
+
+### End of nvme_tcp_cmd_pdu ###
+#########################################
+
+#########################################
+
+resource nvme_sock[sock]
+
+syz_socket_connect_nvme_tcp() nvme_sock
+
+sendto$inet_nvme_of_msg(fd nvme_sock, pdu ptr[in, nvme_of_msg], len len[pdu], f const[0], addr const[0], addrlen const[0])
+sendto$inet_nvme_pdu(fd nvme_sock, pdu ptr[in, nvme_tcp_pdu], len len[pdu], f const[0], addr const[0], addrlen const[0])
+sendto$inet_nvme_icreq_pdu(fd nvme_sock, pdu ptr[in, nvme_tcp_icreq_pdu], len len[pdu], f const[0], addr const[0], addrlen const[0])
+recvmsg$inet_nvme(fd nvme_sock, msg ptr[inout, recv_msghdr], f flags[recv_flags])
+recvfrom$inet_nvme(fd nvme_sock, buf buffer[out], len len[buf], f flags[recv_flags], addr ptr[in, sockaddr_storage, opt], addrlen len[addr])
diff --git a/sys/linux/socket_nvme_of_tcp.txt.const b/sys/linux/socket_nvme_of_tcp.txt.const
new file mode 100644
index 000000000..2b0d5162e
--- /dev/null
+++ b/sys/linux/socket_nvme_of_tcp.txt.const
@@ -0,0 +1,70 @@
+# Code generated by syz-sysgen. DO NOT EDIT.
+arches = 386, amd64, arm, arm64, mips64le, ppc64le, riscv64, s390x
+NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER = 233
+NVME_TCP_ADMIN_CCSZ = 8192
+NVME_TCP_CMD_PDU_SIZE = 72
+NVME_TCP_DATA_DIGEST_ENABLE = 2
+NVME_TCP_DATA_PDU_SIZE = 24
+NVME_TCP_DIGEST_LENGTH = 4
+NVME_TCP_DISC_PORT = 8009
+NVME_TCP_FES_DATA_LIMIT_EXCEEDED = 5
+NVME_TCP_FES_DATA_OUT_OF_RANGE = 4
+NVME_TCP_FES_HDR_DIGEST_ERR = 3
+NVME_TCP_FES_INVALID_PDU_HDR = 1
+NVME_TCP_FES_PDU_SEQ_ERR = 2
+NVME_TCP_FES_R2T_LIMIT_EXCEEDED = 5
+NVME_TCP_FES_UNSUPPORTED_PARAM = 6
+NVME_TCP_F_DATA_LAST = 4
+NVME_TCP_F_DATA_SUCCESS = 8
+NVME_TCP_F_DDGST = 2
+NVME_TCP_F_HDGST = 1
+NVME_TCP_HDR_DIGEST_ENABLE = 1
+NVME_TCP_HDR_H2C_DIGEST_PDO_HDIGEST = 28
+NVME_TCP_HDR_H2C_DIGEST_PDO_NO_HDIGEST = 24
+NVME_TCP_HDR_H2C_DIGEST_PLEN_HDIGEST_DDIGEST = 32
+NVME_TCP_ICREQ_PDU_SIZE = 128
+NVME_TCP_ICRESP_PDU_SIZE = 128
+NVME_TCP_MIN_MAXH2CDATA = 4096
+NVME_TCP_PFV_1_0 = 0
+__NR_recvfrom = 207, 386:s390x:371, amd64:45, arm:292, mips64le:5044, ppc64le:337
+__NR_recvmsg = 212, 386:s390x:372, amd64:47, arm:297, mips64le:5046, ppc64le:342
+__NR_sendto = 206, 386:s390x:369, amd64:44, arm:290, mips64le:5043, ppc64le:335
+nvme_admin_abort_cmd = 8
+nvme_admin_async_event = 12
+nvme_admin_create_cq = 5
+nvme_admin_create_sq = 1
+nvme_admin_dbbuf = 124
+nvme_admin_delete_cq = 4
+nvme_admin_directive_recv = 26
+nvme_admin_directive_send = 25
+nvme_admin_download_fw = 17
+nvme_admin_format_nvm = 128
+nvme_admin_get_features = 10
+nvme_admin_get_log_page = 2
+nvme_admin_identify = 6
+nvme_admin_keep_alive = 24
+nvme_admin_security_recv = 130
+nvme_admin_security_send = 129
+nvme_admin_set_features = 9
+nvme_cmd_dsm = 9
+nvme_cmd_flush = 0
+nvme_cmd_read = 2
+nvme_cmd_resv_report = 14
+nvme_cmd_write = 1
+nvme_cmd_write_zeroes = 8
+nvme_cmd_zone_append = 125
+nvme_cmd_zone_mgmt_recv = 122
+nvme_cmd_zone_mgmt_send = 121
+nvme_fabrics_command = 127
+nvme_fabrics_type_auth_receive = 6
+nvme_fabrics_type_auth_send = 5
+nvme_fabrics_type_connect = 1
+nvme_fabrics_type_property_get = 4
+nvme_fabrics_type_property_set = 0
+nvme_tcp_c2h_data = 7
+nvme_tcp_cmd = 4
+nvme_tcp_h2c_data = 6
+nvme_tcp_icreq = 0
+nvme_tcp_icresp = 1
+nvme_tcp_r2t = 9
+nvme_tcp_rsp = 5
diff --git a/sys/linux/test/nvme b/sys/linux/test/nvme
new file mode 100644
index 000000000..65fbb2d4d
--- /dev/null
+++ b/sys/linux/test/nvme
@@ -0,0 +1,6 @@
+# requires: arch=amd64
+
+# This connects to an NVMe server on 127.0.0.1:4420 and then close the connection
+
+r0 = syz_socket_connect_nvme_tcp()
+close(r0) \ No newline at end of file
diff --git a/sys/linux/test/nvme_h2c_pdu b/sys/linux/test/nvme_h2c_pdu
new file mode 100644
index 000000000..3a313ed31
--- /dev/null
+++ b/sys/linux/test/nvme_h2c_pdu
@@ -0,0 +1,7 @@
+# requires: arch=amd64
+
+# This connects to an NVMe-oF/TCP server and sends an H2C PDU
+
+r0 = syz_socket_connect_nvme_tcp()
+sendto$inet_nvme_pdu(r0, &(0x7f00000001c0)=@data_h2c={{0x6, 0x0, 0x18, 0x0, 0x0}, 0x0, 0x0, 0x1, 0x0, "cfbf3586"}, 0x80, 0x0, 0x0, 0x0)
+close(r0)