A syntax error in the component proxy_tensor.py of pytorch v2.7.0 allows attackers to cause a Denial of Service (DoS).
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
0 → fixed in 2.7.1
Details
A syntax error in the component proxy_tensor.py of pytorch v2.7.0 allows attackers to cause a Denial of Service (DoS).
The fix
[dynamo] Fix syntax error in aot graph from kwarg-less
test/dynamo/test_repros.py+10 −8
@@ -5589,25 +5589,27 @@ def forward(self):# https://github.com/pytorch/pytorch/issues/121621def test_tensor_random(self):-def random_op(tensor, params):-res = tensor.random_(**params)+def random_op(tensor, args, kwargs):+res = tensor.random_(*args, **kwargs)return resrandom_op = torch.compile(random_op)-params = {"from": -10, "to": 10}tensor = torch.randn([2, 3])-random_op(tensor, params)+random_op(tensor, [], {"from": -10, "to": 10})+random_op(tensor, [-10], {"to": 10})+random_op(tensor, [-10, 10], {})# https://github.com/pytorch/pytorch/issues/131019def test_tensor_uniform(self):-def uniform_op(tensor, params):-res = tensor.uniform_(**params)+def uniform_op(tensor, args, kwargs):+res = tensor.uniform_(*args, **kwargs)return resuniform_op = torch.compile(uniform_op)-params = {"from": -10, "to": 10}tensor = torch.randn([2, 3])-uniform_op(tensor, params)+uniform_op(tensor, [], {"from": -10, "to": 10})+uniform_op(tensor, [-10], {"to": 10})+uniform_op(tensor, [-10, 10], {})def test_data_attr_mutation_after_saved_for_bw(self):def f(x):
torch/_dynamo/symbolic_convert.py+0 −36
@@ -2193,42 +2193,6 @@ def CALL_FUNCTION_EX(self, inst):# x.view(*shape) into x.view(shape), which is correct for view()# but not generally. See test_transpose_for_scores().argsvars = TupleVariable([argsvars])-elif (-fn.name == "random_"-and isinstance(argsvars, TupleVariable)-and len(argsvars.items) == 0-and isinstance(kwargsvars, ConstDictVariable)-and ConstantVariable.create("from") in kwargsvars-):-# `from`` is python keyword. Adding random_ with `from` in the-# Fx graph causes syntax error. Even if we convert the kwargs to-# args, aot_autograd/inductor while lowering generates-# aten.random.from, again causing syntax errors. Since this-# usecase is uncommon, graph break.-unimplemented_v2(-gb_type="Tensor.random_ op called with `from` keyword",-context="",-explanation="This is not supported.",-hints=[],-)-elif (-fn.name == "uniform_"-and isinstance(argsvars, TupleVariable)-and len(argsvars.items) == 0-and isinstance(kwargsvars, ConstDictVariable)-and ConstantVariable.create("from") in kwargsvars-):-# `from`` is python keyword. Adding uniform_ with `from` in the-# Fx graph causes syntax error. Even if we convert the kwargs to-# args, aot_autograd/inductor while lowering generates-# aten.uniform.from, again causing syntax errors. Since this-# usecase is uncommon, graph break.-unimplemented_v2(-gb_type="Tensor.uniform_ op called with `from` keyword",-context="",-explanation="This is not supported.",-hints=[],-)if not isinstance(argsvars, BaseListVariable
torch/_dynamo/variables/tensor.py+15 −0
@@ -600,6 +600,21 @@ def call_method(static_attr = all_tensor_attrs.get(name, None)is_base_tensor_method = static_attr is not None+# For historical reasons, these ops decompose down to syntactically+# invalid aten ops because they contain the python keyword `from`, see+# discussions in #151432 for more details.+# We graph break for now since this use case is uncommon.+if name in ("random_", "uniform_"):+unimplemented_v2(+gb_type="Tensor.random_ op called with `from` keyword",+context=f"Tensor.{name}({args=}, {kwargs=})",+explanation="This is not supported.",+hints=[+"Please use the out-of-place version of this op",+*graph_break_hints.SUPPORTABLE,+],+)+if (can_dispatch_torch_function(tx, tuple([self] + list(args)), kwargs)and is_base_tensor_methodkwarg-less `torch.Tensor.[random_|uniform_]` calls"torch/_dynamo/variables/tensor.py | 40 +++++++++++++++++++------------1 file changed, 25 insertions(+), 15 deletions(-)
torch/_dynamo/variables/tensor.py+25 −15
@@ -600,21 +600,6 @@ def call_method(static_attr = all_tensor_attrs.get(name, None)is_base_tensor_method = static_attr is not None-# For historical reasons, these ops decompose down to syntactically-# invalid aten ops because they contain the python keyword `from`, see-# discussions in #151432 for more details.-# We graph break for now since this use case is uncommon.-if name in ("random_", "uniform_"):-unimplemented_v2(-gb_type="Tensor.random_ op called with `from` keyword",-context=f"Tensor.{name}({args=}, {kwargs=})",-explanation="This is not supported.",-hints=[-"Please use the out-of-place version of this op",-*graph_break_hints.SUPPORTABLE,-],-)-if (can_dispatch_torch_function(tx, tuple([self] + list(args)), kwargs)and is_base_tensor_method@@ -640,6 +625,31 @@ def call_method(if name == "__eq__" and isinstance(args[0], UserDefinedClassVariable):return variables.ConstantVariable(False)+# For historical reasons, these ops decompose down to syntactically+# invalid aten ops because they contain the python keyword `from`, see+# discussions in #151432 for more details.+# We graph break for now since this use case is uncommon.+if name == "random_":+unimplemented_v2(+gb_type="Tensor.random_ op",+context=f"Tensor.{name}({args=}, {kwargs=})",+explanation="This is currently not supported.",+hints=[+"Use the out-of-place version of this op",+*graph_break_hints.SUPPORTABLE,+],+)+elif name == "uniform_" and 'from' in kwargs:+unimplemented_v2(+gb_type="Tensor.uniform_ op called with `from` keyword",+context=f"Tensor.{name}({args=}, {kwargs=})",+explanation="This is currently not supported.",+hints=[+"Avoid using the `from` keyword.",+*graph_break_hints.SUPPORTABLE,+],+)+try:handler_method = getattr(self, f"method_{name}")except AttributeError:kwarg-less `torch.Tensor.[random_|uniform_]` calls"torch/_dynamo/variables/tensor.py | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
torch/_dynamo/variables/tensor.py+1 −1
@@ -639,7 +639,7 @@ def call_method(*graph_break_hints.SUPPORTABLE,],)-elif name == "uniform_" and 'from' in kwargs:+elif name == "uniform_" and "from" in kwargs:unimplemented_v2(gb_type="Tensor.uniform_ op called with `from` keyword",context=f"Tensor.{name}({args=}, {kwargs=})",kwarg-less `torch.Tensor.[random_|uniform_]` calls"test/test_tensor_creation_ops.py | 6 ------1 file changed, 6 deletions(-)
test/test_tensor_creation_ops.py+0 −6
@@ -1612,8 +1612,6 @@ def test_random_bool(self, device):self.assertEqual(t.max(), True)self.assertTrue(0.4 < (t.eq(True)).to(torch.int).sum().item() / size < 0.6)-# https://github.com/pytorch/pytorch/issues/126834-@xfailIfTorchDynamodef test_random_from_to_bool(self, device):size = 2000@@ -1693,8 +1691,6 @@ def test_random_full_range(self, device, dtype):# NB: uint64 is broken because its max value is not representable in# int64_t, but this is what random expects-# https://github.com/pytorch/pytorch/issues/126834-@xfailIfTorchDynamo@dtypes(*all_types_and(torch.bfloat16, torch.half, torch .uint16, torch.uint32))def test_random_from_to(self, device, dtype):size = 2000@@ -1784,8 +1780,6 @@ def test_random_from_to(self, device, dtype):lambda: t.random_(from_, to_))-# https://github.com/pytorch/pytorch/issues/126834-@xfailIfTorchDynamo@dtypes(*all_types_and(torch.bfloat16, torch.half, torch.uint16, torch.uint32))def test_random_to(self, device, dtype):size = 2000