From 35cf3a401c95479c0e6414768161cdc014f105ca Mon Sep 17 00:00:00 2001 From: Anatoliy Glagolev Date: Tue, 26 Sep 2023 15:03:30 -0600 Subject: [PATCH 01/15] lun_reset cancelling lun tasks only The existing implementation of iscsi_task_mgmt_lun_reset_async cancels all tasks in ready-to-send and wait-for-completion queues. If the ISCSI context has in-flight tasks for a different LUNs or tasks that are not LUN-specific (such as NOPIN, NOPOUT), those tasks are not supposed to be affected by the LUN reset. Also, the tasks for the LUN being reset may have in-flight responses not affected by a concurrent LUN reset; they have to be handled accordingly. This change cancels only the tasks for the LUN being reset if they are in the ready-to-send queue ('outqueue'). The tasks in the wait-for- completion queue should be cancelled on LUN reset completion. For example: iscsi_task_mgmt_lun_reset_async(iscsi, lun, lun_reset_cb, ctxt); .... .... void lun_reset_cb(struct iscsi_context * iscsi, int status, void * command_data, void * private_data) { // 'response' field per ISCSI spec rfc7143 section 11.6.1 uint8_t iscsi_response = *(uint8_t *)command_data; if (iscsi_response == 0) { // The LUN has been reset. No further replies are expected // for in-flight tasks for that LUN. Explicitly cancelling // the tasks in wait-for-completion queue. for (.. scsi_task-s in flight ..) { iscsi_scsi_cancel_task(iscsi, task); } } ... } --- include/iscsi-private.h | 1 + lib/pdu.c | 33 +++++++++++++++++++++++++++++++++ lib/task_mgmt.c | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 82a328f..c9cab57 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -293,6 +293,7 @@ void iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt); void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn); void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset); void iscsi_cancel_pdus(struct iscsi_context *iscsi); +void iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun); int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, const unsigned char *dptr, int dsize); int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); diff --git a/lib/pdu.c b/lib/pdu.c index 702febe..ba20886 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -799,3 +799,36 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi) iscsi->drv->free_pdu(iscsi, pdu); } } + +void +iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun) +{ + struct iscsi_pdu *pdu; + struct iscsi_pdu *next_pdu; + uint32_t cmdsn_gap = 0; + struct scsi_task * task = NULL; + + for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) { + next_pdu = pdu->next; + task = iscsi_scsi_get_task_from_pdu(pdu); + + if (cmdsn_gap > 0) { + iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap); + } + if (task == NULL || task->lun != lun) { + continue; + } + if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) && + (pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { + iscsi->cmdsn--; + cmdsn_gap++; + } + ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu); + iscsi_set_error(iscsi, "command cancelled"); + if (pdu->callback) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, + NULL, pdu->private_data); + } + iscsi->drv->free_pdu(iscsi, pdu); + } +} diff --git a/lib/task_mgmt.c b/lib/task_mgmt.c index b0ad251..f3e6824 100644 --- a/lib/task_mgmt.c +++ b/lib/task_mgmt.c @@ -130,7 +130,7 @@ iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { - iscsi_scsi_cancel_all_tasks(iscsi); + iscsi_cancel_lun_pdus(iscsi, lun); return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_LUN_RESET, From 9ec12158b0d45d51509f16e762cc09b83f7a402f Mon Sep 17 00:00:00 2001 From: zeroway Date: Fri, 19 Jan 2024 17:41:54 +0800 Subject: [PATCH 02/15] Manually set task to null after free to avoid double free issue --- lib/scsi-lowlevel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 1b49853..0ced6a2 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -80,6 +80,8 @@ scsi_free_scsi_task(struct scsi_task *task) free(task->datain.data); free(task); + task->datain.data = NULL; + task = NULL; } struct scsi_task * From abedc1848cf6305f2c1f20078710755c66415d2d Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Tue, 30 Jan 2024 15:33:20 +0100 Subject: [PATCH 03/15] Fix for https://github.com/sahlberg/libiscsi/issues/409 'ms->pages' was not checked for being NULL. This can happen when a target does not return any pages. --- test-tool/iscsi-support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 9363140..0a36ddb 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -2735,7 +2735,7 @@ int set_swp(struct scsi_device *sdev) logging(LOG_VERBOSE, "[SUCCESS] CONTROL page fetched."); ms = scsi_datain_unmarshall(sense_task); - if (ms == NULL) { + if (ms == NULL || ms->pages == NULL) { logging(LOG_NORMAL, "failed to unmarshall mode sense datain " "blob"); ret = -1; From a51eafa90d8efaac3b0911bddc69780859bb23f8 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Tue, 30 Jan 2024 19:47:28 +0100 Subject: [PATCH 04/15] Previously, 'task->status' was printed as decimal. In iscsi.h, the values that are put into it are defined as hexadecimal. This is a bit confusing (grepping through the code for 251658241 did not result in anything while the hex variant f000001 resulted in SCSI_STATUS_ERROR). --- test-tool/iscsi-support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 0a36ddb..b89e7a0 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -202,7 +202,7 @@ static int check_result(const char *opcode, struct scsi_device *sdev, } if (status == SCSI_STATUS_GOOD && task->status != SCSI_STATUS_GOOD) { logging(LOG_NORMAL, - "[FAILED] %s command failed with status %d / sense key %s(0x%02x) / ASCQ %s(0x%04x)", + "[FAILED] %s command failed with status 0x%x / sense key %s(0x%02x) / ASCQ %s(0x%04x)", opcode, task->status, scsi_sense_key_str(task->sense.key), task->sense.key, scsi_sense_ascq_str(task->sense.ascq), task->sense.ascq); From d960e6253c04770062a7efedd8a92dd34a1ce7fe Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 5 Feb 2024 16:59:18 +1000 Subject: [PATCH 05/15] New version 1.20.0 Mostly various updates to the test tool Signed-off-by: Ronnie Sahlberg --- lib/Makefile.am | 2 +- packaging/RPM/libiscsi.spec.in | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index b81fd3d..4cc03a9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -45,7 +45,7 @@ endif EXTRA_libiscsi_la_DEPENDENCIES = libiscsi.syms -SOCURRENT=9 +SOCURRENT=10 SOREVISON=0 SOAGE=0 libiscsi_la_LDFLAGS = \ diff --git a/packaging/RPM/libiscsi.spec.in b/packaging/RPM/libiscsi.spec.in index 4afa9d3..457b701 100644 --- a/packaging/RPM/libiscsi.spec.in +++ b/packaging/RPM/libiscsi.spec.in @@ -1,6 +1,6 @@ Name: libiscsi Summary: iSCSI client library -Version: 1.19.0 +Version: 1.20.0 Release: 1GITHASH%{?dist} License: LGPLv2+ Group: System Environment/Libraries @@ -109,6 +109,8 @@ Test tool for iSCSI/SCSI targets %changelog +* Mon Feb 5 2024 : 1.20.0 + - Various updates to the test tool * Sun Jul 14 2019 : 1.19.0 - iSER improvements - Add support to senable/disable digests via URL arguments From 0be2be2c31e40d2bb04d599209958741cd103617 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 5 Feb 2024 21:19:00 +0300 Subject: [PATCH 06/15] COPYING: stop mentioning ld_scsi Fixes: e6bcdf5fdb "drop the LD_PRELOAD tool" Signed-off-by: Michael Tokarev --- COPYING | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/COPYING b/COPYING index dddde82..ac8d5bf 100644 --- a/COPYING +++ b/COPYING @@ -15,16 +15,8 @@ A copy of LGPL 2.1 is included in the file LICENCE-LGPL-2.1.txt but can also be This is the licence that applies to the libiscsi library and its use. -src/ld_iscsi.c -============== -This LD_PRELOAD utility is licenced under GNU Lesser General Public License -as published by the Free Software Foundation; either version 2.1 of the -License, or (at your option) any later version. - - - -The src, examples and test-tool directories EXCEPT src/ld_iscsi.c -============================================================= +The src, examples and test-tool directories +=========================================== The utility and example applications using this library, i.e. the src and the examples directories, are licenced under the GNU General Public License as published by the Free Software Foundation; either version 2 of the From 6e0206c135ecbedc2b58711f3f0498f14971b505 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 5 Feb 2024 20:55:39 +0300 Subject: [PATCH 07/15] spelling fixes: eventhough, shoudl, asyncronous, maxium, implicity These changes are carried in debian for a long time, some since 2016. The last one (implicity) is new in 1.20.0. Signed-off-by: Michael Tokarev --- packaging/RPM/libiscsi.spec.in | 2 +- test-tool/test_compareandwrite_miscompare.c | 4 ++-- test-tool/test_sanitize_block_erase.c | 2 +- test-tool/test_sanitize_reset.c | 2 +- utils/iscsi-perf.c | 2 +- utils/iscsi-pr.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packaging/RPM/libiscsi.spec.in b/packaging/RPM/libiscsi.spec.in index 457b701..4043761 100644 --- a/packaging/RPM/libiscsi.spec.in +++ b/packaging/RPM/libiscsi.spec.in @@ -231,7 +231,7 @@ Test tool for iSCSI/SCSI targets - Change all default iqn names so they are valid iqn names. * Mon Jul 9 2012 : 1.5.0 - Make sure we can handle racy eventsystems which might call us for - POLLIN eventhough there is no longer any data to read from the socket. + POLLIN even though there is no longer any data to read from the socket. - Only set up tcp keepalives on systems that support them. - Only export symbols we really want to make public - FreeBSD and Illumos does not define SOL_TCP diff --git a/test-tool/test_compareandwrite_miscompare.c b/test-tool/test_compareandwrite_miscompare.c index 04a9fb5..a8bdef3 100644 --- a/test-tool/test_compareandwrite_miscompare.c +++ b/test-tool/test_compareandwrite_miscompare.c @@ -95,7 +95,7 @@ test_compareandwrite_miscompare(void) for (j = 0; j < i * block_size; j++) { if (scratch[j] != 'A') { logging(LOG_VERBOSE, "[FAILED] Data changed " - "eventhough there was a miscompare"); + "even though there was a miscompare"); CU_FAIL("Block was written to"); return; } @@ -151,7 +151,7 @@ test_compareandwrite_miscompare(void) for (j = 0; j < i * block_size; j++) { if (scratch[j] != 'A') { logging(LOG_VERBOSE, "[FAILED] Data changed " - "eventhough there was a miscompare"); + "even though there was a miscompare"); CU_FAIL("Block was written to"); return; } diff --git a/test-tool/test_sanitize_block_erase.c b/test-tool/test_sanitize_block_erase.c index 15940be..cea72b9 100644 --- a/test-tool/test_sanitize_block_erase.c +++ b/test-tool/test_sanitize_block_erase.c @@ -161,7 +161,7 @@ check_unmap(void) lbas->descriptors[i].lba + lbas->descriptors[i].num_blocks); if (lbas->descriptors[i].provisioning == SCSI_PROVISIONING_TYPE_MAPPED) { logging(LOG_VERBOSE, "[FAILED] Descriptor %d is MAPPED." - "All descriptors shoudl be either DEALLOCATED " + "All descriptors should be either DEALLOCATED " "or ANCHORED after SANITIZE", i); CU_FAIL("[FAILED] LBA status descriptor is MAPPED."); } diff --git a/test-tool/test_sanitize_reset.c b/test-tool/test_sanitize_reset.c index fffc55a..eed451f 100644 --- a/test-tool/test_sanitize_reset.c +++ b/test-tool/test_sanitize_reset.c @@ -58,7 +58,7 @@ test_sanitize_reset(void) return; } - logging(LOG_VERBOSE, "Send an asyncronous SANITIZE to the target."); + logging(LOG_VERBOSE, "Send an asynchronous SANITIZE to the target."); data.size = block_size + 4; data.data = alloca(data.size); memset(&data.data[4], 0, block_size); diff --git a/utils/iscsi-perf.c b/utils/iscsi-perf.c index b43d949..f2f6aee 100644 --- a/utils/iscsi-perf.c +++ b/utils/iscsi-perf.c @@ -151,7 +151,7 @@ void cb(struct iscsi_context *iscsi, int status, void *command_data, void *priva if (status == SCSI_STATUS_BUSY || (status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_UNIT_ATTENTION)) { if (client->retry_cnt++ > 4 * max_in_flight) { - fprintf(stderr, "maxium number of command retries reached...\n"); + fprintf(stderr, "maximum number of command retries reached...\n"); client->err_cnt++; goto out; } diff --git a/utils/iscsi-pr.c b/utils/iscsi-pr.c index 309e6ca..71ae48c 100644 --- a/utils/iscsi-pr.c +++ b/utils/iscsi-pr.c @@ -236,7 +236,7 @@ static void print_help(const char *bin) fprintf(stderr, " -S, --param-sark=SARK PR Out: parameter service action reservation key (SARK is in hex)\n"); fprintf(stderr, " -T, --prout-type=TYPE PR Out: type field\n"); fprintf(stderr, " -G, --register PR Out: Register\n"); - fprintf(stderr, " -R, --reserve PR Out: Reserve, SARK only(register sark implicity)\n"); + fprintf(stderr, " -R, --reserve PR Out: Reserve, SARK only(register sark implicitly)\n"); fprintf(stderr, " -L, --release PR Out: Release, SARK only. This program releases TYPE 7 and TYPE 8 only\n"); fprintf(stderr, " -C, --clear PR Out: Clear, SARK only\n"); fprintf(stderr, " -P, --preempt PR Out: Preempt, use SARK to preempt reservation from RK\n"); From 5fc2dcb88f2d8b52e83952f2dd3eedcdba383f71 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Wed, 14 Feb 2024 00:44:26 +0100 Subject: [PATCH 08/15] A possible 'fix' for https://github.com/sahlberg/libiscsi/issues/415 This patch adds a timestamp before each logged line. That could help correlating a logging to a network-trace. Because of offsets in time between the tracer and the test and the DUT, this does not always help. --- test-tool/iscsi-support.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index b89e7a0..9375952 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -457,6 +457,8 @@ void logging(int level, const char *format, ...) va_list ap; static char message[1024]; int ret; + struct timespec ts; + struct tm tm; if (loglevel < level) { return; @@ -467,6 +469,17 @@ void logging(int level, const char *format, ...) return; } + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + return; + } + + if (!localtime_r(&ts.tv_sec, &tm)) { + return; + } + + printf(" %04d-%02d-%02d %02d:%02d:%02d.%06d ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)ts.tv_nsec / 1000); + va_start(ap, format); ret = vsnprintf(message, 1024, format, ap); va_end(ap); From 380c16a82b96dfde2700c60938a2ffc021b33bf2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 9 Apr 2024 14:52:38 +0200 Subject: [PATCH 09/15] configure: add --with-libgcrypt option libgcrypt is a relatively large dependency that is used only for the sake of computing MD5 in the CHAP authentication protocol. Allow distributions to disable it forcibly and rely on the embedded MD5 implementation. Signed-off-by: Paolo Bonzini --- configure.ac | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c81b916..b7d214f 100644 --- a/configure.ac +++ b/configure.ac @@ -78,8 +78,21 @@ AM_CONDITIONAL([BUILD_EXAMPLES], AC_CONFIG_HEADERS([config.h]) -AC_CHECK_LIB([gcrypt], [gcry_control]) -AM_CONDITIONAL([HAVE_LIBGCRYPT], [test $ac_cv_lib_gcrypt_gcry_control = yes]) +AC_ARG_WITH([libgcrypt], + [AS_HELP_STRING([--with-libgcrypt], + [Use libgcrypt to compute MD5])], + [WITH_LIBGCRYPT=$withval], + [WITH_LIBGCRYPT=auto]) +if test "$WITH_LIBGCRYPT" != no; then + AC_CHECK_LIB([gcrypt], [gcry_control]) + if test "$WITH_LIBGCRYPT" = yes && test "$ac_cv_lib_gcrypt_gcry_control" != yes; then + AC_MSG_ERROR([libgcrypt not found]) + fi + WITH_LIBGCRYPT=$ac_cv_lib_gcrypt_gcry_control +fi + +AM_CONDITIONAL([HAVE_LIBGCRYPT], + [expr "$WITH_LIBGCRYPT" : yes > /dev/null 2>&1]) # For MinGW. AC_CHECK_LIB([ws2_32], [gethostbyname]) From e07472a3370edf59e7293f7bd5b273187b3f84d5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 9 Apr 2024 15:24:57 +0200 Subject: [PATCH 10/15] login: do not try to "emulate" the libgcrypt API Implement a more generic wrapper API for message digests, so that it is easier to also include gnutls as an option. Signed-off-by: Paolo Bonzini --- lib/login.c | 64 +++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/lib/login.c b/lib/login.c index 8251d16..03c4a7d 100644 --- a/lib/login.c +++ b/lib/login.c @@ -681,41 +681,48 @@ i2h(int i) return i + '0'; } -#ifndef HAVE_LIBGCRYPT -typedef struct MD5Context *gcry_md_hd_t; -#define gcry_md_write MD5Update -#define GCRY_MD_MD5 1 +#ifdef HAVE_LIBGCRYPT +typedef gcry_md_hd_t md5_context_t; +#define md5_open(hd) gcry_md_open(hd, GCRY_MD_MD5, 0) +#define md5_write gcry_md_write +#define md5_close gcry_md_close -static void gcry_md_open(gcry_md_hd_t *hd, int algo, unsigned int flags) +static void md5_read(md5_context_t h, uint8_t *result) +{ + memcpy(result, gcry_md_read(h, 0), 16); +} +#else +typedef struct MD5Context *md5_context_t; +#define md5_write MD5Update + +static void md5_open(md5_context_t *hd) { - assert(algo == GCRY_MD_MD5 && flags == 0); *hd = malloc(sizeof(struct MD5Context)); if (*hd) { MD5Init(*hd); } } -static void gcry_md_putc(gcry_md_hd_t h, unsigned char c) -{ - MD5Update(h, &c, 1); -} - -static char *gcry_md_read(gcry_md_hd_t h, int algo) +static void md5_read(md5_context_t h, uint8_t *result) { unsigned char digest[16]; - assert(algo == 0 || algo == GCRY_MD_MD5); MD5Final(digest, h); - return memcpy(h->buf, digest, sizeof(digest)); + memcpy(result, digest, sizeof(digest)); } -static void gcry_md_close(gcry_md_hd_t h) +static void md5_close(md5_context_t h) { memset(h, 0, sizeof(*h)); free(h); } #endif +static inline void md5_putc(md5_context_t h, unsigned char c) +{ + md5_write(h, &c, 1); +} + /* size of the challenge used for bidirectional chap */ #define TARGET_CHAP_C_SIZE 32 @@ -726,7 +733,7 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu char * strp; unsigned char c, cc[2]; unsigned char digest[CHAP_R_SIZE]; - gcry_md_hd_t ctx; + md5_context_t ctx; int i; if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG @@ -739,22 +746,22 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu return -1; } - gcry_md_open(&ctx, GCRY_MD_MD5, 0); + md5_open(&ctx); if (ctx == NULL) { iscsi_set_error(iscsi, "Cannot create MD5 algorithm"); return -1; } - gcry_md_putc(ctx, iscsi->chap_i); - gcry_md_write(ctx, (unsigned char *)iscsi->passwd, strlen(iscsi->passwd)); + md5_putc(ctx, iscsi->chap_i); + md5_write(ctx, (unsigned char *)iscsi->passwd, strlen(iscsi->passwd)); strp = iscsi->chap_c; while (*strp != 0) { c = (h2i(strp[0]) << 4) | h2i(strp[1]); strp += 2; - gcry_md_putc(ctx, c); + md5_putc(ctx, c); } - memcpy(digest, gcry_md_read(ctx, 0), sizeof(digest)); - gcry_md_close(ctx); + md5_read(ctx, digest); + md5_close(ctx); strncpy(str,"CHAP_R=0x",MAX_STRING_SIZE); if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)) @@ -822,20 +829,19 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu return -1; } - gcry_md_open(&ctx, GCRY_MD_MD5, 0); + md5_open(&ctx); if (ctx == NULL) { iscsi_set_error(iscsi, "Cannot create MD5 algorithm"); return -1; } - gcry_md_putc(ctx, iscsi->target_chap_i); - gcry_md_write(ctx, (unsigned char *)iscsi->target_passwd, + md5_putc(ctx, iscsi->target_chap_i); + md5_write(ctx, (unsigned char *)iscsi->target_passwd, strlen(iscsi->target_passwd)); - gcry_md_write(ctx, (unsigned char *)target_chap_c, + md5_write(ctx, (unsigned char *)target_chap_c, TARGET_CHAP_C_SIZE); - memcpy(iscsi->target_chap_r, gcry_md_read(ctx, 0), - sizeof(iscsi->target_chap_r)); - gcry_md_close(ctx); + md5_read(ctx, iscsi->target_chap_r); + md5_close(ctx); } return 0; From 35fec3ea0ef5c3c068f698e1b2a94695522f8e47 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 9 Apr 2024 15:43:02 +0200 Subject: [PATCH 11/15] login: add support for gnutls Signed-off-by: Paolo Bonzini --- configure.ac | 26 ++++++++++++++++++++++++-- lib/Makefile.am | 2 +- lib/login.c | 19 ++++++++++++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index b7d214f..13ae3bb 100644 --- a/configure.ac +++ b/configure.ac @@ -78,11 +78,29 @@ AM_CONDITIONAL([BUILD_EXAMPLES], AC_CONFIG_HEADERS([config.h]) +AC_ARG_WITH([gnutls], + [AS_HELP_STRING([--with-gnutls], + [Use gnutls to compute MD5])], + [WITH_GNUTLS=$withval], + [WITH_GNUTLS=auto]) + AC_ARG_WITH([libgcrypt], [AS_HELP_STRING([--with-libgcrypt], [Use libgcrypt to compute MD5])], [WITH_LIBGCRYPT=$withval], [WITH_LIBGCRYPT=auto]) + +if test "$WITH_GNUTLS" != no; then + AC_CHECK_LIB([gnutls], [gnutls_hash_init]) + if test "$WITH_GNUTLS" = yes && test "$ac_cv_lib_gnutls_gnutls_hash_init" != yes; then + AC_MSG_ERROR([gnutls not found]) + fi + WITH_GNUTLS=$ac_cv_lib_gnutls_gnutls_hash_init +fi +if test "$WITH_GNUTLS" = yes; then + WITH_LIBGCRYPT=no +fi + if test "$WITH_LIBGCRYPT" != no; then AC_CHECK_LIB([gcrypt], [gcry_control]) if test "$WITH_LIBGCRYPT" = yes && test "$ac_cv_lib_gcrypt_gcry_control" != yes; then @@ -91,8 +109,12 @@ if test "$WITH_LIBGCRYPT" != no; then WITH_LIBGCRYPT=$ac_cv_lib_gcrypt_gcry_control fi -AM_CONDITIONAL([HAVE_LIBGCRYPT], - [expr "$WITH_LIBGCRYPT" : yes > /dev/null 2>&1]) +NEED_MD5=no +if test "$WITH_GNUTLS" = no && test "$WITH_LIBGCRYPT" = no; then + NEED_MD5=yes +fi +AM_CONDITIONAL([NEED_MD5], + [expr "$NEED_MD5" : yes > /dev/null 2>&1]) # For MinGW. AC_CHECK_LIB([ws2_32], [gethostbyname]) diff --git a/lib/Makefile.am b/lib/Makefile.am index 4cc03a9..ba6aaee 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -12,7 +12,7 @@ if TARGET_OS_IS_WIN32 libiscsipriv_la_SOURCES += ../win32/win32_compat.c endif -if !HAVE_LIBGCRYPT +if NEED_MD5 libiscsipriv_la_SOURCES += md5.c endif diff --git a/lib/login.c b/lib/login.c index 03c4a7d..5177201 100644 --- a/lib/login.c +++ b/lib/login.c @@ -44,6 +44,10 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "md5.h" + +#ifdef HAVE_LIBGNUTLS +#include +#endif #ifdef HAVE_LIBGCRYPT #include #endif @@ -681,7 +685,20 @@ i2h(int i) return i + '0'; } -#ifdef HAVE_LIBGCRYPT +#if defined HAVE_LIBGNUTLS +#define md5_context_t gnutls_hash_hd_t +#define md5_open(hd) gnutls_hash_init(hd, GNUTLS_DIG_MD5) +#define md5_write gnutls_hash +#define md5_read gnutls_hash_output + +static void md5_close(md5_context_t h) +{ + unsigned char digest[16]; + + gnutls_hash_deinit(h, digest); +} + +#elif defined HAVE_LIBGCRYPT typedef gcry_md_hd_t md5_context_t; #define md5_open(hd) gcry_md_open(hd, GCRY_MD_MD5, 0) #define md5_write gcry_md_write From 882bcad53ae024474742275796a2e3f8c61bdd6b Mon Sep 17 00:00:00 2001 From: Brian Meagher Date: Sat, 4 May 2024 18:54:21 -0700 Subject: [PATCH 12/15] Add support for Data Digest --- README.md | 10 +++++ include/iscsi-private.h | 14 +++++++ include/iscsi.h | 23 +++++++++++ lib/connect.c | 1 + lib/crc32c.c | 19 +++++++++ lib/init.c | 59 ++++++++++++++++++++------ lib/libiscsi.def | 1 + lib/libiscsi.syms.in | 1 + lib/login.c | 30 +++++++++++++- lib/pdu.c | 22 ++++++++++ lib/socket.c | 91 +++++++++++++++++++++++++++++++++++++++-- 11 files changed, 254 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 15f9de6..572be0a 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Username and password for bidirectional CHAP authentication: target_user= target_password= header_digest= +data_digest= Transport: iser @@ -125,6 +126,15 @@ be overridden by an application by calling iscsi_set_header_digest() if the application wants to force a specific setting. +Data Digest +=========== + +Libiscsi supports DataDigest. By default, libiscsi will offer None so that +Data digest will not be used, no matter what the target setting is. This can +be overridden by an application by calling iscsi_set_data_digest() if the +application wants to force a specific setting. + + Patches ======= diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 82a328f..63ea17d 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -61,6 +61,13 @@ struct iscsi_in_pdu { long long data_pos; unsigned char *data; + + /* + * Some data structures wrt Data Digest (if negociated) + */ + unsigned char data_digest_buf[ISCSI_DIGEST_SIZE]; + int received_data_digest_bytes; + uint32_t calculated_data_digest; }; void iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); @@ -105,6 +112,8 @@ struct iscsi_context { uint32_t statsn; enum iscsi_header_digest want_header_digest; enum iscsi_header_digest header_digest; + enum iscsi_data_digest want_data_digest; + enum iscsi_data_digest data_digest; int fd; int is_connected; @@ -272,6 +281,8 @@ struct iscsi_pdu { struct iscsi_scsi_cbdata scsi_cbdata; time_t scsi_timeout; uint32_t expxferlen; + + uint32_t calculated_data_digest; }; struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, @@ -350,6 +361,9 @@ void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size); void iscsi_sfree(struct iscsi_context *iscsi, void* ptr); uint32_t crc32c(uint8_t *buf, int len); +void crc32c_init(uint32_t *crc_ptr); +uint32_t crc32c_chain(uint32_t crc, uint8_t *buf, int len); +uint32_t crc32c_chain_done(uint32_t crc); struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); diff --git a/include/iscsi.h b/include/iscsi.h index 8196f64..af557e7 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -335,6 +335,29 @@ enum iscsi_header_digest { EXTERN int iscsi_set_header_digest(struct iscsi_context *iscsi, enum iscsi_header_digest header_digest); +/* + * Types of data digest we support. Default is NONE + */ +enum iscsi_data_digest { + ISCSI_DATA_DIGEST_NONE = 0, + ISCSI_DATA_DIGEST_NONE_CRC32C = 1, + ISCSI_DATA_DIGEST_CRC32C_NONE = 2, + ISCSI_DATA_DIGEST_CRC32C = 3, + ISCSI_DATA_DIGEST_LAST = ISCSI_DATA_DIGEST_CRC32C +}; + +/* + * Set the desired data digest for a scsi context. + * Data digest can only be set/changed before the context + * is logged in to the target. + * + * Returns: + * 0: success + * <0: error + */ +EXTERN int iscsi_set_data_digest(struct iscsi_context *iscsi, + enum iscsi_data_digest data_digest); + /* * Specify the username and password to use for chap authentication */ diff --git a/lib/connect.c b/lib/connect.c index 5234e46..1960ef2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -431,6 +431,7 @@ static int reconnect(struct iscsi_context *iscsi, int force) iscsi_set_targetname(tmp_iscsi, iscsi->target_name); iscsi_set_header_digest(tmp_iscsi, iscsi->want_header_digest); + iscsi_set_data_digest(tmp_iscsi, iscsi->want_data_digest); iscsi_set_initiator_username_pwd(tmp_iscsi, iscsi->user, iscsi->passwd); iscsi_set_target_username_pwd(tmp_iscsi, iscsi->target_user, iscsi->target_passwd); diff --git a/lib/crc32c.c b/lib/crc32c.c index 10180ba..313cad0 100644 --- a/lib/crc32c.c +++ b/lib/crc32c.c @@ -118,3 +118,22 @@ uint32_t crc32c(uint8_t *buf, int len) return crc^0xffffffff; } +void crc32c_init(uint32_t *crc_ptr) +{ + if (crc_ptr) + *crc_ptr = 0xffffffff; +} + +uint32_t crc32c_chain(uint32_t crc, uint8_t *buf, int len) +{ + while (len-- > 0) { + crc = (crc>>8) ^ crctable[(crc ^ (*buf++)) & 0xFF]; + } + return crc; +} + +uint32_t crc32c_chain_done(uint32_t crc) +{ + return crc^0xffffffff; +} + diff --git a/lib/init.c b/lib/init.c index 6bcc761..cb3baeb 100644 --- a/lib/init.c +++ b/lib/init.c @@ -244,6 +244,7 @@ iscsi_create_context(const char *initiator_name) iscsi->want_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C; + iscsi->want_data_digest = ISCSI_DATA_DIGEST_NONE; iscsi->tcp_keepcnt=3; iscsi->tcp_keepintvl=30; @@ -492,6 +493,25 @@ iscsi_set_header_digest(struct iscsi_context *iscsi, return 0; } +int +iscsi_set_data_digest(struct iscsi_context *iscsi, + enum iscsi_data_digest data_digest) +{ + if (iscsi->is_loggedin) { + iscsi_set_error(iscsi, "trying to set data digest while " + "logged in"); + return -1; + } + if ((unsigned)data_digest > ISCSI_DATA_DIGEST_LAST) { + iscsi_set_error(iscsi, "invalid data digest value"); + return -1; + } + + iscsi->want_data_digest = data_digest; + + return 0; +} + int iscsi_is_logged_in(struct iscsi_context *iscsi) { @@ -602,19 +622,32 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full) if (value != NULL) { *value++ = 0; } - if (!strcmp(key, "header_digest")) { - if (!strcmp(value, "crc32c")) { - iscsi_set_header_digest( - iscsi, ISCSI_HEADER_DIGEST_CRC32C); - } else if (!strcmp(value, "none")) { - iscsi_set_header_digest( - iscsi, ISCSI_HEADER_DIGEST_NONE); - } else { - iscsi_set_error(iscsi, - "Invalid URL argument for header_digest: %s", value); - return NULL; - } - } + if (!strcmp(key, "header_digest")) { + if (!strcmp(value, "crc32c")) { + iscsi_set_header_digest( + iscsi, ISCSI_HEADER_DIGEST_CRC32C); + } else if (!strcmp(value, "none")) { + iscsi_set_header_digest( + iscsi, ISCSI_HEADER_DIGEST_NONE); + } else { + iscsi_set_error(iscsi, + "Invalid URL argument for header_digest: %s", value); + return NULL; + } + } + if (!strcmp(key, "data_digest")) { + if (!strcmp(value, "crc32c")) { + iscsi_set_data_digest( + iscsi, ISCSI_DATA_DIGEST_CRC32C); + } else if (!strcmp(value, "none")) { + iscsi_set_data_digest( + iscsi, ISCSI_DATA_DIGEST_NONE); + } else { + iscsi_set_error(iscsi, + "Invalid URL argument for data_digest: %s", value); + return NULL; + } + } if (!strcmp(key, "target_user")) { target_user = value; } else if (!strcmp(key, "target_password")) { diff --git a/lib/libiscsi.def b/lib/libiscsi.def index c56fe59..6b59726 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -115,6 +115,7 @@ iscsi_set_initial_r2t iscsi_set_log_level iscsi_set_log_fn iscsi_set_header_digest +iscsi_set_data_digest iscsi_set_initiator_username_pwd iscsi_set_isid_en iscsi_set_isid_oui diff --git a/lib/libiscsi.syms.in b/lib/libiscsi.syms.in index 2eb50a7..daf2b0f 100644 --- a/lib/libiscsi.syms.in +++ b/lib/libiscsi.syms.in @@ -116,6 +116,7 @@ iscsi_set_alias iscsi_set_bind_interfaces iscsi_set_cache_allocations iscsi_set_header_digest +iscsi_set_data_digest iscsi_set_immediate_data iscsi_set_initial_r2t iscsi_set_initiator_username_pwd diff --git a/lib/login.c b/lib/login.c index 5177201..268c409 100644 --- a/lib/login.c +++ b/lib/login.c @@ -206,7 +206,24 @@ iscsi_login_add_datadigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) return 0; } - strncpy(str,"DataDigest=None",MAX_STRING_SIZE); + switch (iscsi->want_data_digest) { + case ISCSI_DATA_DIGEST_NONE: + strncpy(str,"DataDigest=None",MAX_STRING_SIZE); + break; + case ISCSI_DATA_DIGEST_NONE_CRC32C: + strncpy(str,"DataDigest=None,CRC32C",MAX_STRING_SIZE); + break; + case ISCSI_DATA_DIGEST_CRC32C_NONE: + strncpy(str,"DataDigest=CRC32C,None",MAX_STRING_SIZE); + break; + case ISCSI_DATA_DIGEST_CRC32C: + strncpy(str,"DataDigest=CRC32C",MAX_STRING_SIZE); + break; + default: + iscsi_set_error(iscsi, "invalid data digest value"); + return -1; + } + if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); @@ -1223,6 +1240,16 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, } } + if (!strncmp(ptr, "DataDigest=", 11)) { + if (!strcmp(ptr + 11, "CRC32C")) { + iscsi->want_data_digest + = ISCSI_DATA_DIGEST_CRC32C; + } else { + iscsi->want_data_digest + = ISCSI_DATA_DIGEST_NONE; + } + } + if (!strncmp(ptr, "FirstBurstLength=", 17)) { iscsi->first_burst_length = strtol(ptr + 17, NULL, 10); } @@ -1393,6 +1420,7 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, iscsi->is_loggedin = 1; iscsi_itt_post_increment(iscsi); iscsi->header_digest = iscsi->want_header_digest; + iscsi->data_digest = iscsi->want_data_digest; ISCSI_LOG(iscsi, 2, "login successful"); pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); } else { diff --git a/lib/pdu.c b/lib/pdu.c index 5a97e43..3ef9871 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -225,6 +225,9 @@ iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, /* flags */ pdu->flags = flags; + /* DataDigest - may or may not be calculated. Initialize anyway. */ + crc32c_init(&pdu->calculated_data_digest); + return pdu; } @@ -537,6 +540,25 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) } } + /* verify data checksum ... */ + if (iscsi->data_digest != ISCSI_DATA_DIGEST_NONE) { + int dsl = scsi_get_uint32(&in->hdr[4]) & 0x00ffffff; + /* ... but only if some data is present. */ + if (dsl) { + uint32_t crc_rcvd = 0; + uint32_t crc = crc32c_chain_done(in->calculated_data_digest); + + crc_rcvd |= in->data_digest_buf[0]; + crc_rcvd |= in->data_digest_buf[1] << 8; + crc_rcvd |= in->data_digest_buf[2] << 16; + crc_rcvd |= in->data_digest_buf[3] << 24; + if (crc != crc_rcvd) { + iscsi_set_error(iscsi, "data 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; diff --git a/lib/socket.c b/lib/socket.c index db7f667..d8fbfc9 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -62,6 +62,7 @@ #include #endif +#include #include #include #include @@ -514,7 +515,7 @@ iscsi_out_queue_length(struct iscsi_context *iscsi) } ssize_t -iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *iovector, uint32_t pos, ssize_t count, int do_write) +iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *iovector, uint32_t pos, ssize_t count, uint32_t *data_digest_ptr, int do_write) { struct scsi_iovec *iov, *iov2; int niov; @@ -598,6 +599,19 @@ iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *i n = readv(iscsi->fd, (struct iovec*) iov, niov); } + /* Update the data digest */ + if (data_digest_ptr && n > 0) { + int i; + size_t bytes_to_crc = n; + struct iovec *iov_ptr = (struct iovec*)iov; + + for ( i=0; iov_ptr && iiov_len); + *data_digest_ptr = crc32c_chain(*data_digest_ptr, iov_ptr->iov_base, chunk); + bytes_to_crc -= chunk; + } + } + /* restore original values */ iov->iov_base = (void*) ((uintptr_t)iov->iov_base - pos); iov->iov_len += pos; @@ -619,6 +633,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) { struct iscsi_in_pdu *in; ssize_t hdr_size, data_size, count, padding_size; + bool do_data_digest = (iscsi->data_digest != ISCSI_DATA_DIGEST_NONE); do { hdr_size = ISCSI_HEADER_SIZE(iscsi->header_digest); @@ -628,6 +643,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu"); return -1; } + crc32c_init(&(iscsi->incoming->calculated_data_digest)); iscsi->incoming->hdr = iscsi_smalloc(iscsi, hdr_size); if (iscsi->incoming->hdr == NULL) { iscsi_set_error(iscsi, "Out-of-memory"); @@ -682,7 +698,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) iovector_in = iscsi_get_scsi_task_iovector_in(iscsi, in); if (iovector_in != NULL && count > padding_size) { uint32_t offset = scsi_get_uint32(&in->hdr[40]); - count = iscsi_iovector_readv_writev(iscsi, iovector_in, in->data_pos + offset, count - padding_size, 0); + count = iscsi_iovector_readv_writev(iscsi, iovector_in, in->data_pos + offset, count - padding_size, do_data_digest ? &(in->calculated_data_digest) : NULL, 0); } else { if (iovector_in == NULL) { if (in->data == NULL) { @@ -695,6 +711,8 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) buf = &in->data[in->data_pos]; } count = recv(iscsi->fd, (void *)buf, count, 0); + if (do_data_digest && count > 0) + in->calculated_data_digest = crc32c_chain(in->calculated_data_digest, buf, count); } if (count == 0) { /* remote side has closed the socket. */ @@ -713,6 +731,28 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) break; } + /* Handle Data Digest receive */ + if (data_size != 0 && do_data_digest && + in->received_data_digest_bytes < ISCSI_DIGEST_SIZE) { + + count = recv(iscsi->fd, (void *)(in->data_digest_buf + in->received_data_digest_bytes), ISCSI_DIGEST_SIZE - in->received_data_digest_bytes, 0); + if (count == 0) { + /* remote side has closed the socket. */ + return -1; + } + if (count < 0) { + if (errno == EINTR || errno == EAGAIN) { + break; + } + return -1; + } + in->received_data_digest_bytes += count; + + if (in->received_data_digest_bytes < ISCSI_DIGEST_SIZE) { + break; + } + } + iscsi->incoming = NULL; if (iscsi_process_pdu(iscsi, in) != 0) { iscsi_free_iscsi_in_pdu(iscsi, in); @@ -751,6 +791,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) struct iscsi_pdu *pdu; static char padding_buf[3]; int socket_flags = 0; + bool do_data_digest = (iscsi->data_digest != ISCSI_DATA_DIGEST_NONE); #ifdef MSG_NOSIGNAL socket_flags |= MSG_NOSIGNAL; @@ -848,7 +889,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) count = iscsi_iovector_readv_writev(iscsi, iovector_out, pdu->payload_offset + pdu->payload_written, - pdu->payload_len - pdu->payload_written, 1); + pdu->payload_len - pdu->payload_written, do_data_digest ? &(pdu->calculated_data_digest) : NULL, 1); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; @@ -873,12 +914,56 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) "socket :%d", errno); return -1; } + + if (do_data_digest) + pdu->calculated_data_digest = crc32c_chain(pdu->calculated_data_digest, (uint8_t *)padding_buf, count); + pdu->payload_written += count; } + /* if we havent written the full padding yet. */ + if (pdu->payload_written < total) { + return 0; + } + + /* + * Maybe update the total again, and write the digest, but only if + * 1. DataDigest has been negociated, and + * 2. We have actually written some data + */ + if (do_data_digest && pdu->payload_written) { + uint32_t data_digest = crc32c_chain_done(pdu->calculated_data_digest); + char data_digest_buf[ISCSI_DIGEST_SIZE]; + + total += ISCSI_DIGEST_SIZE; + + data_digest_buf[3] = (data_digest >> 24); + data_digest_buf[2] = (data_digest >> 16); + data_digest_buf[1] = (data_digest >> 8); + data_digest_buf[0] = (data_digest); + + /* Write data digest */ + if (pdu->payload_written < total) { + int todo = total - pdu->payload_written; + count = send(iscsi->fd, data_digest_buf + (ISCSI_DIGEST_SIZE - todo), todo, socket_flags); + if (count == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return 0; + } + iscsi_set_error(iscsi, "Error when writing to " + "socket :%d", errno); + return -1; + } + + pdu->payload_written += count; + } + } + + /* if we havent written everything yet. */ if (pdu->payload_written != total) { return 0; } + if (pdu->flags & ISCSI_PDU_CORK_WHEN_SENT) { iscsi->is_corked = 1; } From b25ee4f0c4e6a27c2f1fa6b9734d6244295a9ac4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 30 May 2024 07:49:48 +1000 Subject: [PATCH 13/15] fix use after free in recent commit Signed-off-by: Ronnie Sahlberg --- lib/scsi-lowlevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 0ced6a2..e23ec0d 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -79,8 +79,8 @@ scsi_free_scsi_task(struct scsi_task *task) } free(task->datain.data); - free(task); task->datain.data = NULL; + free(task); task = NULL; } From 393d5e5204f96482bf64d144b138c254773be665 Mon Sep 17 00:00:00 2001 From: Han Han Date: Sat, 14 Sep 2024 15:07:51 +0800 Subject: [PATCH 14/15] Add utils.h to dist_noinst_HEADERS Fix the compiling error when runing packaging/RPM/makerpms.sh: libtool: compile: gcc -DHAVE_CONFIG_H -I. -I.. -I./../include -I./include -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wcast-qual -Wvla -Wno-unknown-warning-option -Wno-stringop-truncation -Wno-unused-parameter -Werror -Wwrite-strings -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -c sync.c -o libiscsipriv_la-sync.o >/dev/null 2>&1 scsi-lowlevel.c:59:10: fatal error: utils.h: No such file or directory 59 | #include "utils.h" | ^~~~~~~~~ Signed-off-by: Han Han --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index bd2ca58..abefb53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,5 +29,5 @@ pkgconfig_DATA = libiscsi.pc iscsi_includedir = $(includedir)/iscsi dist_iscsi_include_HEADERS = include/iscsi.h include/scsi-lowlevel.h dist_noinst_HEADERS = include/iscsi-private.h include/md5.h include/slist.h \ - include/iser-private.h + include/iser-private.h include/utils.h From 7d4becaeb4167482a2ea8fc42af5a824795175f2 Mon Sep 17 00:00:00 2001 From: Han Han Date: Sat, 14 Sep 2024 15:27:54 +0800 Subject: [PATCH 15/15] install binaries and manpage to rpm Add these files to libiscsi-utils package: - /usr/bin/iscsi-discard - /usr/bin/iscsi-md5sum - /usr/bin/iscsi-pr - /usr/share/man/man1/iscsi-md5sum.1.gz Signed-off-by: Han Han --- packaging/RPM/libiscsi.spec.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packaging/RPM/libiscsi.spec.in b/packaging/RPM/libiscsi.spec.in index 4043761..19602b0 100644 --- a/packaging/RPM/libiscsi.spec.in +++ b/packaging/RPM/libiscsi.spec.in @@ -75,9 +75,13 @@ to iSCSI servers without having to set up the Linux iSCSI initiator. %{_bindir}/iscsi-perf %{_bindir}/iscsi-readcapacity16 %{_bindir}/iscsi-swp +%{_bindir}/iscsi-discard +%{_bindir}/iscsi-md5sum +%{_bindir}/iscsi-pr %{_mandir}/man1/iscsi-inq.1.gz %{_mandir}/man1/iscsi-ls.1.gz %{_mandir}/man1/iscsi-swp.1.gz +%{_mandir}/man1/iscsi-md5sum.1.gz %package devel Summary: iSCSI client development libraries