Applying Software Supply Chain concepts to AOTCache/CDS
Aman Sharma
amansha at kth.se
Tue Feb 17 20:50:24 UTC 2026
Hi all,
I want to attach the thread below since there is some context for what I will say next, and I believe it should be okay since the issue has been addressed in https://github.com/openjdk/jdk/pull/29728.
I want to explore the idea of sharing AOTCache as software supply chain artifact. Currently, Java packages are published on Maven Central and consumers can run them as applications or reuse them as libraries. I am proposing that AOTCache is shared along with the Java package by the developer/publisher so that downstream consumers can use it to achieve optimal performance. They could either 1) use the AOTCache as-is for the corresponding application or the downstream developer could 2) merge the AOTCache from Maven Central with the AOTCache from their application. In this way the distribution of AOTCache as a supply chain artifact can take place.
[cid:5f9ec946-9815-45e5-affa-da2032f00e67]
In this figure, each rectangle is a Java package, and each cylinder is an AOTCache. As you can see, the AOTCache of App (AOTApp) is generated by merging all its dependencies' caches.
The thread below can also be summarised in a figure.
[cid:1b52b633-5ec5-49b5-b5aa-ed4767298ee2]
Basically, the red AOT11 contains a poisoned class that shares the fully qualified name with a class name in say D2. In this case, the App was loading the class from the AOTCache (AOTApp) instead the benign class in D2.
I think sharing AOTCache by developers is a good idea because:
1. Developers would probably have a better idea of how well to exercise their application and hence their downstream consumer does not have to worry about creating an "ideal" workload.
2. Merging AOTCache in this way does not require creating complex workloads because your library code is already available in the AOTCache. You only need to add your own classes from the application.
Now, 1) "use the AOTCache as-is for the corresponding application" could be realized by developers pushing their AOTCache on Maven Central along with their jars. However, achieving 2 is non-trivial because merge option is not available in the JVM.
How have I tried to achieve merging:
1. I first tried to create a parser for *.aot files. The idea was to deserialize this memory mapped file into objects declared by src/hotspot/share/oops<https://github.com/chains-project/aotp/blob/main/src/main/java/io/github/chains_project/aotp/oops/klass/SPECIFICATION.md>. And then do the merging using Java APIs I created. However, there were too many pointers that needed to be adjusted and I did not understand how I would parse or generate the bitmap region.
2. I took a step back and tried to modify *.classlist files generated using CDS training run. Here I tried creating separate classlists for different submodules of PDFBox<https://github.com/apache/pdfbox> and then combining them manually. Then I created the CDS archive (.jsa file) using this "combined" classlist. During the production run, I could observe that some classes from different classlist were loaded from shared object files. (I had to disable some checks for time and size of jar in JDK for this work). However, I am more inclined to have the AOTCache or CDS archive as an artifact which is distributed.
3. Now I am trying to patch JDK code with an option "-XX:+AOTMerge" which would work with "-XX:AOTCache"and this would return "merged.aot". To me, AOTCache is a dump of the memory so I think this is feasible. Given the size of JDK code and how sophisticated HotSpot is, I can be completely wrong about this. I spun up a blueprint for this feature<https://github.com/openjdk/jdk/commit/9d303022edfa6b67a895b7e826382bdbf246c230> and now I am trying to use APIs like "AOTMetaspace::dump_static_archive(thread);" which, of course, end in SEGFaults. Can anyone please give me advice on how to go about implementing this feature? I can use some advice on how exactly AOTCache is dumped.
Caveats I have considered.
1. I know AOTCaches and CDS archive are specific to a single JVM version, classpath, etc
2. The merged AOTCache may be too bloated.
Yet I am motivated to explore more here.
Please share your thoughts on this, and I would also love some technical advice. Thank you in advance!
Regards,
Aman Sharma
PhD Student
KTH Royal Institute of Technology
School of Electrical Engineering and Computer Science (EECS)
Department of Theoretical Computer Science (TCS)
<http://www.kth.se><https://www.kth.se/profile/amansha><https://www.kth.se/profile/amansha>
<https://www.kth.se/profile/amansha>https://algomaster99.github.io/
________________________________
From: Aman Sharma
Sent: Friday, January 30, 2026 11:53 AM
To: leyden-dev at openjdk.org
Cc: Martin Monperrus; roberto.castaneda.lozano at oracle.com
Subject: Integrity violation in AOTCache
Hi all,
I have been playing around with AOTCache and I tried a small with it experiment whose idea was to shadow a class using AOTCache. By class shadowing, I mean loading a different class than intended but they both share the same fully qualified name. We also explored this concept in the paper: Maven-Hijack: Software Supply Chain Attack Exploiting Packaging Order<https://arxiv.org/abs/2407.18760v4>, and now I am trying to extend it to AOTCache.
The steps in the experiment are based on POC<https://github.com/chains-project/maven-hijack-poc> from the same paper and are written briefly below. The exact commands are documented here<https://github.com/chains-project/maven-hijack-poc/blob/main/java/maven/abstract-project/AOTCache.md>.
1. Build the application with one of the dependencies having malicious class. The malicious class has the same name as one of the other classes, say `org.postrgresql.Driver` but has malicious contents<https://github.com/chains-project/maven-hijack-poc/blob/0310de24103a55d1f51f70ef625933a40a7a55b3/java/maven/abstract-project/install-me-first/D11/src/main/java/org/postgresql/Driver.java#L8-L23>.
2. Create an AOTCache using these dependencies in jar. This creates a "polluted AOTCache".
3. Now using the polluted cache, run the application that is packaged with genuine dependencies. Apparently, the JVM initializes the malicious class from AOTCache instead of loading it from classpath. In other words, `java -XX:AOTCache=maven.aot -jar target/victim-1.0.jar` and `java -jar target/victim-1.0.jar` give different outputs.
I see this as a weakness if the poisoned AOTCache is distributed as an artifact for consumers to be used because maybe it is not expected from consumers to perform a training run themselves. I believe there should be some sort of integrity checks before a class is initialized from AOTCache. I noticed there are already some<https://github.com/openjdk/jdk/blob/e3b5b261af6acbe7ab074f301c70283b06c17d39/src/hotspot/share/code/aotCodeCache.cpp#L435> (please share if there are more, and I have missed them), but none of them relate to what I am mentioning. I am happy to listen to some thoughts on this.
Regards,
Aman Sharma
PhD Student
KTH Royal Institute of Technology
School of Electrical Engineering and Computer Science (EECS)
Department of Theoretical Computer Science (TCS)
<http://www.kth.se><https://www.kth.se/profile/amansha><https://www.kth.se/profile/amansha>
<https://www.kth.se/profile/amansha>https://algomaster99.github.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20260217/f3020f30/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Untitled Diagram.drawio(2).png
Type: image/png
Size: 22280 bytes
Desc: Untitled Diagram.drawio(2).png
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20260217/f3020f30/UntitledDiagram.drawio2.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Untitled Diagram.drawio(3).png
Type: image/png
Size: 24921 bytes
Desc: Untitled Diagram.drawio(3).png
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20260217/f3020f30/UntitledDiagram.drawio3.png>
More information about the leyden-dev
mailing list