From f94e3dea9584cdb477ebb639f627b59be4681782 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 12 May 2026 17:19:22 +0200 Subject: [PATCH 1/2] chunkers: check return value of malloc, raise MemoryError --- src/borg/chunkers/buzhash.pyx | 8 +++++++- src/borg/chunkers/buzhash64.pyx | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/borg/chunkers/buzhash.pyx b/src/borg/chunkers/buzhash.pyx index d31ddf8b9..7c1b6872a 100644 --- a/src/borg/chunkers/buzhash.pyx +++ b/src/borg/chunkers/buzhash.pyx @@ -83,10 +83,12 @@ cdef extern from *: @cython.boundscheck(False) # Deactivate bounds checking @cython.wraparound(False) # Deactivate negative indexing. -cdef uint32_t* buzhash_init_table(uint32_t seed): +cdef uint32_t* buzhash_init_table(uint32_t seed) except NULL: """Initialize the buzhash table with the given seed.""" cdef int i cdef uint32_t* table = malloc(1024) # 256 * sizeof(uint32_t) + if table == NULL: + raise MemoryError("Failed to allocate buzhash table") for i in range(256): table[i] = table_base[i] ^ seed return table @@ -141,6 +143,8 @@ cdef class Chunker: cdef bint sparse def __cinit__(self, int seed, int chunk_min_exp, int chunk_max_exp, int hash_mask_bits, int hash_window_size, bint sparse=False): + self.table = NULL + self.data = NULL min_size = 1 << chunk_min_exp max_size = 1 << chunk_max_exp assert max_size <= len(zeros) @@ -153,6 +157,8 @@ cdef class Chunker: self.table = buzhash_init_table(seed & 0xffffffff) self.buf_size = max_size self.data = malloc(self.buf_size) + if self.data == NULL: + raise MemoryError("Failed to allocate chunker buffer") self.fh = -1 self.done = 0 self.eof = 0 diff --git a/src/borg/chunkers/buzhash64.pyx b/src/borg/chunkers/buzhash64.pyx index a03a98829..bbe41cd96 100644 --- a/src/borg/chunkers/buzhash64.pyx +++ b/src/borg/chunkers/buzhash64.pyx @@ -40,7 +40,7 @@ cdef extern from *: @cython.boundscheck(False) # Deactivate bounds checking @cython.wraparound(False) # Deactivate negative indexing. -cdef uint64_t* buzhash64_init_table(bytes key): +cdef uint64_t* buzhash64_init_table(bytes key) except NULL: """ Generate a balanced pseudo-random table deterministically from a 256-bit key. Balanced means that for each bit position 0..63, exactly 50% of the table values have the bit set to 1. @@ -50,6 +50,8 @@ cdef uint64_t* buzhash64_init_table(bytes key): cdef int i, j, bit_pos cdef uint64_t* table = malloc(2048) # 256 * sizeof(uint64_t) + if table == NULL: + raise MemoryError("Failed to allocate buzhash64 table") # Initialize all values to 0 for i in range(256): @@ -118,6 +120,8 @@ cdef class ChunkerBuzHash64: cdef bint sparse def __cinit__(self, bytes key, int chunk_min_exp, int chunk_max_exp, int hash_mask_bits, int hash_window_size, bint sparse=False): + self.table = NULL + self.data = NULL min_size = 1 << chunk_min_exp max_size = 1 << chunk_max_exp assert max_size <= len(zeros) @@ -130,6 +134,8 @@ cdef class ChunkerBuzHash64: self.table = buzhash64_init_table(key) self.buf_size = max_size self.data = malloc(self.buf_size) + if self.data == NULL: + raise MemoryError("Failed to allocate chunker buffer") self.fh = -1 self.done = 0 self.eof = 0 From b362b0898e33591c168baa6916c074fed2d4ae27 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 12 May 2026 17:30:07 +0200 Subject: [PATCH 2/2] buzhash chunkers: add len==0 check to avoid buffer over-read Isn't called by the higher level code with len==0, but adding the check nevertheless for cleaner and less suspicious code. --- src/borg/chunkers/buzhash.pyx | 2 ++ src/borg/chunkers/buzhash64.pyx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/borg/chunkers/buzhash.pyx b/src/borg/chunkers/buzhash.pyx index 7c1b6872a..8a30594bc 100644 --- a/src/borg/chunkers/buzhash.pyx +++ b/src/borg/chunkers/buzhash.pyx @@ -101,6 +101,8 @@ cdef uint32_t _buzhash(const unsigned char* data, size_t len, const uint32_t* h) """Calculate the buzhash of the given data.""" cdef uint32_t i cdef uint32_t sum = 0, imod + if len == 0: + return 0 for i in range(len - 1, 0, -1): imod = i & 0x1f sum ^= BARREL_SHIFT(h[data[0]], imod) diff --git a/src/borg/chunkers/buzhash64.pyx b/src/borg/chunkers/buzhash64.pyx index bbe41cd96..a3c7bf110 100644 --- a/src/borg/chunkers/buzhash64.pyx +++ b/src/borg/chunkers/buzhash64.pyx @@ -78,6 +78,8 @@ cdef uint64_t _buzhash64(const unsigned char* data, size_t len, const uint64_t* """Calculate the buzhash of the given data.""" cdef uint64_t i cdef uint64_t sum = 0, imod + if len == 0: + return 0 for i in range(len - 1, 0, -1): imod = i & 0x3f sum ^= BARREL_SHIFT64(h[data[0]], imod)