Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libiscsi for openSUSE:Factory checked in at 2024-06-09 20:19:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libiscsi (Old) and /work/SRC/openSUSE:Factory/.libiscsi.new.19518 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libiscsi" Sun Jun 9 20:19:00 2024 rev:25 rq:1179242 version:1.20.0+git.20240530 Changes: -------- --- /work/SRC/openSUSE:Factory/libiscsi/libiscsi.changes 2024-03-01 23:34:58.912105856 +0100 +++ /work/SRC/openSUSE:Factory/.libiscsi.new.19518/libiscsi.changes 2024-06-09 20:19:19.643630576 +0200 @@ -1,0 +2,13 @@ +Fri Jun 7 13:49:23 UTC 2024 - Martin Pluskal <mplus...@suse.com> + +- Update to version 1.20.0+git.20240530: + * fix use after free in recent commit + * Add support for Data Digest + * login: add support for gnutls + * login: do not try to "emulate" the libgcrypt API + * configure: add --with-libgcrypt option + * 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. + * Manually set task to null after free to avoid double free issue + * lun_reset cancelling lun tasks only + +------------------------------------------------------------------- Old: ---- libiscsi-1.20.0+git.20240206.obscpio New: ---- libiscsi-1.20.0+git.20240530.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libiscsi.spec ++++++ --- /var/tmp/diff_new_pack.qKerhJ/_old 2024-06-09 20:19:20.191649692 +0200 +++ /var/tmp/diff_new_pack.qKerhJ/_new 2024-06-09 20:19:20.195649831 +0200 @@ -18,7 +18,7 @@ %define sover 10 Name: libiscsi -Version: 1.20.0+git.20240206 +Version: 1.20.0+git.20240530 Release: 0 Summary: iSCSI client library and utilities License: GPL-2.0-only AND LGPL-2.1-only ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.qKerhJ/_old 2024-06-09 20:19:20.235651227 +0200 +++ /var/tmp/diff_new_pack.qKerhJ/_new 2024-06-09 20:19:20.239651366 +0200 @@ -3,6 +3,6 @@ <param name="url">g...@github.com:sahlberg/libiscsi.git</param> <param name="changesrevision">e6bcdf5fdbf39729399c4f0914661ca1055107a1</param></service><service name="tar_scm"> <param name="url">https://github.com/sahlberg/libiscsi.git</param> - <param name="changesrevision">fef688aa99804588c09beb6ef7a3313dc9cf7492</param></service></servicedata> + <param name="changesrevision">b25ee4f0c4e6a27c2f1fa6b9734d6244295a9ac4</param></service></servicedata> (No newline at EOF) ++++++ libiscsi-1.20.0+git.20240206.obscpio -> libiscsi-1.20.0+git.20240530.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/README.md new/libiscsi-1.20.0+git.20240530/README.md --- old/libiscsi-1.20.0+git.20240206/README.md 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/README.md 2024-05-29 23:49:48.000000000 +0200 @@ -45,6 +45,7 @@ target_user=<account> target_password=<password> header_digest=<crc32c|none> +data_digest=<crc32c|none> Transport: iser @@ -125,6 +126,15 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/configure.ac new/libiscsi-1.20.0+git.20240530/configure.ac --- old/libiscsi-1.20.0+git.20240206/configure.ac 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/configure.ac 2024-05-29 23:49:48.000000000 +0200 @@ -78,8 +78,43 @@ 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([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 + AC_MSG_ERROR([libgcrypt not found]) + fi + WITH_LIBGCRYPT=$ac_cv_lib_gcrypt_gcry_control +fi + +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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/include/iscsi-private.h new/libiscsi-1.20.0+git.20240530/include/iscsi-private.h --- old/libiscsi-1.20.0+git.20240206/include/iscsi-private.h 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/include/iscsi-private.h 2024-05-29 23:49:48.000000000 +0200 @@ -61,6 +61,13 @@ 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 @@ 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_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, @@ -293,6 +304,7 @@ 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); @@ -350,6 +362,9 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/include/iscsi.h new/libiscsi-1.20.0+git.20240530/include/iscsi.h --- old/libiscsi-1.20.0+git.20240206/include/iscsi.h 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/include/iscsi.h 2024-05-29 23:49:48.000000000 +0200 @@ -336,6 +336,29 @@ 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 */ EXTERN int iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/Makefile.am new/libiscsi-1.20.0+git.20240530/lib/Makefile.am --- old/libiscsi-1.20.0+git.20240206/lib/Makefile.am 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/Makefile.am 2024-05-29 23:49:48.000000000 +0200 @@ -12,7 +12,7 @@ libiscsipriv_la_SOURCES += ../win32/win32_compat.c endif -if !HAVE_LIBGCRYPT +if NEED_MD5 libiscsipriv_la_SOURCES += md5.c endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/connect.c new/libiscsi-1.20.0+git.20240530/lib/connect.c --- old/libiscsi-1.20.0+git.20240206/lib/connect.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/connect.c 2024-05-29 23:49:48.000000000 +0200 @@ -431,6 +431,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/crc32c.c new/libiscsi-1.20.0+git.20240530/lib/crc32c.c --- old/libiscsi-1.20.0+git.20240206/lib/crc32c.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/crc32c.c 2024-05-29 23:49:48.000000000 +0200 @@ -118,3 +118,22 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/init.c new/libiscsi-1.20.0+git.20240530/lib/init.c --- old/libiscsi-1.20.0+git.20240206/lib/init.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/init.c 2024-05-29 23:49:48.000000000 +0200 @@ -244,6 +244,7 @@ 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; @@ -493,6 +494,25 @@ } 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) { return iscsi->is_loggedin; @@ -602,19 +622,32 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/libiscsi.def new/libiscsi-1.20.0+git.20240530/lib/libiscsi.def --- old/libiscsi-1.20.0+git.20240206/lib/libiscsi.def 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/libiscsi.def 2024-05-29 23:49:48.000000000 +0200 @@ -115,6 +115,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/libiscsi.syms.in new/libiscsi-1.20.0+git.20240530/lib/libiscsi.syms.in --- old/libiscsi-1.20.0+git.20240206/lib/libiscsi.syms.in 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/libiscsi.syms.in 2024-05-29 23:49:48.000000000 +0200 @@ -116,6 +116,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/login.c new/libiscsi-1.20.0+git.20240530/lib/login.c --- old/libiscsi-1.20.0+git.20240206/lib/login.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/login.c 2024-05-29 23:49:48.000000000 +0200 @@ -44,6 +44,10 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "md5.h" + +#ifdef HAVE_LIBGNUTLS +#include <gnutls/crypto.h> +#endif #ifdef HAVE_LIBGCRYPT #include <gcrypt.h> #endif @@ -202,7 +206,24 @@ 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."); @@ -681,41 +702,61 @@ return i + '0'; } -#ifndef HAVE_LIBGCRYPT -typedef struct MD5Context *gcry_md_hd_t; -#define gcry_md_write MD5Update -#define GCRY_MD_MD5 1 +#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 +#define md5_close gcry_md_close + +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 gcry_md_open(gcry_md_hd_t *hd, int algo, unsigned int flags) +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 +767,7 @@ 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 +780,22 @@ 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 +863,19 @@ 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; @@ -1200,6 +1240,16 @@ } } + 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); } @@ -1370,6 +1420,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/pdu.c new/libiscsi-1.20.0+git.20240530/lib/pdu.c --- old/libiscsi-1.20.0+git.20240206/lib/pdu.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/pdu.c 2024-05-29 23:49:48.000000000 +0200 @@ -225,6 +225,9 @@ /* 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 @@ } } + /* 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; @@ -946,4 +968,37 @@ } 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/scsi-lowlevel.c new/libiscsi-1.20.0+git.20240530/lib/scsi-lowlevel.c --- old/libiscsi-1.20.0+git.20240206/lib/scsi-lowlevel.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/scsi-lowlevel.c 2024-05-29 23:49:48.000000000 +0200 @@ -79,7 +79,9 @@ } free(task->datain.data); + task->datain.data = NULL; free(task); + task = NULL; } struct scsi_task * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/socket.c new/libiscsi-1.20.0+git.20240530/lib/socket.c --- old/libiscsi-1.20.0+git.20240206/lib/socket.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/socket.c 2024-05-29 23:49:48.000000000 +0200 @@ -62,6 +62,7 @@ #include <sys/uio.h> #endif +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -514,7 +515,7 @@ } 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 @@ 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 && i<niov && bytes_to_crc; iov_ptr++, i++) { + size_t chunk = MIN(bytes_to_crc, iov_ptr->iov_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 @@ { 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_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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ "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; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/lib/task_mgmt.c new/libiscsi-1.20.0+git.20240530/lib/task_mgmt.c --- old/libiscsi-1.20.0+git.20240206/lib/task_mgmt.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/lib/task_mgmt.c 2024-05-29 23:49:48.000000000 +0200 @@ -130,7 +130,7 @@ 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, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libiscsi-1.20.0+git.20240206/test-tool/iscsi-support.c new/libiscsi-1.20.0+git.20240530/test-tool/iscsi-support.c --- old/libiscsi-1.20.0+git.20240206/test-tool/iscsi-support.c 2024-02-06 00:51:38.000000000 +0100 +++ new/libiscsi-1.20.0+git.20240530/test-tool/iscsi-support.c 2024-05-29 23:49:48.000000000 +0200 @@ -457,6 +457,8 @@ va_list ap; static char message[1024]; int ret; + struct timespec ts; + struct tm tm; if (loglevel < level) { return; @@ -467,6 +469,17 @@ 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); ++++++ libiscsi.obsinfo ++++++ --- /var/tmp/diff_new_pack.qKerhJ/_old 2024-06-09 20:19:20.491660157 +0200 +++ /var/tmp/diff_new_pack.qKerhJ/_new 2024-06-09 20:19:20.495660297 +0200 @@ -1,5 +1,5 @@ name: libiscsi -version: 1.20.0+git.20240206 -mtime: 1707177098 -commit: fef688aa99804588c09beb6ef7a3313dc9cf7492 +version: 1.20.0+git.20240530 +mtime: 1717019388 +commit: b25ee4f0c4e6a27c2f1fa6b9734d6244295a9ac4