summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Vater2025-07-25 08:37:16 +0200
committerSebastian Vater2025-07-25 08:37:16 +0200
commite8e9f271764534b2f65285d192df3626f16af063 (patch)
tree2a0fb9c9f99b013f1f5d5307aec506de15940f52
parentMade fast hashing a little bit more readable and fixed address increment for ... (diff)
downloaddnbd3-e8e9f271764534b2f65285d192df3626f16af063.tar.gz
dnbd3-e8e9f271764534b2f65285d192df3626f16af063.tar.xz
dnbd3-e8e9f271764534b2f65285d192df3626f16af063.zip
Resize hash map after half capacity load instead full in order to avoid bucket overload. Also updated iSCSI packet validation to check header and data digests, if available and check if packet size matches all header length fields.
-rw-r--r--src/server/iscsi.c30
-rw-r--r--src/server/iscsi.h4
2 files changed, 23 insertions, 11 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index c5f796d..19eb8d4 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -139,7 +139,7 @@ static int iscsi_hashmap_resize(iscsi_hashmap *map)
const uint old_capacity = map->capacity;
iscsi_hashmap_bucket *old_buckets = map->buckets;
- map->capacity <<= ISCSI_HASHMAP_RESIZE_FACTOR;
+ map->capacity <<= ISCSI_HASHMAP_RESIZE_SHIFT;
map->buckets = (iscsi_hashmap_bucket *) calloc( map->capacity, sizeof(struct iscsi_hashmap_bucket) );
@@ -295,7 +295,7 @@ void iscsi_hashmap_destroy_key(uint8_t *key) {
*/
int iscsi_hashmap_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value)
{
- if ( ((map->count + 1) > map->capacity) && (iscsi_hashmap_resize( map ) < 0) )
+ if ( ((map->count + 1) > (map->capacity >> ISCSI_HASHMAP_RESIZE_SHIFT)) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
const uint32_t hash = iscsi_hashmap_hash_data( key, key_size );
@@ -350,7 +350,7 @@ int iscsi_hashmap_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_s
*/
int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t **out_in_value)
{
- if ( ((map->count + 1) > map->capacity) && (iscsi_hashmap_resize( map ) < 0) )
+ if ( ((map->count + 1) > (map->capacity >> ISCSI_HASHMAP_RESIZE_SHIFT)) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
const uint32_t hash = iscsi_hashmap_hash_data( key, key_size );
@@ -416,7 +416,7 @@ int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t k
*/
int iscsi_hashmap_put_free(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value, iscsi_hashmap_callback callback, uint8_t *user_data)
{
- if ( ((map->count + 1) > map->capacity) && (iscsi_hashmap_resize( map ) < 0) )
+ if ( ((map->count + 1) > (map->capacity >> ISCSI_HASHMAP_RESIZE_SHIFT)) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
const uint32_t hash = iscsi_hashmap_hash_data( key, key_size );
@@ -685,7 +685,7 @@ iscsi_bhs_packet *iscsi_append_ahs_packet(iscsi_bhs_packet *packet_data, const u
ahs_pkt->type = 0;
ahs_pkt->specific = 0;
memset( ahs_pkt->data, 0, (new_pkt_size - old_pkt_size) - offsetof(struct iscsi_ahs_packet, data) );
- packet_data->total_ahs_len += (ahs_len + 3) >> 2U;
+ packet_data->total_ahs_len += (ahs_len + (ISCSI_ALIGN_SIZE - 1)) >> 2U;
return packet_data;
}
@@ -949,23 +949,29 @@ int iscsi_validate_data_digest(const iscsi_bhs_packet *packet_data, const int he
* not be NULL.
* @param[in] len Length of packet data to be checked for iSCSI, must be
* at least 48 bytes (minimum BHS header size).
+ * @param[in] header_digest_size Length of optional header digest (0 or 4 for now) in
+ * order to validate header digest. The header digest size IS NOT checked for
+ * conforming to iSCSI specs, so be careful.
+ * @param[in] data_digest_size Length of optional data digest (0 or 4 for now) in
+ * order to validate data digest size. The data digest size IS NOT checked for
+ * conforming to iSCSI specs, so take caution.
* @return 0 if it's clearly a iSCSI packet (detected without
* heuristics) or a positive integfer value up to 65536, if heuristics
* were necessary. A negative value is returned in case of an error or
* if it's clearly not an iSCSI packet.
*/
-int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint32_t len)
+int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint32_t len, const uint32_t header_digest_size, const uint32_t data_digest_size)
{
if ( packet_data == NULL )
return -1; // Packet data not specified (prevent null pointer exception)
- else if ( len < ISCSI_BHS_SIZE )
+ else if ( len < sizeof (struct iscsi_bhs_packet) )
return -2; // Packet data length smaller than minimum required iSCSI packet size -> clearly no iSCSI packet
const uint32_t ahs_len = (uint32_t) packet_data->total_ahs_len << 2UL; // AHS length is in DWORD's
const uint32_t ds_len = (uint32_t) iscsi_get_be24(packet_data->ds_len);
- if ( len < (ISCSI_BHS_SIZE + ahs_len) )
- return -3; // Packet to small in order to contain full AHS data
+ if ( len != (sizeof (struct iscsi_bhs_packet) + ahs_len + header_digest_size + iscsi_align(ds_len, ISCSI_ALIGN_SIZE) + data_digest_size) )
+ return -3; // Calculated packet length doesn't match with actual size of iSCSI packet data
const uint8_t opcode = ISCSI_GET_OPCODE(packet_data->opcode);
@@ -1097,5 +1103,11 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint
}
}
+ if ( (header_digest_size != 0) && (iscsi_validate_header_digest( packet_data ) == 0) )
+ return -7; // CRC32C of AHS and BHS header doesn't match with header digest
+
+ if ( (data_digest_size != 0) && (iscsi_validate_data_digest( packet_data, header_digest_size ) == 0) )
+ return -8; // CRC32C of data segment doesn't match with data digest
+
return 0; // All tests for iSCSI passed, return 0
}
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index a8e0a35..cf8fd34 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -108,7 +108,7 @@ static inline void iscsi_put_be64(uint8_t *data, const uint64_t val)
#define iscsi_align(x, n) (((x) + (n) - 1) & ~((n) - 1))
#define ISCSI_HASHMAP_DEFAULT_CAPACITY 5UL // Shift factor with base 1
-#define ISCSI_HASHMAP_RESIZE_FACTOR 1UL // Number of bits to shift left when resizing
+#define ISCSI_HASHMAP_RESIZE_SHIFT 1UL // Number of bits to shift left when resizing
#define ISCSI_HASHMAP_KEY_ALIGN_SHIFT 3UL // Key data shift value for alignment enforcement
#define ISCSI_HASHMAP_KEY_ALIGN (1UL << (ISCSI_HASHMAP_KEY_ALIGN_SHIFT)) // Key data size must be multiple of 8 bytes by now
#define ISCSI_HASHMAP_HASH_INITIAL 0x811C9DC5UL // Initial hash code
@@ -2842,6 +2842,6 @@ void iscsi_calc_header_digest(const iscsi_bhs_packet *packet_data); // Calculate
int iscsi_validate_header_digest(const iscsi_bhs_packet *packet_data); // Validates a stored iSCSI header digest (CRC32C) with actual header data
void iscsi_calc_data_digest(const iscsi_bhs_packet *packet_data, const int header_digest_size); // Calculate iSCSI data digest (CRC32C)
int iscsi_validate_data_digest(const iscsi_bhs_packet *packet_data, const int header_digest_size); // Validates a stored iSCSI data digest (CRC32C) with actual DataSegment
-int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint32_t len); // Check if valid iSCSI packet and validate if necessarily
+int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint32_t len, const uint32_t header_digest_size, const uint32_t data_digest_size); // Check if valid iSCSI packet and validate if necessarily
#endif /* DNBD3_ISCSI_H_ */