Open
Fix CVE-2026-12570: unbounded memory allocation in HDF5 dataset loading #47
nebdAdd on Aug 13
Fix CVE-2026-12570: unbounded memory allocation in HDF5 dataset loading #47
Open
Total: 2 files changed+103-1
| @@ -0,0 +1,95 @@ | |||
| 1 | +From 4933ea4a5b3fcc24ceacdc276f5bb5dfbd06756c Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Ziyu Lin <104151270+LinZiyuu@users.noreply.github.com> | ||
| 3 | +Date: Mon, 17 Aug 2026 14:49:19 +0800 | ||
| 4 | +Subject: [PATCH] Fix CVE-2026-12570: guard against HDF5 shape/decompression | ||
| 5 | + bomb | ||
| 6 | + | ||
| 7 | +In keras 2.12.0, H5IOStore.get() returns an HDF5 group object whose | ||
| 8 | +datasets are accessed directly by _load_own_variables via store[key]. | ||
| 9 | +A crafted .keras file can contain an HDF5 dataset that declares an | ||
| 10 | +enormous shape (e.g. petabytes) while occupying only a few kilobytes | ||
| 11 | +on disk (chunked + compressed + fill-value-only). When the dataset is | ||
| 12 | +read into memory via v.assign(store[key]), h5py attempts to allocate | ||
| 13 | +memory for the full declared shape, triggering an OOM condition. | ||
| 14 | + | ||
| 15 | +Add validate_h5_dataset to saving_lib.py and call it from | ||
| 16 | +base_layer._load_own_variables before reading each dataset. | ||
| 17 | + | ||
| 18 | +Origin: https://github.com/keras-team/keras/commit/4933ea4a5b3fcc24ceacdc276f5bb5dfbd06756c | ||
| 19 | +Issue: https://atomgit.com/src-openeuler/python-Keras/issues/31 | ||
| 20 | +--- | ||
| 21 | + keras/engine/base_layer.py | 4 +++- | ||
| 22 | + keras/saving/saving_lib.py | 35 +++++++++++++++++++++++++++++++++++ | ||
| 23 | + 2 files changed, 38 insertions(+), 1 deletion(-) | ||
| 24 | + | ||
| 25 | +diff --git a/keras/engine/base_layer.py b/keras/engine/base_layer.py | ||
| 26 | +index 6d126b6..e1ad50e 100644 | ||
| 27 | +--- a/keras/engine/base_layer.py | ||
| 28 | ++++ b/keras/engine/base_layer.py | ||
| 29 | +@@ -3518,7 +3518,9 @@ class Layer(tf.Module, version_utils.LayerVersionSelector): | ||
| 30 | + ) | ||
| 31 | + for i, v in enumerate(all_vars): | ||
| 32 | + # TODO(rchao): check shapes and raise errors. | ||
| 33 | +- v.assign(store[f"{i}"]) | ||
| 34 | ++ val = store[f"{i}"] | ||
| 35 | ++ saving_lib.validate_h5_dataset(val, name=f"{i}") | ||
| 36 | ++ v.assign(val) | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + class TensorFlowOpLayer(Layer): | ||
| 40 | +diff --git a/keras/saving/saving_lib.py b/keras/saving/saving_lib.py | ||
| 41 | +index 9e52ecf..f6ec9c9 100644 | ||
| 42 | +--- a/keras/saving/saving_lib.py | ||
| 43 | ++++ b/keras/saving/saving_lib.py | ||
| 44 | +@@ -17,6 +17,7 @@ | ||
| 45 | + import datetime | ||
| 46 | + import io | ||
| 47 | + import json | ||
| 48 | ++import math | ||
| 49 | + import os | ||
| 50 | + import re | ||
| 51 | + import tempfile | ||
| 52 | +@@ -668,6 +669,40 @@ class NpzIOStore: | ||
| 53 | + self.f.close() | ||
| 54 | + | ||
| 55 | + | ||
| 56 | ++# Guard against HDF5 "shape bomb" datasets (CVE-2026-12570). | ||
| 57 | ++# A dataset can declare an enormous shape while storing almost nothing on disk | ||
| 58 | ++# (e.g. chunked + gzip-compressed with only a fill value), which forces a huge | ||
| 59 | ++# allocation when it is read into memory (CWE-789 / CWE-409). For datasets | ||
| 60 | ++# whose declared in-memory size is above this floor, we require it to stay | ||
| 61 | ++# within _H5_DATASET_MAX_EXPANSION of the bytes actually stored on disk. | ||
| 62 | ++_H5_DATASET_BOMB_FLOOR_BYTES = 1 << 32 # 4 GiB | ||
| 63 | ++_H5_DATASET_MAX_EXPANSION = 1000 | ||
| 64 | ++ | ||
| 65 | ++ | ||
| 66 | ++def validate_h5_dataset(dataset, name="<unknown>"): | ||
| 67 | ++ """Validate that an HDF5 dataset is not a shape/decompression bomb. | ||
| 68 | ++ | ||
| 69 | ++ Checks that the dataset's declared in-memory size is not | ||
| 70 | ++ disproportionately larger than the bytes actually stored on disk. | ||
| 71 | ++ """ | ||
| 72 | ++ if h5py is None: | ||
| 73 | ++ return | ||
| 74 | ++ if not isinstance(dataset, h5py.Dataset): | ||
| 75 | ++ return | ||
| 76 | ++ declared_bytes = math.prod(dataset.shape) * dataset.dtype.itemsize | ||
| 77 | ++ stored_bytes = dataset.id.get_storage_size() | ||
| 78 | ++ if ( | ||
| 79 | ++ declared_bytes > _H5_DATASET_BOMB_FLOOR_BYTES | ||
| 80 | ++ and declared_bytes > _H5_DATASET_MAX_EXPANSION * stored_bytes | ||
| 81 | ++ ): | ||
| 82 | ++ raise ValueError( | ||
| 83 | ++ f"Not allowed: H5 dataset '{name}' declares " | ||
| 84 | ++ f"{declared_bytes} bytes in memory but only " | ||
| 85 | ++ f"{stored_bytes} bytes are stored on disk; " | ||
| 86 | ++ "refusing to load a potential decompression/shape bomb." | ||
| 87 | ++ ) | ||
| 88 | ++ | ||
| 89 | ++ | ||
| 90 | + def _get_temp_dir(): | ||
| 91 | + temp_dir = tempfile.mkdtemp() | ||
| 92 | + testfile = tempfile.TemporaryFile(dir=temp_dir) | ||
| 93 | +-- | ||
| 94 | +2.55.0 | ||
| 95 | + | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | %global _empty_manifest_terminate_build 0 | 1 | %global _empty_manifest_terminate_build 0 |
| 2 | Name: python-Keras | 2 | Name: python-Keras |
| 3 | Version: 2.12.0 | 3 | Version: 2.12.0 |
| 4 | -Release: 4 | 4 | +Release: 5 |
| 5 | Summary: Deep Learning for humans | 5 | Summary: Deep Learning for humans |
| 6 | License: Apache-2.0 | 6 | License: Apache-2.0 |
| 7 | URL: https://github.com/keras-team/keras | 7 | URL: https://github.com/keras-team/keras |
| @@ -11,6 +11,7 @@ BuildArch: noarch | |||
| 11 | Patch0: backport-CVE-2025-12058.patch | 11 | Patch0: backport-CVE-2025-12058.patch |
| 12 | Patch1: backport-CVE-2026-12482.patch | 12 | Patch1: backport-CVE-2026-12482.patch |
| 13 | Patch2: backport-CVE-2026-11816.patch | 13 | Patch2: backport-CVE-2026-11816.patch |
| 14 | +Patch3: backport-CVE-2026-12570.patch | ||
| 14 | 15 | ||
| 15 | Requires: python3-numpy | 16 | Requires: python3-numpy |
| 16 | Requires: python3-scipy | 17 | Requires: python3-scipy |
| @@ -100,6 +101,12 @@ mv %{buildroot}/doclist.lst . | |||
| 100 | %{_docdir}/* | 101 | %{_docdir}/* |
| 101 | 102 | ||
| 102 | %changelog | 103 | %changelog |
| 104 | +* Thu Aug 13 2026 shaojiansong <shaojiansong@kylinos.cn> - 2.12.0-5 | ||
| 105 | +- Type:CVE | ||
| 106 | +- CVE:CVE-2026-12570 | ||
| 107 | +- SUG:NA | ||
| 108 | +- DESC:Security fix: unbounded memory allocation in HDF5 dataset loading (shape/decompression bomb). Add validate_h5_dataset to guard against malicious .keras model files. | ||
| 109 | + | ||
| 103 | * Wed Jul 22 2026 lizhengde <lizhengde@xfusion.com> - 2.12.0-4 | 110 | * Wed Jul 22 2026 lizhengde <lizhengde@xfusion.com> - 2.12.0-4 |
| 104 | - Type:CVE | 111 | - Type:CVE |
| 105 | - CVE:CVE-2026-11816 | 112 | - CVE:CVE-2026-11816 |