已开启
fix: CVE-2026-12480 - master #46
fix: CVE-2026-12480 - master #46
已开启
hongjinghao创建于 8月3日
共 2 个文件变更+399-1
@@ -0,0 +1,391 @@
1+From d5a88bdb137c0d3039b8f4bbbe8c7099925cc10c Mon Sep 17 00:00:00 2001
2+From: hertschuh <1091026+hertschuh@users.noreply.github.com>
3+Date: Thu, 30 Apr 2026 15:50:00 -0700
4+Subject: [PATCH] Refactor and share H5 validation code between legacy and new
5+ format. (#22801)
6+ 
7+ 
8+Conflict: File renamed: keras/src/legacy/saving/legacy_h5_format.py -> keras/saving/legacy/hdf5_format.py; Adapted import paths from keras.src.* to keras.* (2.12.0 layout); Skipped 1 non-critical file (file_editor.py does not exist in 2.12.0); Kept try/except ImportError for h5py (module_utils not in 2.12.0); Dropped _verify_group/_verify_dataset removal and H5IOStore cursor pattern refactoring (methods don't exist in 2.12.0); Adapted H5IOStore.get to use safe_get_h5_group for ExternalLink/SoftLink validation
9+---
10+ keras/saving/legacy/hdf5_format.py | 106 ++++++++++++++++++++-----------------
11+ keras/saving/saving_lib.py | 64 +++++++++++++++++++++-
12+ 2 files changed, 119 insertions(+), 51 deletions(-)
13+ 
14+diff --git a/keras/saving/legacy/hdf5_format.py b/keras/saving/legacy/hdf5_format.py
15+index 8b57d28..da05e42 100644
16+--- a/keras/saving/legacy/hdf5_format.py
17++++ b/keras/saving/legacy/hdf5_format.py
18+@@ -27,6 +27,8 @@ from keras.optimizers import optimizer_v1
19+ from keras.saving.legacy import model_config as model_config_lib
20+ from keras.saving.legacy import saving_utils
21+ from keras.saving.legacy.saved_model import json_utils
22++from keras.saving.saving_lib import safe_get_h5_dataset
23++from keras.saving.saving_lib import safe_get_h5_group
24+ from keras.utils.generic_utils import LazyLoader
25+ from keras.utils.io_utils import ask_to_proceed_with_overwrite
26+
27+@@ -194,7 +196,9 @@ def load_model_from_hdf5(filepath, custom_objects=None, compile=True):
28+ )
29+
30+ # set weights
31+- load_weights_from_hdf5_group(f["model_weights"], model)
32++ load_weights_from_hdf5_group(
33++ safe_get_h5_group(f, "model_weights"), model
34++ )
35+
36+ if compile:
37+ # instantiate optimizer
38+@@ -657,11 +661,11 @@ def _convert_rnn_weights(layer, weights):
39+ return weights
40+
41+
42+-def save_optimizer_weights_to_hdf5_group(hdf5_group, optimizer):
43++def save_optimizer_weights_to_hdf5_group(group, optimizer):
44+ """Saves optimizer weights of a optimizer to a HDF5 group.
45+
46+ Args:
47+- hdf5_group: HDF5 group.
48++ group: HDF5 group.
49+ optimizer: optimizer instance.
50+ """
51+ if isinstance(optimizer, optimizer_base.Optimizer):
52+@@ -669,7 +673,7 @@ def save_optimizer_weights_to_hdf5_group(hdf5_group, optimizer):
53+ else:
54+ symbolic_weights = getattr(optimizer, "weights")
55+ if symbolic_weights:
56+- weights_group = hdf5_group.create_group("optimizer_weights")
57++ weights_group = group.create_group("optimizer_weights")
58+ weight_names = [str(w.name).encode("utf8") for w in symbolic_weights]
59+ save_attributes_to_hdf5_group(
60+ weights_group, "weight_names", weight_names
61+@@ -686,36 +690,37 @@ def save_optimizer_weights_to_hdf5_group(hdf5_group, optimizer):
62+ param_dset[:] = val
63+
64+
65+-def load_optimizer_weights_from_hdf5_group(hdf5_group):
66++def load_optimizer_weights_from_hdf5_group(group):
67+ """Load optimizer weights from a HDF5 group.
68+
69+ Args:
70+- hdf5_group: A pointer to a HDF5 group.
71++ group: HDF5 group.
72+
73+ Returns:
74+ data: List of optimizer weight names.
75+ """
76+- weights_group = hdf5_group["optimizer_weights"]
77++ weights_group = safe_get_h5_group(group, "optimizer_weights")
78+ optimizer_weight_names = load_attributes_from_hdf5_group(
79+ weights_group, "weight_names"
80+ )
81+ return [
82+- weights_group[weight_name] for weight_name in optimizer_weight_names
83++ safe_get_h5_dataset(weights_group, weight_name)
84++ for weight_name in optimizer_weight_names
85+ ]
86+
87+
88+-def save_subset_weights_to_hdf5_group(f, weights):
89++def save_subset_weights_to_hdf5_group(group, weights):
90+ """Save top-level weights of a model to a HDF5 group.
91+
92+ Args:
93+- f: HDF5 group.
94++ group: HDF5 group.
95+ weights: List of weight variables.
96+ """
97+ weight_values = backend.batch_get_value(weights)
98+ weight_names = [w.name.encode("utf8") for w in weights]
99+- save_attributes_to_hdf5_group(f, "weight_names", weight_names)
100++ save_attributes_to_hdf5_group(group, "weight_names", weight_names)
101+ for name, val in zip(weight_names, weight_values):
102+- param_dset = f.create_dataset(name, val.shape, dtype=val.dtype)
103++ param_dset = group.create_dataset(name, val.shape, dtype=val.dtype)
104+ if not val.shape:
105+ # scalar
106+ param_dset[()] = val
107+@@ -723,37 +728,37 @@ def save_subset_weights_to_hdf5_group(f, weights):
108+ param_dset[:] = val
109+
110+
111+-def save_weights_to_hdf5_group(f, model):
112++def save_weights_to_hdf5_group(group, model):
113+ """Saves the weights of a list of layers to a HDF5 group.
114+
115+ Args:
116+- f: HDF5 group.
117++ group: HDF5 group.
118+ model: Model instance.
119+ """
120+ from keras import __version__ as keras_version
121+
122+ save_attributes_to_hdf5_group(
123+- f, "layer_names", [layer.name.encode("utf8") for layer in model.layers]
124++ group, "layer_names", [layer.name.encode("utf8") for layer in model.layers]
125+ )
126+- f.attrs["backend"] = backend.backend().encode("utf8")
127+- f.attrs["keras_version"] = str(keras_version).encode("utf8")
128++ group.attrs["backend"] = backend.backend().encode("utf8")
129++ group.attrs["keras_version"] = str(keras_version).encode("utf8")
130+
131+ # Sort model layers by layer name to ensure that group names are strictly
132+ # growing to avoid prefix issues.
133+ for layer in sorted(model.layers, key=lambda x: x.name):
134+- g = f.create_group(layer.name)
135++ layer_group = group.create_group(layer.name)
136+ weights = _legacy_weights(layer)
137+- save_subset_weights_to_hdf5_group(g, weights)
138++ save_subset_weights_to_hdf5_group(layer_group, weights)
139+ weights = model._trainable_weights + model._non_trainable_weights
140+- g = f.create_group("top_level_model_weights")
141+- save_subset_weights_to_hdf5_group(g, weights)
142++ layer_group = group.create_group("top_level_model_weights")
143++ save_subset_weights_to_hdf5_group(layer_group, weights)
144+
145+
146+-def load_subset_weights_from_hdf5_group(f):
147++def load_subset_weights_from_hdf5_group(group):
148+ """Load layer weights of a model from hdf5.
149+
150+ Args:
151+- f: A pointer to a HDF5 group.
152++ group: HDF5 group.
153+
154+ Returns:
155+ List of NumPy arrays of the weight values.
156+@@ -762,29 +767,32 @@ def load_subset_weights_from_hdf5_group(f):
157+ ValueError: in case of mismatch between provided model
158+ and weights file.
159+ """
160+- weight_names = load_attributes_from_hdf5_group(f, "weight_names")
161+- return [np.asarray(f[weight_name]) for weight_name in weight_names]
162++ weight_names = load_attributes_from_hdf5_group(group, "weight_names")
163++ return [
164++ np.asarray(safe_get_h5_dataset(group, weight_name))
165++ for weight_name in weight_names
166++ ]
167+
168+
169+-def load_weights_from_hdf5_group(f, model):
170++def load_weights_from_hdf5_group(group, model):
171+ """Implements topological (order-based) weight loading.
172+
173+ Args:
174+- f: A pointer to a HDF5 group.
175++ group: HDF5 group.
176+ model: Model instance.
177+
178+ Raises:
179+ ValueError: in case of mismatch between provided layers
180+ and weights file.
181+ """
182+- if "keras_version" in f.attrs:
183+- original_keras_version = f.attrs["keras_version"]
184++ if "keras_version" in group.attrs:
185++ original_keras_version = group.attrs["keras_version"]
186+ if hasattr(original_keras_version, "decode"):
187+ original_keras_version = original_keras_version.decode("utf8")
188+ else:
189+ original_keras_version = "1"
190+- if "backend" in f.attrs:
191+- original_backend = f.attrs["backend"]
192++ if "backend" in group.attrs:
193++ original_backend = group.attrs["backend"]
194+ if hasattr(original_backend, "decode"):
195+ original_backend = original_backend.decode("utf8")
196+ else:
197+@@ -796,11 +804,11 @@ def load_weights_from_hdf5_group(f, model):
198+ if weights:
199+ filtered_layers.append(layer)
200+
201+- layer_names = load_attributes_from_hdf5_group(f, "layer_names")
202++ layer_names = load_attributes_from_hdf5_group(group, "layer_names")
203+ filtered_layer_names = []
204+ for name in layer_names:
205+- g = f[name]
206+- weight_names = load_attributes_from_hdf5_group(g, "weight_names")
207++ layer_group = safe_get_h5_group(group, name)
208++ weight_names = load_attributes_from_hdf5_group(layer_group, "weight_names")
209+ if weight_names:
210+ filtered_layer_names.append(name)
211+ layer_names = filtered_layer_names
212+@@ -815,10 +823,10 @@ def load_weights_from_hdf5_group(f, model):
213+ # which provides a speedup in TensorFlow.
214+ weight_value_tuples = []
215+ for k, name in enumerate(layer_names):
216+- g = f[name]
217++ layer_group = safe_get_h5_group(group, name)
218+ layer = filtered_layers[k]
219+ symbolic_weights = _legacy_weights(layer)
220+- weight_values = load_subset_weights_from_hdf5_group(g)
221++ weight_values = load_subset_weights_from_hdf5_group(layer_group)
222+ weight_values = preprocess_weights_for_loading(
223+ layer, weight_values, original_keras_version, original_backend
224+ )
225+@@ -831,12 +839,12 @@ def load_weights_from_hdf5_group(f, model):
226+ )
227+ weight_value_tuples += zip(symbolic_weights, weight_values)
228+
229+- if "top_level_model_weights" in f:
230++ if "top_level_model_weights" in group:
231+ symbolic_weights = (
232+ model._trainable_weights + model._non_trainable_weights
233+ )
234+ weight_values = load_subset_weights_from_hdf5_group(
235+- f["top_level_model_weights"]
236++ safe_get_h5_group(group, "top_level_model_weights")
237+ )
238+ if len(weight_values) != len(symbolic_weights):
239+ raise ValueError(
240+@@ -853,13 +861,13 @@ def load_weights_from_hdf5_group(f, model):
241+ layer.finalize_state()
242+
243+
244+-def load_weights_from_hdf5_group_by_name(f, model, skip_mismatch=False):
245++def load_weights_from_hdf5_group_by_name(group, model, skip_mismatch=False):
246+ """Implements name-based weight loading (instead of topological loading).
247+
248+ Layers that have no matching name are skipped.
249+
250+ Args:
251+- f: A pointer to a HDF5 group.
252++ group: HDF5 group.
253+ model: Model instance.
254+ skip_mismatch: Boolean, whether to skip loading of layers
255+ where there is a mismatch in the number of weights,
256+@@ -869,21 +877,21 @@ def load_weights_from_hdf5_group_by_name(f, model, skip_mismatch=False):
257+ ValueError: in case of mismatch between provided layers
258+ and weights file and skip_match=False.
259+ """
260+- if "keras_version" in f.attrs:
261+- original_keras_version = f.attrs["keras_version"]
262++ if "keras_version" in group.attrs:
263++ original_keras_version = group.attrs["keras_version"]
264+ if hasattr(original_keras_version, "decode"):
265+ original_keras_version = original_keras_version.decode("utf8")
266+ else:
267+ original_keras_version = "1"
268+- if "backend" in f.attrs:
269+- original_backend = f.attrs["backend"]
270++ if "backend" in group.attrs:
271++ original_backend = group.attrs["backend"]
272+ if hasattr(original_backend, "decode"):
273+ original_backend = original_backend.decode("utf8")
274+ else:
275+ original_backend = None
276+
277+ # New file format.
278+- layer_names = load_attributes_from_hdf5_group(f, "layer_names")
279++ layer_names = load_attributes_from_hdf5_group(group, "layer_names")
280+
281+ # Reverse index of layer name to list of layers with name.
282+ index = {}
283+@@ -895,8 +903,8 @@ def load_weights_from_hdf5_group_by_name(f, model, skip_mismatch=False):
284+ # which provides a speedup in TensorFlow.
285+ weight_value_tuples = []
286+ for k, name in enumerate(layer_names):
287+- g = f[name]
288+- weight_values = load_subset_weights_from_hdf5_group(g)
289++ layer_group = safe_get_h5_group(group, name)
290++ weight_values = load_subset_weights_from_hdf5_group(layer_group)
291+ for layer in index.get(name, []):
292+ symbolic_weights = _legacy_weights(layer)
293+ weight_values = preprocess_weights_for_loading(
294+@@ -944,12 +952,12 @@ def load_weights_from_hdf5_group_by_name(f, model, skip_mismatch=False):
295+ (symbolic_weights[i], weight_values[i])
296+ )
297+
298+- if "top_level_model_weights" in f:
299++ if "top_level_model_weights" in group:
300+ symbolic_weights = (
301+ model._trainable_weights + model._non_trainable_weights
302+ )
303+ weight_values = load_subset_weights_from_hdf5_group(
304+- f["top_level_model_weights"]
305++ safe_get_h5_group(group, "top_level_model_weights")
306+ )
307+
308+ if len(weight_values) != len(symbolic_weights):
309+diff --git a/keras/saving/saving_lib.py b/keras/saving/saving_lib.py
310+index 9e52ecf..12e3bdc 100644
311+--- a/keras/saving/saving_lib.py
312++++ b/keras/saving/saving_lib.py
313+@@ -574,6 +574,64 @@ class DiskIOStore:
314+ tf.io.gfile.rmtree(self.tmp_dir)
315+
316+
317++def safe_get_h5_group(parent, name):
318++ """Retrieve a Group within a given File or Group.
319++
320++ Args:
321++ parent: the parent h5py.File or h5py.Group.
322++ name: the name of the Group to retrieve.
323++
324++ Returns:
325++ The child h5py.Group.
326++ """
327++ # Also handles the case when the group is an empty dict initially.
328++ if name not in parent:
329++ raise KeyError(name)
330++
331++ group_type = parent.get(name, default=None, getclass=True, getlink=True)
332++ if group_type in (h5py.ExternalLink, h5py.SoftLink):
333++ raise ValueError(f"Not allowed: H5 file with {group_type.__name__}")
334++
335++ group = parent[name]
336++ if not isinstance(group, h5py.Group):
337++ raise ValueError(
338++ f"Invalid H5 file, expected Group but received {type(group)}"
339++ )
340++ return group
341++
342++
343++def safe_get_h5_dataset(group, name):
344++ """Retrieve a Dataset within a given Group.
345++
346++ Args:
347++ group: the parent h5py.Group.
348++ name: the name of the Dataset to retrieve.
349++
350++ Returns:
351++ The child h5py.Dataset.
352++ """
353++ # Also handles the case when the group is an empty dict initially.
354++ if name not in group:
355++ raise KeyError(name)
356++
357++ dataset_type = group.get(name, default=None, getclass=True, getlink=True)
358++ if dataset_type in (h5py.ExternalLink, h5py.SoftLink):
359++ raise ValueError(f"Not allowed: H5 file with {dataset_type.__name__}")
360++
361++ dataset = group[name]
362++ if not isinstance(dataset, h5py.Dataset):
363++ raise ValueError(
364++ f"Invalid H5 file, expected Dataset, received {type(dataset)}"
365++ )
366++ if dataset.external:
367++ raise ValueError(
368++ f"Not allowed: H5 file with external Dataset: {dataset.external}"
369++ )
370++ if dataset.is_virtual:
371++ raise ValueError("Not allowed: H5 file with virtual Dataset")
372++ return dataset
373++
374++
375+ class H5IOStore:
376+ def __init__(self, root_path, archive=None, mode="r"):
377+ """Numerical variable store backed by HDF5.
378+@@ -605,9 +663,11 @@ class H5IOStore:
379+
380+ def get(self, path):
381+ if not path:
382+- return self.h5_file["vars"]
383++ return safe_get_h5_group(self.h5_file, "vars")
384+ if path in self.h5_file and "vars" in self.h5_file[path]:
385+- return self.h5_file[path]["vars"]
386++ return safe_get_h5_group(
387++ safe_get_h5_group(self.h5_file, path), "vars"
388++ )
389+ return {}
390+
391+ def close(self):
@@ -1,7 +1,7 @@
1%global _empty_manifest_terminate_build 01%global _empty_manifest_terminate_build 0
2Name: python-Keras2Name: python-Keras
3Version: 2.12.03Version: 2.12.0
4-Release: 44+Release: 5
5Summary: Deep Learning for humans5Summary: Deep Learning for humans
6License: Apache-2.06License: Apache-2.0
7URL: https://github.com/keras-team/keras7URL: https://github.com/keras-team/keras
@@ -11,6 +11,7 @@ BuildArch: noarch
11Patch0: backport-CVE-2025-12058.patch11Patch0: backport-CVE-2025-12058.patch
12Patch1: backport-CVE-2026-12482.patch12Patch1: backport-CVE-2026-12482.patch
13Patch2: backport-CVE-2026-11816.patch13Patch2: backport-CVE-2026-11816.patch
14+Patch6000: backport-CVE-2026-12480.patch
14 15 
15Requires: python3-numpy16Requires: python3-numpy
16Requires: python3-scipy17Requires: python3-scipy
@@ -100,6 +101,12 @@ mv %{buildroot}/doclist.lst .
100%{_docdir}/*101%{_docdir}/*
101 102 
102%changelog103%changelog
104+* Mon Aug 03 2026 hongjinghao <hongjinghao@huawei.com> - 2.12.0-5
105+- Type:CVE
106+- CVE:CVE-2026-12480
107+- SUG:NA
108+- DESC:fix CVE-2026-12480
109+ 
103* Wed Jul 22 2026 lizhengde <lizhengde@xfusion.com> - 2.12.0-4110* Wed Jul 22 2026 lizhengde <lizhengde@xfusion.com> - 2.12.0-4
104- Type:CVE111- Type:CVE
105- CVE:CVE-2026-11816112- CVE:CVE-2026-11816