From 24e5d66b748867c851a6f4cb5d5414728b8ec03e Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Fri, 14 Aug 2026 13:29:51 +0100 Subject: [PATCH] Update to kastore version 2.1.3 --- c/CHANGELOG.rst | 3 +++ c/subprojects/kastore/VERSION.txt | 2 +- c/subprojects/kastore/kastore.c | 30 +++++++++++++++++++++++------- c/subprojects/kastore/kastore.h | 2 +- python/tests/test_python_c.py | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/c/CHANGELOG.rst b/c/CHANGELOG.rst index ae17936fd6..e75b9e2bf1 100644 --- a/c/CHANGELOG.rst +++ b/c/CHANGELOG.rst @@ -7,6 +7,9 @@ In development - Add ``tsk_json_struct_metadata_get_blob`` function (:user:`benjeffery`, :pr:`3306`) +- Update to kastore 2.1.3 to include file security fix (:user:`jeromekelleher`, + :pr:`3478`). + -------------------- [1.3.1] - 2026-03-06 -------------------- diff --git a/c/subprojects/kastore/VERSION.txt b/c/subprojects/kastore/VERSION.txt index eca07e4c1a..ac2cdeba01 100644 --- a/c/subprojects/kastore/VERSION.txt +++ b/c/subprojects/kastore/VERSION.txt @@ -1 +1 @@ -2.1.2 +2.1.3 diff --git a/c/subprojects/kastore/kastore.c b/c/subprojects/kastore/kastore.c index 1f7143b019..5305c10f13 100644 --- a/c/subprojects/kastore/kastore.c +++ b/c/subprojects/kastore/kastore.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "kastore.h" @@ -292,12 +293,21 @@ kastore_read_descriptors(kastore_t *self) goto out; } self->items[j].type = (int) type; - if (key_start + key_len > self->file_size) { + if (key_len == 0) { + /* Keys must be non-empty, matching the write-side invariant. */ + goto out; + } + /* The bounds checks below are written using subtraction and division so + * that they cannot themselves overflow on these attacker-controlled + * 64-bit values (e.g. key_start + key_len or array_len * type_size + * wrapping around past file_size). */ + if (key_start > self->file_size || key_len > self->file_size - key_start) { goto out; } self->items[j].key_start = (size_t) key_start; self->items[j].key_len = (size_t) key_len; - if (array_start + array_len * type_size(type) > self->file_size) { + if (array_start > self->file_size + || array_len > (self->file_size - array_start) / type_size(type)) { goto out; } self->items[j].array_start = (size_t) array_start; @@ -387,11 +397,11 @@ kastore_read_file(kastore_t *self) offset = KAS_HEADER_SIZE + self->num_items * KAS_ITEM_DESCRIPTOR_SIZE; - /* Read in up to the start of first array. This will contain all the keys. */ - size = self->items[0].array_start; - - assert(size > offset); - size -= offset; + /* Read in up to the start of first array. This will contain all the keys. + * kastore_read_descriptors rejects zero-length keys and validates the key + * and array packing, so items[0].array_start is always strictly greater + * than offset and the subtraction below cannot underflow. */ + size = self->items[0].array_start - offset; self->key_read_buffer = (char *) malloc(size); if (self->key_read_buffer == NULL) { @@ -445,6 +455,12 @@ kastore_read_item(kastore_t *self, kaitem_t *item) goto out; } if (size > 0) { + /* array_start is a size_t but fseek takes a long, which is only 32 bits + * on LLP64 platforms (e.g. 64-bit Windows). Guard against truncation. */ + if (item->array_start > (size_t) (LONG_MAX - self->file_offset)) { + ret = KAS_ERR_IO; + goto out; + } err = fseek(self->file, self->file_offset + (long) item->array_start, SEEK_SET); if (err != 0) { ret = KAS_ERR_IO; diff --git a/c/subprojects/kastore/kastore.h b/c/subprojects/kastore/kastore.h index 3acc01aad1..0861f9b85a 100644 --- a/c/subprojects/kastore/kastore.h +++ b/c/subprojects/kastore/kastore.h @@ -157,7 +157,7 @@ to the API or ABI are introduced, i.e., the addition of a new function. The library patch version. Incremented when any changes not relevant to the to the API or ABI are introduced, i.e., internal refactors of bugfixes. */ -#define KAS_VERSION_PATCH 2 +#define KAS_VERSION_PATCH 3 /** @} */ #define KAS_HEADER_SIZE 64 diff --git a/python/tests/test_python_c.py b/python/tests/test_python_c.py index c003a61a54..aba3bc54cb 100644 --- a/python/tests/test_python_c.py +++ b/python/tests/test_python_c.py @@ -5077,7 +5077,7 @@ class TestModuleFunctions: def test_kastore_version(self): version = _tskit.get_kastore_version() - assert version == (2, 1, 2) + assert version == (2, 1, 3) def test_tskit_version(self): version = _tskit.get_tskit_version()