Skip to content

Commit a6eaeb8

Browse files
committed
Fix sandbox
1 parent a6cd80d commit a6eaeb8

10 files changed

Lines changed: 140 additions & 918 deletions

File tree

‎evaluation/src/main/java/jsheets/evaluation/shell/environment/fork/ForkedExecutionControl.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public final class ForkedExecutionControl extends JdiExecutionControl {
2424

2525
private final Lock stopLock = new ReentrantLock();
2626
private boolean userCodeRunning = false;
27+
private volatile boolean closed;
2728

2829
private final String remoteAgentClass;
2930
private final ClassFileStore classFileStore;
@@ -96,6 +97,7 @@ public void stop() throws EngineTerminationException, InternalException {
9697
try {
9798
if (userCodeRunning) {
9899
new RemoteInterrupt(vm(), remoteAgentClass).runInSuspendedMode();
100+
closed = true;
99101
}
100102
} finally {
101103
stopLock.unlock();
@@ -107,6 +109,12 @@ public void stop() throws EngineTerminationException, InternalException {
107109
public void close() {
108110
super.close();
109111
disposeMachine();
112+
stopLock.lock();
113+
closed = true;
114+
}
115+
116+
public boolean isClosed() {
117+
return closed;
110118
}
111119

112120
synchronized void disposeMachine() {

‎evaluation/src/main/java/jsheets/evaluation/shell/environment/fork/ForkedExecutionEnvironment.java‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import java.util.Collection;
44
import java.util.Objects;
5+
import java.util.concurrent.Executors;
6+
import java.util.concurrent.ScheduledExecutorService;
7+
8+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
59

610
import jdk.jshell.spi.ExecutionControlProvider;
711
import jsheets.evaluation.shell.environment.ClassFileStore;
@@ -14,23 +18,39 @@ public static ForkedExecutionEnvironment create(
1418
) {
1519
Objects.requireNonNull(store, "store");
1620
Objects.requireNonNull(virtualMachineOptions, "virtualMachineOptions");
17-
return new ForkedExecutionEnvironment(store, virtualMachineOptions);
21+
return new ForkedExecutionEnvironment(
22+
store,
23+
virtualMachineOptions,
24+
createDaemonScheduler()
25+
);
26+
}
27+
28+
private static ScheduledExecutorService createDaemonScheduler() {
29+
var factory = new ThreadFactoryBuilder().setDaemon(true).build();
30+
return Executors.newScheduledThreadPool(1, factory);
1831
}
1932

2033
private final ClassFileStore store;
2134
private final Collection<String> virtualMachineOptions;
35+
private final ScheduledExecutorService scheduler;
2236

2337
private ForkedExecutionEnvironment(
2438
ClassFileStore store,
25-
Collection<String> virtualMachineOptions
39+
Collection<String> virtualMachineOptions,
40+
ScheduledExecutorService scheduler
2641
) {
2742
this.store = store;
2843
this.virtualMachineOptions = virtualMachineOptions;
44+
this.scheduler = scheduler;
2945
}
3046

3147
@Override
3248
public ExecutionControlProvider control(String name) {
33-
return ForkingExecutionControlProvider.create(virtualMachineOptions, store);
49+
return ForkingExecutionControlProvider.create(
50+
virtualMachineOptions,
51+
store,
52+
scheduler
53+
);
3454
}
3555

3656
@Override

‎evaluation/src/main/java/jsheets/evaluation/shell/environment/fork/ForkingExecutionControlProvider.java‎

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@
88
import java.net.InetAddress;
99
import java.net.ServerSocket;
1010
import java.time.Duration;
11-
import java.util.ArrayList;
1211
import java.util.Collection;
1312
import java.util.Collections;
1413
import java.util.List;
1514
import java.util.Map;
1615
import java.util.Objects;
1716
import java.util.concurrent.CopyOnWriteArrayList;
17+
import java.util.concurrent.Executors;
18+
import java.util.concurrent.ScheduledExecutorService;
19+
import java.util.concurrent.TimeUnit;
1820
import java.util.function.BiFunction;
1921
import java.util.function.Consumer;
2022

23+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
24+
2125
import com.sun.jdi.VirtualMachine;
2226
import jdk.jshell.execution.JdiInitiator;
2327
import jdk.jshell.execution.RemoteExecutionControl;
@@ -33,42 +37,55 @@
3337
public final class ForkingExecutionControlProvider
3438
implements ExecutionControlProvider {
3539

36-
private static final Duration defaultTimeout = Duration.ofMillis(3000);
37-
3840
public static ForkingExecutionControlProvider create() {
39-
return create(List.of(), EmptyClassFileStore.create());
41+
return create(
42+
List.of(),
43+
EmptyClassFileStore.create(),
44+
Executors.newScheduledThreadPool(
45+
1,
46+
new ThreadFactoryBuilder().setDaemon(true).build()
47+
)
48+
);
4049
}
4150

51+
private static final Duration defaultTimeout = Duration.ofMillis(3000);
52+
private static final Duration defaultExecutionTimeout =
53+
Duration.ofSeconds(30);
54+
4255
public static ForkingExecutionControlProvider create(
4356
Collection<String> rawVirtualMachineOptions,
44-
ClassFileStore classFileStore
57+
ClassFileStore classFileStore,
58+
ScheduledExecutorService scheduler
4559
) {
4660
Objects.requireNonNull(classFileStore, "classFileStore");
4761
Objects.requireNonNull(rawVirtualMachineOptions, "rawVirtualMachineOptions");
48-
var host = InetAddress.getLoopbackAddress().getHostName();
4962
return new ForkingExecutionControlProvider(
50-
host,
63+
defaultExecutionTimeout,
5164
defaultTimeout,
5265
List.copyOf(rawVirtualMachineOptions),
53-
classFileStore
66+
classFileStore,
67+
scheduler
5468
);
5569
}
5670

57-
private final String host;
58-
private final Duration timeout;
71+
private final Duration connectTimeout;
72+
private final Duration executionTimeout;
5973
private final List<String> rawVirtualMachineOptions;
74+
private final ScheduledExecutorService scheduler;
6075
private final ClassFileStore classFileStore;
6176

6277
private ForkingExecutionControlProvider(
63-
String host,
64-
Duration timeout,
78+
Duration executionTimeout,
79+
Duration connectTimeout,
6580
List<String> rawVirtualMachineOptions,
66-
ClassFileStore classFileStore
81+
ClassFileStore classFileStore,
82+
ScheduledExecutorService scheduler
6783
) {
68-
this.host = host;
69-
this.timeout = timeout;
84+
this.executionTimeout = executionTimeout;
85+
this.connectTimeout = connectTimeout;
7086
this.rawVirtualMachineOptions = rawVirtualMachineOptions;
7187
this.classFileStore = classFileStore;
88+
this.scheduler = scheduler;
7289
}
7390

7491
@Override
@@ -101,7 +118,7 @@ private Box initiate(int port) {
101118
/* remoteAgentClassName */ remoteAgentClassName,
102119
/* controlledLaunch */ false,
103120
/* host */ "",
104-
/* timeout */ (int) timeout.toMillis(),
121+
/* timeout */ (int) connectTimeout.toMillis(),
105122
/* connectorOptions*/ Collections.emptyMap()
106123
);
107124
return new Box(
@@ -115,7 +132,7 @@ private Box initiate(int port) {
115132
ExecutionControl create(ExecutionEnv environment) throws IOException {
116133
var address = InetAddress.getLoopbackAddress();
117134
try (var listener = new ServerSocket(0, backlog, address)) {
118-
listener.setSoTimeout((int) timeout.toMillis());
135+
listener.setSoTimeout((int) connectTimeout.toMillis());
119136
var box = initiate(listener.getLocalPort());
120137
return accept(listener, environment, box);
121138
}
@@ -164,10 +181,19 @@ private BiFunction<ObjectInput, ObjectOutput, ExecutionControl> createControl(
164181
);
165182
hooks.add(event -> environment.closeDown());
166183
hooks.add(event -> control.disposeMachine());
184+
scheduleExecutionTimeout(control);
167185
return control;
168186
};
169187
}
170188

189+
private void scheduleExecutionTimeout(ForkedExecutionControl control) {
190+
scheduler.schedule(() -> {
191+
if (!control.isClosed()) {
192+
control.close();
193+
}
194+
}, executionTimeout.toMillis(), TimeUnit.MILLISECONDS);
195+
}
196+
171197
private Map<String, OutputStream> createOutputs(ExecutionEnv environment) {
172198
return Map.of(
173199
"out", environment.userOut(),

‎evaluation/src/main/java/jsheets/evaluation/shell/environment/sandbox/SandboxClassFileCheck.java‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,20 @@ private SandboxClassFileCheck(Collection<Rule> rules) {
2323

2424
@Override
2525
public void redefine(ExecutionControl.ClassBytecodes[] bytecodes) {
26+
analyze(bytecodes);
27+
}
28+
29+
@Override
30+
public void load(ExecutionControl.ClassBytecodes[] bytecodes) {
31+
analyze(bytecodes);
32+
}
33+
34+
private void analyze(ExecutionControl.ClassBytecodes[] bytecodes) {
2635
var analysis = Analysis.create();
2736
var check = SandboxBytecodeCheck.withRules(rules);
2837
for (var binary : bytecodes) {
2938
check.run(analysis, binary.bytecodes());
3039
}
3140
analysis.reportViolations();
3241
}
33-
34-
@Override
35-
public void load(ExecutionControl.ClassBytecodes[] bytecodes) {
36-
37-
}
3842
}

0 commit comments

Comments
 (0)