Skip to content

Multi-byte filenames in zip files can cause an endless loop in ZipString.hash #38751

Closed
@jhackel-hypo

Description

@jhackel-hypo

Our Spring Boot 3.2.0 app hangs for random builds during a very early start-up phase. We see this thread-dump:

"main" #1 prio=5 os_prio=31 cpu=17588,58ms elapsed=17,96s tid=0x0000000145009a00 nid=0x2203 runnable  [0x000000016d49a000]
   java.lang.Thread.State: RUNNABLE
	at org.springframework.boot.loader.zip.ZipString.readInBuffer(ZipString.java:281)
	at org.springframework.boot.loader.zip.ZipString.hash(ZipString.java:112)
	at org.springframework.boot.loader.zip.ZipContent$Loader.add(ZipContent.java:445)
	at org.springframework.boot.loader.zip.ZipContent$Loader.loadContent(ZipContent.java:581)
	at org.springframework.boot.loader.zip.ZipContent$Loader.openAndLoad(ZipContent.java:543)
	at org.springframework.boot.loader.zip.ZipContent$Loader.loadNestedZip(ZipContent.java:537)
	at org.springframework.boot.loader.zip.ZipContent$Loader.load(ZipContent.java:522)
	at org.springframework.boot.loader.zip.ZipContent.open(ZipContent.java:372)
	at org.springframework.boot.loader.zip.ZipContent.open(ZipContent.java:361)
	at org.springframework.boot.loader.jar.NestedJarFileResources.<init>(NestedJarFileResources.java:57)
	at org.springframework.boot.loader.jar.NestedJarFile.<init>(NestedJarFile.java:141)
	at org.springframework.boot.loader.jar.NestedJarFile.<init>(NestedJarFile.java:120)
	at org.springframework.boot.loader.net.protocol.jar.UrlNestedJarFile.<init>(UrlNestedJarFile.java:42)
	at org.springframework.boot.loader.net.protocol.jar.UrlJarFileFactory.createJarFileForNested(UrlJarFileFactory.java:86)
	at org.springframework.boot.loader.net.protocol.jar.UrlJarFileFactory.createJarFile(UrlJarFileFactory.java:55)
	at org.springframework.boot.loader.net.protocol.jar.UrlJarFiles.getOrCreate(UrlJarFiles.java:72)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlConnection.connect(JarUrlConnection.java:289)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlConnection.getJarFile(JarUrlConnection.java:99)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.getJarFile(JarUrlClassLoader.java:185)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.definePackage(JarUrlClassLoader.java:143)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.definePackageIfNecessary(JarUrlClassLoader.java:126)
	at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.loadClass(JarUrlClassLoader.java:99)
	at org.springframework.boot.loader.launch.LaunchedClassLoader.loadClass(LaunchedClassLoader.java:91)
	at java.lang.ClassLoader.loadClass(java.base@17.0.5/ClassLoader.java:520)
	at java.lang.Class.getDeclaredMethods0(java.base@17.0.5/Native Method)
	at java.lang.Class.privateGetDeclaredMethods(java.base@17.0.5/Class.java:3402)
	at java.lang.Class.getDeclaredMethod(java.base@17.0.5/Class.java:2673)
	at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:89)
	at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53)
	at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58)

I am not sure what this code exactly does, but it seems to calculate a hash code of a a file name from a JAR file embedded in the super-jar of our app. The code seems to operate on DataBlock instances of the central ZIP file directory.

The error occurs because the block it is processing happens to only contain the first half of the file name. Unfortunately, the last byte in the data block is the first byte of multi-byte character. It seems, this code tries to read the whole multi-byte character:

if (!hasEnoughBytes(byteIndex, codePointSize, count)) {
pos--;
len++;
break;
}

But the data block seems to be unable to provide the missing byte, because it will not read any further data from the underlying file channel. It returns only the first byte of the multi-byte character again and again. And the hash function hangs.

I am not deep enough into it, do dig what is exactly going on. Furthermore, I am unable to provide the broken JAR as it comes from a closed source project.

Metadata

Metadata

Assignees

Labels

type: regressionA regression from a previous release

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions