8145838: JShell: restrict RemoteAgent connection socket to localhost
Also reviewed by Chris Ries Reviewed-by: rfield
This commit is contained in:
parent
5f24c132d9
commit
d969a1a3fa
@ -24,18 +24,23 @@
|
||||
*/
|
||||
package jdk.jshell.execution;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.sun.jdi.BooleanValue;
|
||||
import com.sun.jdi.ClassNotLoadedException;
|
||||
import com.sun.jdi.Field;
|
||||
@ -111,7 +116,7 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
*/
|
||||
private static ExecutionControl create(ExecutionEnv env,
|
||||
boolean isLaunch, String host) throws IOException {
|
||||
try (final ServerSocket listener = new ServerSocket(0)) {
|
||||
try (final ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) {
|
||||
// timeout after 60 seconds
|
||||
listener.setSoTimeout(60000);
|
||||
int port = listener.getLocalPort();
|
||||
@ -122,6 +127,14 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
VirtualMachine vm = jdii.vm();
|
||||
Process process = jdii.process();
|
||||
|
||||
OutputStream processOut = process.getOutputStream();
|
||||
SecureRandom rng = new SecureRandom();
|
||||
byte[] randomBytes = new byte[VERIFY_HASH_LEN];
|
||||
|
||||
rng.nextBytes(randomBytes);
|
||||
processOut.write(randomBytes);
|
||||
processOut.flush();
|
||||
|
||||
List<Consumer<String>> deathListeners = new ArrayList<>();
|
||||
deathListeners.add(s -> env.closeDown());
|
||||
Util.detectJdiExitEvent(vm, s -> {
|
||||
@ -130,6 +143,8 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
}
|
||||
});
|
||||
|
||||
ByteArrayOutputStream receivedRandomBytes = new ByteArrayOutputStream();
|
||||
|
||||
// Set-up the commands/reslts on the socket. Piggy-back snippet
|
||||
// output.
|
||||
Socket socket = listener.accept();
|
||||
@ -138,11 +153,35 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
Map<String, OutputStream> outputs = new HashMap<>();
|
||||
outputs.put("out", env.userOut());
|
||||
outputs.put("err", env.userErr());
|
||||
outputs.put("echo", new OutputStream() {
|
||||
@Override public void write(int b) throws IOException {
|
||||
synchronized (receivedRandomBytes) {
|
||||
receivedRandomBytes.write(b);
|
||||
receivedRandomBytes.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
Map<String, InputStream> input = new HashMap<>();
|
||||
input.put("in", env.userIn());
|
||||
return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners));
|
||||
return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> {
|
||||
synchronized (receivedRandomBytes) {
|
||||
while (receivedRandomBytes.size() < randomBytes.length) {
|
||||
try {
|
||||
receivedRandomBytes.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
if (!Arrays.equals(receivedRandomBytes.toByteArray(), randomBytes)) {
|
||||
throw new IllegalStateException("Invalid connection!");
|
||||
}
|
||||
}
|
||||
return new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners);
|
||||
});
|
||||
}
|
||||
}
|
||||
//where:
|
||||
private static final int VERIFY_HASH_LEN = 20;
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
package jdk.jshell.execution;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
@ -57,6 +58,7 @@ public class RemoteExecutionControl extends DirectExecutionControl implements Ex
|
||||
* @throws Exception any unexpected exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
InputStream fd0 = System.in;
|
||||
String loopBack = null;
|
||||
Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
|
||||
InputStream inStream = socket.getInputStream();
|
||||
@ -64,6 +66,25 @@ public class RemoteExecutionControl extends DirectExecutionControl implements Ex
|
||||
Map<String, Consumer<OutputStream>> outputs = new HashMap<>();
|
||||
outputs.put("out", st -> System.setOut(new PrintStream(st, true)));
|
||||
outputs.put("err", st -> System.setErr(new PrintStream(st, true)));
|
||||
outputs.put("echo", st -> {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int read;
|
||||
|
||||
while ((read = fd0.read()) != (-1)) {
|
||||
st.write(read);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
st.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
Map<String, Consumer<InputStream>> input = new HashMap<>();
|
||||
input.put("in", st -> System.setIn(st));
|
||||
forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, outputs, input);
|
||||
|
Loading…
Reference in New Issue
Block a user