@@ -4413,6 +4413,33 @@ def test_sneaky_hardlink_fallback(self):
44134413 self .expect_file ("boom" , symlink_to = '../../link_here' )
44144414 self .expect_file ("c" , symlink_to = 'b' )
44154415
4416+ @symlink_test
4417+ def test_sneaky_hardlink_fallback_deep (self ):
4418+ with ArchiveMaker () as arc :
4419+ arc .add ("a/b/s" , symlink_to = os .path .join (".." , "escape" ))
4420+ arc .add ("s" , hardlink_to = os .path .join ("a" , "b" , "s" ))
4421+
4422+ with self .check_context (arc .open (), 'data' ):
4423+ if not os_helper .can_symlink () or sys .platform == "win32" :
4424+ # See notes in test_sneaky_hardlink_fallback.
4425+ self .expect_exception (tarfile .LinkOutsideDestinationError )
4426+ else :
4427+ e = self .expect_exception (
4428+ tarfile .LinkFallbackError ,
4429+ "link 's' would be extracted as a copy of "
4430+ + "'a/b/s', which was rejected" )
4431+ self .assertIsInstance (e .__cause__ ,
4432+ tarfile .LinkOutsideDestinationError )
4433+
4434+ for filter in 'tar' , 'fully_trusted' :
4435+ with self .subTest (filter ), self .check_context (arc .open (), filter ):
4436+ if not os_helper .can_symlink ():
4437+ self .expect_file ("a/b/s" )
4438+ self .expect_file ("s" )
4439+ else :
4440+ self .expect_file ("a/b/s" , symlink_to = os .path .join ('..' , 'escape' ))
4441+ self .expect_file ("s" , symlink_to = os .path .join ('..' , 'escape' ))
4442+
44164443 @symlink_test
44174444 def test_exfiltration_via_symlink (self ):
44184445 # (CVE-2025-4138)
0 commit comments