Skip to content

Commit 41b7bad

Browse files
author
Elia Trachsel
committed
Low-level Runtime substitutions:
- Most of the substitutions just simply link against VM methods. - Introduction of JNU to store system encodings
1 parent de96721 commit 41b7bad

26 files changed

+1006
-3
lines changed

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ public static void ensureInitialized() {
185185
public static final Symbol<Type> sun_nio_ch_IOStatus = SYMBOLS.putType("Lsun/nio/ch/IOStatus;");
186186
public static final Symbol<Type> java_net_spi_InetAddressResolver$LookupPolicy = SYMBOLS.putType("Ljava/net/spi/InetAddressResolver$LookupPolicy;");
187187
public static final Symbol<Type> sun_nio_ch_Net = SYMBOLS.putType("Lsun/nio/ch/Net;");
188+
// libjava
189+
public static final Symbol<Type> java_lang_ProcessHandleImpl$Info = SYMBOLS.putType("Ljava/lang/ProcessHandleImpl$Info;");
188190
// libnio
189191
public static final Symbol<Type> sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream = SYMBOLS.putType("Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignDirectoryStream;");
190192
public static final Symbol<Type> sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator = SYMBOLS.putType("Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignIterator;");
@@ -826,6 +828,14 @@ public static class Names {
826828
public static final Symbol<Name> SHUT_RD = SYMBOLS.putName("SHUT_RD");
827829
public static final Symbol<Name> SHUT_WR = SYMBOLS.putName("SHUT_WR");
828830
public static final Symbol<Name> SHUT_RDWR = SYMBOLS.putName("SHUT_RDWR");
831+
// java.lang.ProcessHandleImpl$Info
832+
public static final Symbol<Name> command = SYMBOLS.putName("command");
833+
public static final Symbol<Name> commandLine = SYMBOLS.putName("commandLine");
834+
public static final Symbol<Name> arguments = SYMBOLS.putName("arguments");
835+
public static final Symbol<Name> startTime = SYMBOLS.putName("startTime");
836+
public static final Symbol<Name> totalTime = SYMBOLS.putName("totalTime");
837+
public static final Symbol<Name> user = SYMBOLS.putName("user");
838+
public static final Symbol<Name> initialized = SYMBOLS.putName("initialized");
829839
// java.lang.invoke.*
830840
// CallSite
831841
public static final Symbol<Name> target = SYMBOLS.putName("target");

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/InformationLeak.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
*/
2323
package com.oracle.truffle.espresso.libs;
2424

25+
import java.io.Console;
2526
import java.io.IOException;
27+
import java.lang.reflect.InvocationTargetException;
28+
import java.lang.reflect.Method;
2629
import java.net.Inet4Address;
2730
import java.net.Inet6Address;
2831
import java.net.InetSocketAddress;
@@ -42,9 +45,13 @@
4245
/**
4346
* In the context of the EspressoLibs project, this class is designed to aggregate methods and
4447
* fields that potentially leak information about the host system. Depending on the context, leaking
45-
* such information might not be preferable due to security or privacy concerns.
48+
* such information might not be preferable due to security or privacy concerns. However, it is
49+
* assumed that permission checks are done in the caller's of InformationLeak. Please note it leaks
50+
* host information, meaning return types should not be StaticObjects!
4651
*/
4752
public class InformationLeak {
53+
private static final Method IS_TERMINAL_METHOD = getIsTerminalMethod();
54+
4855
private final EspressoContext context;
4956
private volatile boolean isIPv6Initialized = false;
5057
private boolean isIPv6Available = false;
@@ -53,6 +60,25 @@ public InformationLeak(EspressoContext ctx) {
5360
this.context = ctx;
5461
}
5562

63+
private static Method getIsTerminalMethod() {
64+
try {
65+
return Console.class.getMethod("isTerminal");
66+
} catch (NoSuchMethodException e) {
67+
return null;
68+
}
69+
}
70+
71+
public long getPid() {
72+
return ProcessHandle.current().pid();
73+
}
74+
75+
@TruffleBoundary
76+
public ProcessHandle.Info getProcessHandleInfo(long pid) {
77+
assert context.getEnv().isCreateProcessAllowed();
78+
Optional<ProcessHandle> processHandle = ProcessHandle.of(pid);
79+
return processHandle.map(ProcessHandle::info).orElse(null);
80+
}
81+
5682
public boolean isIPv6Available() {
5783
if (isIPv6Initialized) {
5884
return isIPv6Available;
@@ -91,6 +117,34 @@ public boolean isReusePortAvailable0() {
91117
}
92118
}
93119

120+
public boolean istty() {
121+
if (!(context.getEnv().in() == System.in && context.getEnv().out() == System.out)) {
122+
return false;
123+
}
124+
Console console = System.console();
125+
if (console == null) {
126+
return false;
127+
}
128+
if (IS_TERMINAL_METHOD != null) {
129+
try {
130+
return (boolean) IS_TERMINAL_METHOD.invoke(console);
131+
} catch (IllegalAccessException | InvocationTargetException e) {
132+
throw new Error(e);
133+
}
134+
} else {
135+
return true;
136+
}
137+
}
138+
139+
public String consoleEncoding() {
140+
if (OS.getCurrent() == OS.Windows) {
141+
if (istty()) {
142+
throw Throw.throwUnsupported("console encoding for windows is currently unimplemented", context);
143+
}
144+
}
145+
return null;
146+
}
147+
94148
@TruffleBoundary
95149
public int isExclusiveBindAvailable() {
96150
assert context.getEnv().isSocketIOAllowed();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.espresso.libs;
24+
25+
import java.nio.charset.Charset;
26+
import java.nio.charset.StandardCharsets;
27+
28+
/**
29+
* A class to guarantee consistency when encoding and decoding bytes to strings between the guest
30+
* and host world.
31+
*
32+
* The guest gets its charSet for encoding and decoding from System.getProperty("sun.jnu.encoding").
33+
* We substitute this with the charSet specified in this class. Then on the host side, we just
34+
* simply use the same charSet.
35+
*/
36+
public class JNU {
37+
private static final Charset charSet = StandardCharsets.UTF_8;
38+
39+
public static Charset getCharSet() {
40+
return charSet;
41+
}
42+
43+
public static String getString(byte[] arr, int index, int length) {
44+
return new String(arr, index, length, charSet);
45+
}
46+
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsMeta.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public final class LibsMeta implements ContextAccess {
4747
public final ObjectKlass sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator;
4848
public final Field sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE;
4949
public final Method sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_init;
50+
5051
// libzip
5152
public final ObjectKlass java_util_zip_CRC32;
5253
public final Field HIDDEN_CRC32;
@@ -55,9 +56,21 @@ public final class LibsMeta implements ContextAccess {
5556
public final Field java_util_zip_Inflater_outputConsumed;
5657
public final ObjectKlass java_util_zip_DataFormatException;
5758

59+
// libjava
60+
public final ObjectKlass java_lang_ProcessHandleImpl$Info;
61+
public final Field java_lang_ProcessHandleImpl$Info_command;
62+
public final Field java_lang_ProcessHandleImpl$Info_commandLine;
63+
public final Field java_lang_ProcessHandleImpl$Info_arguments;
64+
public final Field java_lang_ProcessHandleImpl$Info_startTime;
65+
public final Field java_lang_ProcessHandleImpl$Info_totalTime;
66+
public final Field java_lang_ProcessHandleImpl$Info_user;
67+
public final ObjectKlass java_lang_SecurityManager;
68+
public final Field java_lang_SecurityManager_initialized;
69+
5870
// libnet
5971
public final ObjectKlass java_net_NetworkInterface;
6072
public final LibNetMeta net;
73+
6174
// Checkstyle: resume field name check
6275

6376
@Override
@@ -92,6 +105,21 @@ public LibsMeta(EspressoContext ctx) {
92105
java_util_zip_Inflater_inputConsumed = java_util_zip_Inflater.requireDeclaredField(EspressoSymbols.Names.inputConsumed, EspressoSymbols.Types._int);
93106
java_util_zip_Inflater_outputConsumed = java_util_zip_Inflater.requireDeclaredField(EspressoSymbols.Names.outputConsumed, EspressoSymbols.Types._int);
94107

108+
// libjava
109+
java_lang_ProcessHandleImpl$Info = knownKlass(EspressoSymbols.Types.java_lang_ProcessHandleImpl$Info);
110+
java_lang_ProcessHandleImpl$Info_command = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.command, EspressoSymbols.Types.java_lang_String);
111+
java_lang_ProcessHandleImpl$Info_commandLine = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.commandLine, EspressoSymbols.Types.java_lang_String);
112+
java_lang_ProcessHandleImpl$Info_arguments = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.arguments, EspressoSymbols.Types.java_lang_String_array);
113+
java_lang_ProcessHandleImpl$Info_startTime = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.startTime, EspressoSymbols.Types._long);
114+
java_lang_ProcessHandleImpl$Info_totalTime = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.totalTime, EspressoSymbols.Types._long);
115+
java_lang_ProcessHandleImpl$Info_user = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.user, EspressoSymbols.Types.java_lang_String);
116+
java_lang_SecurityManager = knownKlass(EspressoSymbols.Types.java_lang_SecurityManager);
117+
if (context.getJavaVersion().java25OrLater()) {
118+
java_lang_SecurityManager_initialized = null;
119+
} else {
120+
java_lang_SecurityManager_initialized = java_lang_SecurityManager.requireDeclaredField(EspressoSymbols.Names.initialized, EspressoSymbols.Types._boolean);
121+
}
122+
95123
// libnet
96124
java_net_NetworkInterface = knownKlass(EspressoSymbols.Types.java_net_NetworkInterface);
97125
this.net = context.getEnv().isSocketIOAllowed() ? new LibNetMeta() : null;

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsState.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ public class LibsState {
4949

5050
private final StrongHandles<Inflater> handle2Inflater = new StrongHandles<>();
5151

52+
private final EspressoContext context;
53+
5254
public final LibsStateNet net;
5355

5456
public LibsState(EspressoContext context, LibsMeta lMeta) {
57+
this.context = context;
5558
this.net = (context.getEnv().isSocketIOAllowed()) ? new LibsStateNet(context, lMeta) : null;
5659
}
5760

@@ -81,6 +84,12 @@ private static EspressoException throwInternalError() {
8184
return meta.throwExceptionWithMessage(meta.java_lang_InternalError, "the provided handle doesn't correspond to an Inflater");
8285
}
8386

87+
public void checkCreateProcessAllowed() {
88+
if (!context.getEnv().isCreateProcessAllowed()) {
89+
throw Throw.throwSecurityException("process creation is not allowed!", context);
90+
}
91+
}
92+
8493
public final class LibsStateNet {
8594
private final EspressoContext context;
8695
private final LibsMeta lMeta;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.espresso.libs.libjava.impl;
24+
25+
import java.io.Console;
26+
27+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
28+
import com.oracle.truffle.espresso.libs.InformationLeak;
29+
import com.oracle.truffle.espresso.libs.libjava.LibJava;
30+
import com.oracle.truffle.espresso.meta.Meta;
31+
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
32+
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
33+
import com.oracle.truffle.espresso.substitutions.Inject;
34+
import com.oracle.truffle.espresso.substitutions.JavaType;
35+
import com.oracle.truffle.espresso.substitutions.Substitution;
36+
import com.oracle.truffle.espresso.substitutions.VersionFilter;
37+
38+
@EspressoSubstitutions(value = Console.class, group = LibJava.class)
39+
public final class Target_java_io_Console {
40+
@Substitution
41+
@TruffleBoundary
42+
public static boolean istty(@Inject InformationLeak iL) {
43+
return iL.istty();
44+
}
45+
46+
@Substitution(languageFilter = VersionFilter.Java23OrEarlier.class)
47+
public static @JavaType(String.class) StaticObject encoding(@Inject InformationLeak iL, @Inject Meta meta) {
48+
String encoding = iL.consoleEncoding();
49+
return meta.toGuestString(encoding);
50+
}
51+
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ClassLoader.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@
2222
*/
2323
package com.oracle.truffle.espresso.libs.libjava.impl;
2424

25+
import java.nio.ByteBuffer;
2526
import java.security.ProtectionDomain;
2627

2728
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
29+
import com.oracle.truffle.api.interop.TruffleObject;
2830
import com.oracle.truffle.espresso.EspressoLanguage;
2931
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
3032
import com.oracle.truffle.espresso.classfile.descriptors.Type;
33+
import com.oracle.truffle.espresso.ffi.Pointer;
34+
import com.oracle.truffle.espresso.ffi.nfi.NativeUtils;
3135
import com.oracle.truffle.espresso.libs.libjava.LibJava;
3236
import com.oracle.truffle.espresso.runtime.EspressoContext;
3337
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
@@ -135,6 +139,39 @@ public static void registerNatives() {
135139
return ctx.getVM().defineClass(type, loader, pd, buf);
136140
}
137141

142+
@Substitution
143+
@TruffleBoundary
144+
public static @JavaType(Class.class) StaticObject defineClass2(@JavaType(ClassLoader.class) StaticObject loader, @JavaType(String.class) StaticObject name,
145+
@JavaType(ByteBuffer.class) StaticObject data, int off, int len,
146+
@JavaType(ProtectionDomain.class) StaticObject pd,
147+
// TODO: source unused
148+
@SuppressWarnings("unused") @JavaType(String.class) StaticObject source,
149+
@Inject EspressoContext ctx) {
150+
if (StaticObject.isNull(data)) {
151+
throw ctx.getMeta().throwNullPointerException();
152+
}
153+
if (len < 0 || off < 0) {
154+
throw ctx.getMeta().throwIndexOutOfBoundsExceptionBoundary("ByteBuffer", off, len);
155+
}
156+
157+
// retrieve the GuestBuffer as Array
158+
@Pointer
159+
TruffleObject dataAddrPointer = ctx.getJNI().GetDirectBufferAddress(data);
160+
ByteBuffer dataBuffer = NativeUtils.directByteBuffer(dataAddrPointer, len + off);
161+
162+
Symbol<Type> type = null;
163+
if (StaticObject.notNull(name)) {
164+
type = ctx.getVM().nameToInternal(toSlashName(ctx.getMeta().toHostString(name)));
165+
}
166+
167+
// read into array
168+
byte[] buf = new byte[len];
169+
dataBuffer.get(off, buf);
170+
171+
return ctx.getVM().defineClass(type, loader, pd, buf);
172+
173+
}
174+
138175
private static String toSlashName(String name) {
139176
return name.replace('.', '/');
140177
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.espresso.libs.libjava.impl;
24+
25+
import java.lang.ref.PhantomReference;
26+
import java.lang.ref.Reference;
27+
28+
import com.oracle.truffle.espresso.libs.libjava.LibJava;
29+
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
30+
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
31+
import com.oracle.truffle.espresso.substitutions.Inject;
32+
import com.oracle.truffle.espresso.substitutions.JavaType;
33+
import com.oracle.truffle.espresso.substitutions.Substitution;
34+
import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler;
35+
import com.oracle.truffle.espresso.substitutions.VersionFilter;
36+
import com.oracle.truffle.espresso.vm.VM;
37+
38+
@EspressoSubstitutions(value = PhantomReference.class, group = LibJava.class)
39+
public final class Target_java_lang_PhantomReference {
40+
@Substitution(hasReceiver = true, languageFilter = VersionFilter.Java25OrLater.class)
41+
public static void clear0(@JavaType(Reference.class) StaticObject ref,
42+
@Inject SubstitutionProfiler profiler, @Inject VM vm) {
43+
vm.JVM_ReferenceClear(ref, profiler);
44+
45+
}
46+
47+
@Substitution(hasReceiver = true)
48+
public static boolean refersTo0(@JavaType(Reference.class) StaticObject ref, @JavaType(Object.class) StaticObject object,
49+
@Inject SubstitutionProfiler profiler, @Inject VM vm) {
50+
return vm.JVM_PhantomReferenceRefersTo(ref, object, profiler);
51+
}
52+
53+
}

0 commit comments

Comments
 (0)