diff --git a/0005-bugfix-for-CVE-2025-55552.patch b/0005-bugfix-for-CVE-2025-55552.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1aa50c322172bfc63f8e87f26019ac419ea2acb --- /dev/null +++ b/0005-bugfix-for-CVE-2025-55552.patch @@ -0,0 +1,190 @@ +From b0f029ca081204dc6569b971db2d4e4ca4094af0 Mon Sep 17 00:00:00 2001 +From: tomcruiseqi +Date: Fri, 27 Mar 2026 15:49:05 +0800 +Subject: [PATCH] [inductor] preserve strides for *_like random decompositions + +Backport the fix for CVE-2025-55552 to the PyTorch 2.8.0 package. + +Make rand_like, randn_like and randint_like preserve the logical stride +layout when memory_format is preserve_format, and add a regression test +for the torch.rot90 plus torch.randn_like case. + +Upstream issue: https://github.com/pytorch/pytorch/issues/147847 +Backport based on: https://github.com/pytorch/pytorch/pull/159294 +Related upstream fixes: + https://github.com/pytorch/pytorch/pull/158898 + https://github.com/pytorch/pytorch/pull/158188 +--- + test/inductor/test_torchinductor.py | 16 +++++ + torch/_inductor/decomposition.py | 97 ++++++++++++++++++++++------- + 2 files changed, 89 insertions(+), 24 deletions(-) + +diff --git a/test/inductor/test_torchinductor.py b/test/inductor/test_torchinductor.py +index 20ce486..1567cfd 100644 +--- a/test/inductor/test_torchinductor.py ++++ b/test/inductor/test_torchinductor.py +@@ -9241,6 +9241,22 @@ def forward(self, arg0_1: "Sym(s77)", arg1_1: "Sym(s27)", arg2_1: "Sym(s53)", ar + + self.common(fn, [torch.zeros([20, 20])]) + ++ @config.patch(fallback_random=True) ++ @xfail_if_mps # 100% are not close ++ def test_randn_like_after_rot90(self): ++ def fn(x): ++ return torch.randn_like(torch.rot90(x, k=1, dims=[2, 3])) ++ ++ x = torch.randn(1, 1, 2, 2, device=self.device) ++ ++ torch.manual_seed(0) ++ eager_out = fn(x) ++ torch.manual_seed(0) ++ compiled_out = torch.compile(fn, backend="inductor")(x) ++ ++ self.assertEqual(eager_out, compiled_out) ++ self.assertEqual(eager_out.stride(), compiled_out.stride()) ++ + @config.patch(check_stack_no_cycles_TESTING_ONLY=True) + def test_check_stack_no_cycles(self): + if config.cpp_wrapper and self.device != "cpu": +diff --git a/torch/_inductor/decomposition.py b/torch/_inductor/decomposition.py +index 08c3abc..971c800 100644 +--- a/torch/_inductor/decomposition.py ++++ b/torch/_inductor/decomposition.py +@@ -591,6 +591,51 @@ def get_like_layout( + return memory_format + + ++def _get_shape_permutation_like( ++ self: torch.Tensor, ++) -> tuple[utils.ShapeType, utils.StrideType]: ++ physical_layout = utils.compute_elementwise_output_logical_to_physical_perm(self) ++ shape = [self.shape[l] for l in physical_layout] ++ ++ permutation = [0] * len(shape) ++ for p, l in enumerate(physical_layout): ++ permutation[l] = p ++ ++ return shape, permutation ++ ++ ++def _rand_like( ++ rand_fn: Callable[..., torch.Tensor], ++ self: torch.Tensor, ++ *, ++ dtype: Optional[torch.dtype] = None, ++ device: Optional[torch.device] = None, ++ memory_format: Optional[torch.memory_format] = None, ++ **kwargs: Any, ++) -> torch.Tensor: ++ dtype = self.dtype if dtype is None else dtype ++ device = self.device if device is None else device ++ ++ if memory_format not in (None, torch.preserve_format): ++ return rand_fn( ++ self.shape, ++ dtype=dtype, ++ device=device, ++ **kwargs, ++ ).to(memory_format=memory_format) ++ ++ shape, permutation = _get_shape_permutation_like(self) ++ result = rand_fn( ++ shape, ++ dtype=dtype, ++ device=device, ++ **kwargs, ++ ) ++ if permutation == list(range(len(permutation))): ++ return result ++ return result.permute(permutation).clone() ++ ++ + @register_decomposition(aten.rand_like) + def rand_like( + self: torch.Tensor, +@@ -600,12 +645,14 @@ def rand_like( + memory_format: Optional[torch.memory_format] = None, + **kwargs: Any, + ) -> torch.Tensor: +- return torch.rand( +- [*self.size()], +- dtype=dtype or self.dtype, +- device=device or self.device, ++ return _rand_like( ++ torch.rand, ++ self, ++ dtype=dtype, ++ device=device, ++ memory_format=memory_format, + **kwargs, +- ).to(memory_format=get_like_layout(self, memory_format)) ++ ) + + + @register_decomposition(aten.randn_like) +@@ -617,12 +664,14 @@ def randn_like( + memory_format: Optional[torch.memory_format] = None, + **kwargs: Any, + ) -> torch.Tensor: +- return torch.randn( +- [*self.size()], +- dtype=dtype or self.dtype, +- device=device or self.device, ++ return _rand_like( ++ torch.randn, ++ self, ++ dtype=dtype, ++ device=device, ++ memory_format=memory_format, + **kwargs, +- ).to(memory_format=get_like_layout(self, memory_format)) ++ ) + + + @register_decomposition(aten.full_like) +@@ -657,14 +706,14 @@ def randint_like( + memory_format: Optional[torch.memory_format] = None, + **kwargs: Any, + ) -> torch.Tensor: +- return aten.randint.low( +- 0, +- high, +- [*self.size()], +- dtype=dtype or self.dtype, +- device=device or self.device, ++ return _rand_like( ++ functools.partial(aten.randint.low, 0, high), ++ self, ++ dtype=dtype, ++ device=device, ++ memory_format=memory_format, + **kwargs, +- ).to(memory_format=get_like_layout(self, memory_format)) ++ ) + + + @register_decomposition(aten.randint_like.low_dtype) +@@ -678,14 +727,14 @@ def randint_like_low( + memory_format: Optional[torch.memory_format] = None, + **kwargs: Any, + ) -> torch.Tensor: +- return aten.randint.low( +- low, +- high, +- [*self.size()], +- dtype=dtype or self.dtype, +- device=device or self.device, ++ return _rand_like( ++ functools.partial(aten.randint.low, low, high), ++ self, ++ dtype=dtype, ++ device=device, ++ memory_format=memory_format, + **kwargs, +- ).to(memory_format=get_like_layout(self, memory_format)) ++ ) + + + @register_decomposition(aten.randint.default) +-- +2.43.1 diff --git a/0006-bugfix-for-CVE-2025-55554.patch b/0006-bugfix-for-CVE-2025-55554.patch new file mode 100644 index 0000000000000000000000000000000000000000..74110b5772e9e38ff51b8de9673ef4f630ad9921 --- /dev/null +++ b/0006-bugfix-for-CVE-2025-55554.patch @@ -0,0 +1,185 @@ +From 09f9d03a69a868843a778b59b7038867732a3df6 Mon Sep 17 00:00:00 2001 +From: tomcruiseqi +Date: Fri, 27 Mar 2026 15:49:05 +0800 +Subject: [PATCH] [c10] clamp float-to-int casts to avoid overflow UB + +Backport the fix for CVE-2025-55554 to the PyTorch 2.8.0 package. + +Clamp floating-point values before casting to signed integer types so +CPU behavior avoids undefined overflow, and add a regression test for +int64 max conversion. + +Upstream issue: https://github.com/pytorch/pytorch/issues/151510 +Backport of: https://github.com/pytorch/pytorch/pull/169360 +--- + c10/util/TypeCast.h | 64 ++++++++++++++++++++++++++++++++++----------- + test/test_torch.py | 5 ++++ + 2 files changed, 54 insertions(+), 15 deletions(-) + +diff --git a/c10/util/TypeCast.h b/c10/util/TypeCast.h +index 3291fce..63dfd00 100644 +--- a/c10/util/TypeCast.h ++++ b/c10/util/TypeCast.h +@@ -57,11 +57,11 @@ struct maybe_bool { + } + }; + +-// Note: deliberately ignores undefined behavior, consistent with NumPy. +-// PyTorch's type conversions can cause a variety of undefined behavior, +-// including float to integral overflow and signed to unsigned integer overflow. +-// Some of this undefined behavior is addressed below. +-template ++// Note: PyTorch's type conversions can cause a variety of undefined behavior, ++// including signed to unsigned integer overflow. Float to integral overflow is ++// addressed below. Other undefined behaviors are deliberately ignored, ++// consistent with NumPy. ++template + struct static_cast_with_inter_type { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline dest_t apply( + src_t src) { +@@ -71,11 +71,37 @@ struct static_cast_with_inter_type { + } + }; + ++// Partial template instantiation for casting float to signed integer. ++// Casting float to signed integer can overflow, which is undefined ++// behavior in C++, and current CPU and GPU compilers exhibit divergent ++// behavior. Here we clamp the float value to the range of the destination ++// type to avoid undefined behavior. ++template ++struct static_cast_with_inter_type< ++ dest_t, ++ src_t, ++ typename std::enable_if< ++ std::is_floating_point::value && std::is_signed::value && ++ std::is_integral::value>::type> { ++ C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline dest_t apply( ++ src_t src) { ++ constexpr bool real = needs_real::value; ++ auto r = maybe_real::apply(src); ++ if (r >= static_cast(std::numeric_limits::max())) { ++ return std::numeric_limits::max(); ++ } else if (r < static_cast(std::numeric_limits::min())) { ++ return std::numeric_limits::min(); ++ } else { ++ return static_cast(r); ++ } ++ } ++}; ++ + // Partial template specialization for casting to bool. + // Need to handle complex types separately, as we don't + // simply want to cast the real part to bool. + template +-struct static_cast_with_inter_type { ++struct static_cast_with_inter_type { + C10_HOST_DEVICE static inline bool apply(src_t src) { + constexpr bool complex = needs_real::value; + return static_cast(maybe_bool::apply(src)); +@@ -92,7 +118,7 @@ struct static_cast_with_inter_type { + // Further note: Type conversions across compilers still have other undefined + // and divergent behavior. + template +-struct static_cast_with_inter_type { ++struct static_cast_with_inter_type { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline uint8_t apply( + src_t src) { + constexpr bool real = needs_real::value; +@@ -102,7 +128,7 @@ struct static_cast_with_inter_type { + }; + + template <> +-struct static_cast_with_inter_type, c10::BFloat16> { ++struct static_cast_with_inter_type, c10::BFloat16, void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::BFloat16 src) { +@@ -111,7 +137,10 @@ struct static_cast_with_inter_type, c10::BFloat16> { + }; + + template <> +-struct static_cast_with_inter_type, c10::Float8_e5m2> { ++struct static_cast_with_inter_type< ++ c10::complex, ++ c10::Float8_e5m2, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Float8_e5m2 src) { +@@ -122,7 +151,8 @@ struct static_cast_with_inter_type, c10::Float8_e5m2> { + template <> + struct static_cast_with_inter_type< + c10::complex, +- c10::Float8_e5m2fnuz> { ++ c10::Float8_e5m2fnuz, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Float8_e5m2fnuz src) { +@@ -133,7 +163,8 @@ struct static_cast_with_inter_type< + template <> + struct static_cast_with_inter_type< + c10::complex, +- c10::Float8_e4m3fn> { ++ c10::Float8_e4m3fn, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Float8_e4m3fn src) { +@@ -144,7 +175,8 @@ struct static_cast_with_inter_type< + template <> + struct static_cast_with_inter_type< + c10::complex, +- c10::Float8_e4m3fnuz> { ++ c10::Float8_e4m3fnuz, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Float8_e4m3fnuz src) { +@@ -157,7 +189,8 @@ struct static_cast_with_inter_type< + template <> + struct static_cast_with_inter_type< + c10::complex, +- c10::Float8_e8m0fnu> { ++ c10::Float8_e8m0fnu, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Float8_e8m0fnu src) { +@@ -166,7 +199,7 @@ struct static_cast_with_inter_type< + }; + + template <> +-struct static_cast_with_inter_type, c10::Half> { ++struct static_cast_with_inter_type, c10::Half, void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::Half src) { +@@ -177,7 +210,8 @@ struct static_cast_with_inter_type, c10::Half> { + template <> + struct static_cast_with_inter_type< + c10::complex, +- c10::complex> { ++ c10::complex, ++ void> { + C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex< + c10::Half> + apply(c10::complex src) { +diff --git a/test/test_torch.py b/test/test_torch.py +index d8cc39d..15324e1 100644 +--- a/test/test_torch.py ++++ b/test/test_torch.py +@@ -9688,6 +9688,11 @@ tensor([[[1.+1.j, 1.+1.j, 1.+1.j, ..., 1.+1.j, 1.+1.j, 1.+1.j], + self.assertEqual(x.int().type(torch.Tensor).dtype, torch.get_default_dtype()) + self.assertEqual(x.type(torch.int32).dtype, torch.int32) + ++ def test_type_float_to_int_overflow(self): ++ x = torch.tensor([[float(torch.iinfo(torch.int64).max)]]) ++ x = x.long() ++ self.assertEqual(x.item(), torch.iinfo(torch.int64).max) ++ + # FIXME: port to a quantization test suite + def test_qengine(self): + qengines = torch.backends.quantized.supported_engines +-- +2.43.1 diff --git a/0007-bugfix-for-CVE-2025-55551.patch b/0007-bugfix-for-CVE-2025-55551.patch new file mode 100644 index 0000000000000000000000000000000000000000..f79323f65e245f2f905be60cd8988b9ce00e5653 --- /dev/null +++ b/0007-bugfix-for-CVE-2025-55551.patch @@ -0,0 +1,64 @@ +From fc7d29f988fc39e2b9098bb803bbc23d06c3155b Mon Sep 17 00:00:00 2001 +From: tomcruiseqi +Date: Fri, 27 Mar 2026 15:49:05 +0800 +Subject: [PATCH] [dynamo] preserve NamedTupleVariable dynamic attributes + +Backport the fix for CVE-2025-55551 to the PyTorch 2.8.0 package. + +This keeps dynamic_attributes when cloning NamedTupleVariable instances, +which fixes torch.linalg.lu(x)[:2] under torch.compile. + +Add a regression test covering the lu slicing case. + +Upstream issue: https://github.com/pytorch/pytorch/issues/151401 +Backport of: https://github.com/pytorch/pytorch/pull/158190 +--- + test/dynamo/test_repros.py | 13 +++++++++++++ + torch/_dynamo/variables/lists.py | 6 ++++-- + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/test/dynamo/test_repros.py b/test/dynamo/test_repros.py +index 2dfd97b..00ea72d 100644 +--- a/test/dynamo/test_repros.py ++++ b/test/dynamo/test_repros.py +@@ -7465,6 +7465,19 @@ class ReproTestsDevice(torch._dynamo.test_case.TestCase): + with mock.patch("torch.cuda.is_initialized", lambda: False): + self.assertEqual(f(inp), inp + 2) + ++ def test_named_tuple_vt_clone_linalg_lu_slice(self): ++ class Model(nn.Module): ++ def forward(self, x): ++ p, l = torch.linalg.lu(x)[:2] ++ return p, l ++ ++ model = Model() ++ x = torch.randn(2, 4, 3, 3) ++ ++ eager_out = model(x.clone()) ++ compiled_out = torch.compile(model, backend="eager")(x.clone()) ++ self.assertEqual(eager_out, compiled_out) ++ + + instantiate_parametrized_tests(ReproTests) + +diff --git a/torch/_dynamo/variables/lists.py b/torch/_dynamo/variables/lists.py +index 12a6111..d06144b 100644 +--- a/torch/_dynamo/variables/lists.py ++++ b/torch/_dynamo/variables/lists.py +@@ -889,10 +889,12 @@ class NamedTupleVariable(TupleVariable): + *TupleVariable._nonvar_fields, + } + +- def __init__(self, items, tuple_cls, **kwargs) -> None: ++ def __init__(self, items, tuple_cls, dynamic_attributes=None, **kwargs) -> None: + super().__init__(items, **kwargs) + self.tuple_cls = tuple_cls +- self.dynamic_attributes = {} ++ self.dynamic_attributes = ( ++ {} if dynamic_attributes is None else dynamic_attributes ++ ) + + def is_namedtuple(self): + return isinstance(getattr(self.tuple_cls, "_fields", None), tuple) and callable( +-- +2.43.1 diff --git a/pytorch.spec b/pytorch.spec index 9ed4e36e4ee84217b1a4dcbebbaac6b45276b792..7cbd6ec896fccd4f1f70328d3b45ac472d8eabc9 100644 --- a/pytorch.spec +++ b/pytorch.spec @@ -1,4 +1,4 @@ -%define anolis_release 3 +%define anolis_release 4 %global vcu_maj 12 %global vcu_min 1 @@ -24,6 +24,15 @@ Patch0003: 1002-add-loongarch64-support-for-cpuinfo.patch # https://github.com/pytorch/pytorch/commit/167ad09be5af5c52666759412a3804068c6955d1 Patch0004: 0002-add-patch-to-fix-CVE-2026-24747.patch +# CVE-2025-55552 https://github.com/pytorch/pytorch/pull/159294 +Patch0005: 0005-bugfix-for-CVE-2025-55552.patch + +# CVE-2025-55554 https://github.com/pytorch/pytorch/pull/169360 +Patch0006: 0006-bugfix-for-CVE-2025-55554.patch + +# CVE-2025-55551 https://github.com/pytorch/pytorch/pull/158190 +Patch0007: 0007-bugfix-for-CVE-2025-55551.patch + BuildRequires: python3-devel cmake gcc-c++ BuildRequires: python3-typing-extensions python3-pyyaml python3-setuptools BuildRequires: python3-six python3-numpy @@ -111,6 +120,9 @@ end %{python3_sitearch}/torch/share %changelog +* Fri Mar 27 2026 tomcruiseqi - 2.8.0-4 +- Fix CVE-2025-55552,CVE-2025-55554,CVE-2025-55551 + * Sat Feb 28 2026 lzq11122 - 2.8.0-3 - Add patch to fix CVE-2026-24747