Skip to content

Commit

Permalink
[GR-9218] Allow a read access to language homes when IO is denied.
Browse files Browse the repository at this point in the history
PullRequest: graal/1295
  • Loading branch information
tzezula committed Apr 8, 2018
2 parents bde8833 + 1b62108 commit 3d7fdc8
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
Expand Down Expand Up @@ -113,6 +114,15 @@ public static Collection<Configuration> createParameters() throws IOException {
Files.createTempDirectory(VirtualizedFileSystemTest.class.getSimpleName()),
fullIO);
result.add(new Configuration("No IO", ctx, privateDir, cwd, fullIO, false, false, false, true));
// No IO under language home
ctx = Context.newBuilder(LANGAUGE_ID).allowIO(false).build();
privateDir = createContent(
Files.createTempDirectory(VirtualizedFileSystemTest.class.getSimpleName()),
fullIO);
final String langHome = privateDir.toString();
result.add(new Configuration("No IO under language home", ctx, privateDir, cwd, fullIO, false, true, false, true, () -> {
System.setProperty(LANGAUGE_ID + ".home", langHome);
}));
// Checked IO
accessibleDir = createContent(
Files.createTempDirectory(VirtualizedFileSystemTest.class.getSimpleName()),
Expand Down Expand Up @@ -168,6 +178,8 @@ public VirtualizedFileSystemTest(final Configuration cfg) {

@Before
public void setUp() {
Optional.ofNullable(this.cfg.getBeforeAction()).ifPresent(Runnable::run);
resetLanguageHomes();
Engine.create().close();
}

Expand Down Expand Up @@ -633,6 +645,7 @@ public static final class Configuration implements Closeable {
private final boolean readable;
private final boolean writable;
private final boolean allowsUserDir;
private final Runnable beforeAction;

Configuration(
final String name,
Expand All @@ -643,7 +656,7 @@ public static final class Configuration implements Closeable {
final boolean readable,
final boolean writable,
final boolean allowsUserDir) {
this(name, context, path, path, fileSystem, needsURI, readable, writable, allowsUserDir);
this(name, context, path, path, fileSystem, needsURI, readable, writable, allowsUserDir, null);
}

Configuration(
Expand All @@ -656,6 +669,20 @@ public static final class Configuration implements Closeable {
final boolean readable,
final boolean writable,
final boolean allowsUserDir) {
this(name, context, path, userDir, fileSystem, needsURI, readable, writable, allowsUserDir, null);
}

Configuration(
final String name,
final Context context,
final Path path,
final Path userDir,
final FileSystem fileSystem,
final boolean needsURI,
final boolean readable,
final boolean writable,
final boolean allowsUserDir,
final Runnable beforeAction) {
Objects.requireNonNull(name, "Name must be non null.");
Objects.requireNonNull(context, "Context must be non null.");
Objects.requireNonNull(path, "Path must be non null.");
Expand All @@ -670,6 +697,11 @@ public static final class Configuration implements Closeable {
this.readable = readable;
this.writable = writable;
this.allowsUserDir = allowsUserDir;
this.beforeAction = beforeAction;
}

Runnable getBeforeAction() {
return beforeAction;
}

String getName() {
Expand Down Expand Up @@ -833,6 +865,17 @@ private static void deleteRecursively(Path path, final FileSystem fs) throws IOE
}
}

private static void resetLanguageHomes() {
try {
final Class<?> langCacheClz = Class.forName("com.oracle.truffle.api.vm.LanguageCache", true, VirtualizedFileSystemTest.class.getClassLoader());
final Method reset = langCacheClz.getDeclaredMethod("resetNativeImageCacheLanguageHomes");
reset.setAccessible(true);
reset.invoke(null);
} catch (ReflectiveOperationException re) {
throw new RuntimeException(re);
}
}

static class ForwardingFileSystem implements FileSystem {

private final FileSystem delegate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.spi.FileSystemProvider;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -328,6 +330,8 @@ private Path resolveRelative(Path path) {
private static final class DeniedIOFileSystem implements FileSystem {
private final Path userDir;
private final boolean explicitUserDir;
private final FileSystem fullIO;
private volatile Set<Path> languageHomes;

DeniedIOFileSystem() {
this(null, false);
Expand All @@ -340,6 +344,7 @@ private static final class DeniedIOFileSystem implements FileSystem {
private DeniedIOFileSystem(final Path userDir, final boolean explicitUserDir) {
this.userDir = userDir;
this.explicitUserDir = explicitUserDir;
this.fullIO = FileSystems.getDefaultFileSystem();
}

@Override
Expand All @@ -354,6 +359,11 @@ public Path parsePath(final String path) {

@Override
public void checkAccess(Path path, Set<? extends AccessMode> modes, LinkOption... linkOptions) throws IOException {
path = toAbsolutePath(path);
if (inLanguageHome(path)) {
fullIO.checkAccess(path, modes, linkOptions);
return;
}
throw forbidden(path);
}

Expand All @@ -379,16 +389,41 @@ public void move(Path source, Path target, CopyOption... options) throws IOExcep

@Override
public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
boolean read = options.contains(StandardOpenOption.READ);
boolean write = options.contains(StandardOpenOption.WRITE) || options.contains(StandardOpenOption.DELETE_ON_CLOSE);
if (!read && !write) {
if (options.contains(StandardOpenOption.APPEND)) {
write = true;
} else {
read = true;
}
}
if (write) {
throw forbidden(path);
}
assert read;
path = toAbsolutePath(path);
if (inLanguageHome(path)) {
return fullIO.newByteChannel(path, options, attrs);
}
throw forbidden(path);
}

@Override
public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {
dir = toAbsolutePath(dir);
if (inLanguageHome(dir)) {
return fullIO.newDirectoryStream(dir, filter);
}
throw forbidden(dir);
}

@Override
public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
path = toAbsolutePath(path);
if (inLanguageHome(path)) {
return fullIO.readAttributes(path, attributes, options);
}
throw forbidden(path);
}

Expand All @@ -414,9 +449,42 @@ public Path toAbsolutePath(Path path) {

@Override
public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException {
path = toAbsolutePath(path);
if (inLanguageHome(path)) {
return fullIO.toRealPath(path, linkOptions);
}
throw forbidden(path);
}

private boolean inLanguageHome(final Path path) {
for (Path home : getLanguageHomes()) {
if (path.startsWith(home)) {
return true;
}
}
return false;
}

private Set<Path> getLanguageHomes() {
Set<Path> res = languageHomes;
if (res == null) {
synchronized (this) {
res = languageHomes;
if (res == null) {
res = new HashSet<>();
for (LanguageCache cache : LanguageCache.languages().values()) {
final String languageHome = cache.getLanguageHome();
if (languageHome != null) {
res.add(Paths.get(languageHome));
}
}
languageHomes = res;
}
}
}
return res;
}

private static SecurityException forbidden(final Path path) {
throw new SecurityException("Operation is not allowed for: " + path);
}
Expand Down

0 comments on commit 3d7fdc8

Please sign in to comment.