Skip to content

Commit c5ead60

Browse files
committed
Better handling for creating SecureJars from Zip
1 parent 0dcb7a9 commit c5ead60

File tree

4 files changed

+48
-11
lines changed

4 files changed

+48
-11
lines changed

.github/workflows/test_jvms.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
uses: actions/checkout@main
8888

8989
- name: Downloads results
90-
uses: actions/download-artifact@v3
90+
uses: actions/download-artifact@v4
9191
id: download
9292
with:
9393
path: build/test_artifacts
@@ -99,7 +99,7 @@ jobs:
9999
# run: groovy .github/workflows/aggregate-junit-tests.groovy
100100

101101
- name: Upload Final Results
102-
uses: actions/upload-artifact@v3
102+
uses: actions/upload-artifact@v4
103103
with:
104104
name: aggregate-results
105105
path: jmh_results.md

src/main/java/cpw/mods/jarhandling/JarMetadata.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
import cpw.mods.jarhandling.impl.SimpleJarMetadata;
1010

1111
import java.lang.module.ModuleDescriptor;
12+
import java.net.URI;
13+
import java.net.URISyntaxException;
1214
import java.nio.file.Path;
15+
import java.nio.file.Paths;
1316
import java.util.List;
1417
import java.util.Set;
1518
import java.util.regex.Pattern;
@@ -113,7 +116,28 @@ private static SimpleJarMetadata fromFileNameImpl(final Path path, final Set<Str
113116
}
114117

115118
// fallback parsing
116-
var fn = path.getFileName().toString();
119+
var fileName = path.getFileName();
120+
if (fileName == null) {
121+
// This is the root of a ZipFileSystem, lets try getting the name from the outer path
122+
URI uri = path.toUri();
123+
if ("jar".equals(uri.getScheme())) {
124+
String spec = uri.getRawSchemeSpecificPart();
125+
int sep = spec.indexOf("!/");
126+
if (sep != -1)
127+
spec = spec.substring(0, sep);
128+
129+
try {
130+
fileName = Paths.get(new URI(spec)).getFileName();
131+
} catch (URISyntaxException e) {
132+
// This will result in fileName == null and the IllegalArgument being thrown below
133+
}
134+
}
135+
}
136+
137+
if (fileName == null)
138+
throw new IllegalArgumentException("Can not make module name from path with null getFileName: " + path.toUri());
139+
140+
var fn = fileName.toString();
117141
var lastDot = fn.lastIndexOf('.');
118142
if (lastDot > 0) {
119143
fn = fn.substring(0, lastDot); // strip extension if possible
@@ -122,7 +146,7 @@ private static SimpleJarMetadata fromFileNameImpl(final Path path, final Set<Str
122146
var mat = DASH_VERSION.matcher(fn);
123147
if (mat.find()) {
124148
var potential = fn.substring(mat.start() + 1);
125-
var ver = safeParseVersion(potential, path.getFileName().toString());
149+
var ver = safeParseVersion(potential, fileName.toString());
126150
var name = mat.replaceAll("");
127151
return new SimpleJarMetadata(cleanModuleName(name), ver, pkgs, providers);
128152
} else {

src/main/java/cpw/mods/jarhandling/impl/Jar.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import cpw.mods.jarhandling.JarMetadata;
99
import cpw.mods.jarhandling.SecureJar;
10-
import cpw.mods.util.LambdaExceptionUtils;
1110
import cpw.mods.util.ZipUtils;
1211

1312
import java.io.IOException;
@@ -20,7 +19,6 @@
2019
import java.nio.file.FileSystems;
2120
import java.nio.file.Files;
2221
import java.nio.file.Path;
23-
import java.nio.file.Paths;
2422
import java.nio.file.spi.FileSystemProvider;
2523
import java.security.CodeSigner;
2624
import java.util.ArrayList;
@@ -182,21 +180,27 @@ private Path newFileSystem(BiPredicate<String, String> filter, Path[] paths) {
182180
FileSystem fs = null;
183181
try {
184182
if (filter == null && paths.length == 1) {
185-
if (Files.isDirectory(paths[0]))
183+
if (Files.isDirectory(paths[0])) {
184+
ZipUtils.setUninterruptible(paths[0].getFileSystem());
186185
return paths[0];
186+
}
187+
187188
var uri = paths[0].toUri();
188-
if ("file".equals(uri.getScheme())) {
189+
var scheme = uri.getScheme();
190+
191+
if ("file".equals(scheme) || "jar".equals(scheme) || "roimfs".equals(scheme)) {
189192
// We have to manually open the jar files up via a URI instead of a Path
190193
// because the ZipFileSystem implementation only caches the FileSystems
191194
// when accessed that way. But we can only open it once or else it throws
192195
// a FileSystemAlreadyExistsException. So, exceptions as codeflow, yay!
193-
uri = new URI("jar:" + uri);
196+
if (!"jar".equals(scheme))
197+
uri = new URI("jar:" + uri);
194198
try {
195199
fs = FileSystems.newFileSystem(uri, Map.of(), null);
196200
} catch (FileSystemAlreadyExistsException e) {
197201
fs = FileSystems.getFileSystem(uri);
198202
}
199-
ZipUtils.setUninterruptible(ZipUtils.getByteChannel(fs));
203+
ZipUtils.setUninterruptible(fs);
200204
} else {
201205
// JarInJar is fucking stupid and breaks horribly if it knows about files directly.
202206
// So because I don't want to go into the rabbit hole that is digging into that

src/main/java/cpw/mods/util/ZipUtils.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* Hacky utilities to access interals of ZipFileSystem to prevent thread interrrupts for breaking the entire FileSystem for everyone else.
2020
* This is an internal class, not exposed in module-info. If you're using this as a consumer, Don't.
2121
* See: https://github.com/MinecraftForge/SecureModules/pull/8
22-
* The ZipPath.exists invocation is for a performance optimization.
22+
* The ZipPath.exists invocation is for a performance optimization.
2323
*/
2424
public class ZipUtils {
2525
private static final MethodHandle ZIPFS_EXISTS;
@@ -55,6 +55,15 @@ public static void setUninterruptible(final SeekableByteChannel byteChannel) thr
5555
}
5656
}
5757

58+
public static void setUninterruptible(final FileSystem fileSystem) throws Throwable {
59+
try {
60+
SeekableByteChannel byteChannel = getByteChannel(fileSystem);
61+
setUninterruptible(byteChannel);
62+
} catch (ClassCastException e) {
63+
// ZipFileSystem is private, so we can't do a normal check, so just eat the exception
64+
}
65+
}
66+
5867
public static boolean exists(final Path path) throws Throwable {
5968
return (boolean) ZIPFS_EXISTS.invoke(path);
6069
}

0 commit comments

Comments
 (0)