From c68d2c0ddb1739b8c589e329e624fb5032513159 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 3 Jan 2017 12:03:07 +0100 Subject: [PATCH 1/8] init: introduce iscsi_smalloc Signed-off-by: Peter Lieven --- include/iscsi-private.h | 1 + lib/init.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index b91af60..60d216e 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -351,6 +351,7 @@ void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size); void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size); void iscsi_free(struct iscsi_context *iscsi, void* ptr); char* iscsi_strdup(struct iscsi_context *iscsi, const char* str); +void* iscsi_smalloc(struct iscsi_context *iscsi, size_t size); void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size); void iscsi_sfree(struct iscsi_context *iscsi, void* ptr); diff --git a/lib/init.c b/lib/init.c index 9941ceb..1b063cd 100644 --- a/lib/init.c +++ b/lib/init.c @@ -111,15 +111,22 @@ char* iscsi_strdup(struct iscsi_context *iscsi, const char* str) { return str2; } -void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size) { +void* iscsi_smalloc(struct iscsi_context *iscsi, size_t size) { void *ptr; if (size > iscsi->smalloc_size) return NULL; if (iscsi->smalloc_free > 0) { ptr = iscsi->smalloc_ptrs[--iscsi->smalloc_free]; - memset(ptr, 0, iscsi->smalloc_size); iscsi->smallocs++; } else { - ptr = iscsi_zmalloc(iscsi, iscsi->smalloc_size); + ptr = iscsi_malloc(iscsi, iscsi->smalloc_size); + } + return ptr; +} + +void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size) { + void *ptr = iscsi_smalloc(iscsi, size); + if (ptr) { + memset(ptr, 0, size); } return ptr; } From 1a552a8afa06b28fb68114989c30bab38429ddb6 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 12:19:07 +0100 Subject: [PATCH 2/8] socket: do not zero header of incoming PDU we overwrite it anyway Signed-off-by: Peter Lieven --- lib/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/socket.c b/lib/socket.c index 036b4f4..7ab6be8 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -570,7 +570,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) if (iscsi->incoming == NULL) { iscsi->incoming = iscsi_szmalloc(iscsi, sizeof(struct iscsi_in_pdu)); - iscsi->incoming->hdr = iscsi_szmalloc(iscsi, ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE); + iscsi->incoming->hdr = iscsi_smalloc(iscsi, ISCSI_HEADER_SIZE); if (iscsi->incoming == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu"); return -1; From ed1ed27ddedf63e37904428491271ff5426a2c76 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 3 Jan 2017 12:19:12 +0100 Subject: [PATCH 3/8] socket: return in->hdr to smalloc pool commit bc64420 introduced an extra smalloc for the in->hdr, however it did use iscsi_free instead of iscsi_sfree to free it. Signed-off-by: Peter Lieven --- lib/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/socket.c b/lib/socket.c index 7ab6be8..aa25059 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -979,7 +979,7 @@ static int iscsi_tcp_queue_pdu(struct iscsi_context *iscsi, void iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { - iscsi_free(iscsi, in->hdr); + iscsi_sfree(iscsi, in->hdr); iscsi_free(iscsi, in->data); in->data=NULL; iscsi_sfree(iscsi, in); From 23738bf1c3ecab68d59e1666911e9a5b9ca35c73 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 12:28:37 +0100 Subject: [PATCH 4/8] socket: calculate header checksum at the right place we mangled the PDU header after calculating the checksum which effectively broke CRC32C header digests completely. Signed-off-by: Peter Lieven --- lib/socket.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/socket.c b/lib/socket.c index aa25059..caf51a5 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -675,6 +675,25 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) return 0; } +static int iscsi_pdu_update_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) +{ + unsigned long crc; + + if (pdu->outdata.size < ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE) { + iscsi_set_error(iscsi, "PDU too small (%u) to contain header digest", + (unsigned int) pdu->outdata.size); + return -1; + } + + crc = crc32c((char *)pdu->outdata.data, ISCSI_RAW_HEADER_SIZE); + + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+3] = (crc >> 24)&0xff; + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+2] = (crc >> 16)&0xff; + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+1] = (crc >> 8)&0xff; + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+0] = (crc) &0xff; + return 0; +} + static int iscsi_write_to_socket(struct iscsi_context *iscsi) { @@ -724,7 +743,13 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) /* set exp statsn */ iscsi_pdu_set_expstatsn(iscsi->outqueue_current, iscsi->statsn + 1); - + + /* calculate header checksum */ + if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE && + iscsi_pdu_update_headerdigest(iscsi, iscsi->outqueue_current) != 0) { + return -1; + } + ISCSI_LIST_REMOVE(&iscsi->outqueue, iscsi->outqueue_current); if (!(iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT)) { /* we have to add the pdu to the waitqueue already here @@ -954,23 +979,6 @@ static int iscsi_tcp_queue_pdu(struct iscsi_context *iscsi, return -1; } - if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) { - unsigned long crc; - - if (pdu->outdata.size < ISCSI_RAW_HEADER_SIZE + 4) { - iscsi_set_error(iscsi, "PDU too small (%u) to contain header digest", - (unsigned int) pdu->outdata.size); - return -1; - } - - crc = crc32c((char *)pdu->outdata.data, ISCSI_RAW_HEADER_SIZE); - - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+3] = (crc >> 24)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+2] = (crc >> 16)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+1] = (crc >> 8)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+0] = (crc) &0xff; - } - iscsi_add_to_outqueue(iscsi, pdu); return 0; From 55eacac42544a8e455aa29ba9fa3952e494c1477 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 12:33:47 +0100 Subject: [PATCH 5/8] login: add logging for the negotiation login parameters Signed-off-by: Peter Lieven --- lib/login.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/login.c b/lib/login.c index dd0e7ab..36de085 100644 --- a/lib/login.c +++ b/lib/login.c @@ -1217,6 +1217,8 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, must_have_chap_r = 0; } + ISCSI_LOG(iscsi, 6, "TargetLoginReply: %s", ptr); + ptr += len + 1; size -= len + 1; } From 443b104833718d130f94a0fa3e2cc8bdd6d02984 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 14:39:15 +0100 Subject: [PATCH 6/8] crc32c: use uint_t types Signed-off-by: Peter Lieven --- include/iscsi-private.h | 2 +- lib/crc32c.c | 6 +++--- lib/socket.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 60d216e..b9f38f7 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -355,7 +355,7 @@ void* iscsi_smalloc(struct iscsi_context *iscsi, size_t size); void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size); void iscsi_sfree(struct iscsi_context *iscsi, void* ptr); -unsigned long crc32c(char *buf, int len); +uint32_t crc32c(uint8_t *buf, int len); struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); diff --git a/lib/crc32c.c b/lib/crc32c.c index 0ae2cda..4455171 100644 --- a/lib/crc32c.c +++ b/lib/crc32c.c @@ -43,7 +43,7 @@ /* */ /*****************************************************************/ -static unsigned long crctable[256] = { +uint32_t crctable[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, @@ -110,9 +110,9 @@ static unsigned long crctable[256] = { 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; -unsigned long crc32c(char *buf, int len) +uint32_t crc32c(uint8_t *buf, int len) { - unsigned long crc = 0xffffffff; + uint32_t crc = 0xffffffff; while (len-- > 0) { crc = (crc>>8) ^ crctable[(crc ^ (*buf++)) & 0xFF]; } diff --git a/lib/socket.c b/lib/socket.c index caf51a5..3b32ba2 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -677,7 +677,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) static int iscsi_pdu_update_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { - unsigned long crc; + uint32_t crc; if (pdu->outdata.size < ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE) { iscsi_set_error(iscsi, "PDU too small (%u) to contain header digest", @@ -685,12 +685,12 @@ static int iscsi_pdu_update_headerdigest(struct iscsi_context *iscsi, struct isc return -1; } - crc = crc32c((char *)pdu->outdata.data, ISCSI_RAW_HEADER_SIZE); + crc = crc32c(pdu->outdata.data, ISCSI_RAW_HEADER_SIZE); - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+3] = (crc >> 24)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+2] = (crc >> 16)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+1] = (crc >> 8)&0xff; - pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+0] = (crc) &0xff; + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+3] = (crc >> 24); + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+2] = (crc >> 16); + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+1] = (crc >> 8); + pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+0] = (crc); return 0; } From 1cbeec6bdc951a2a4261d7060e286d6dc38dfa01 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 14:41:21 +0100 Subject: [PATCH 7/8] pdu: verify header digest we never verified the received header digest. do that now. Signed-off-by: Peter Lieven --- lib/pdu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/pdu.c b/lib/pdu.c index 1275b33..63adcc6 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" @@ -429,6 +430,20 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) uint8_t ahslen = in->hdr[4]; struct iscsi_pdu *pdu; + /* verify header checksum */ + if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) { + uint32_t crc, crc_rcvd = 0; + crc = crc32c(in->hdr, ISCSI_RAW_HEADER_SIZE); + crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+0]; + crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+1] << 8; + crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+2] << 16; + crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+3] << 24; + if (crc != crc_rcvd) { + iscsi_set_error(iscsi, "header checksum verification failed: calculated 0x%" PRIx32 " received 0x%" PRIx32, crc, crc_rcvd); + return -1; + } + } + if (ahslen != 0) { iscsi_set_error(iscsi, "cant handle expanded headers yet"); return -1; From 0225c662d0e1e7d9c75c219f98d583aee7a380e4 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 5 Jan 2017 14:47:51 +0100 Subject: [PATCH 8/8] socket: restore connected_portal info this got lost in commit 0d6362f Signed-off-by: Peter Lieven --- lib/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/socket.c b/lib/socket.c index 3b32ba2..8eee56d 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -366,6 +366,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, } freeaddrinfo(ai); + strncpy(iscsi->connected_portal, portal, MAX_STRING_SIZE); return 0; }