Skip to content

Commit 412f738

Browse files
author
Felix Berlakovich
committed
[GR-43835] Add new SpeculativeExecutionBarriers option instead of AllTargets option for SpectrePHTBarriers
PullRequest: graal/13621
2 parents cfd323b + 078a719 commit 412f738

File tree

4 files changed

+99
-9
lines changed

4 files changed

+99
-9
lines changed

compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpectrePHTMitigations.java

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,14 @@
2424
*/
2525
package org.graalvm.compiler.core.common;
2626

27+
import org.graalvm.collections.EconomicMap;
28+
import org.graalvm.collections.UnmodifiableEconomicMap;
2729
import org.graalvm.compiler.options.EnumOptionKey;
2830
import org.graalvm.compiler.options.Option;
2931
import org.graalvm.compiler.options.OptionKey;
3032
import org.graalvm.compiler.options.OptionStability;
3133
import org.graalvm.compiler.options.OptionType;
34+
import org.graalvm.compiler.options.OptionValues;
3235

3336
public enum SpectrePHTMitigations {
3437
None,
@@ -38,8 +41,55 @@ public enum SpectrePHTMitigations {
3841

3942
public static class Options {
4043
// @formatter:off
44+
45+
@Option(help = "Stop speculative execution on all branch targets with execution barrier instructions.", stability = OptionStability.STABLE)
46+
public static final OptionKey<Boolean> SpeculativeExecutionBarriers = new OptionKey<>(false) {
47+
48+
@Override
49+
public Boolean getValue(OptionValues values) {
50+
// Do not use getValue to avoid an infinite recursion
51+
if (values.getMap().get(SpectrePHTBarriers) == AllTargets) {
52+
return true;
53+
}
54+
return super.getValue(values);
55+
}
56+
57+
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
58+
if (values.containsKey(SpectrePHTBarriers)) {
59+
Object otherValue = values.get(SpectrePHTBarriers);
60+
if (newValue && otherValue != AllTargets || (!newValue && otherValue == AllTargets)) {
61+
throw new IllegalArgumentException("SpectrePHTBarriers can be set to 'AllTargets' if and only if SpeculativeExecutionBarriers is enabled or unspecified.");
62+
}
63+
}
64+
}
65+
};
66+
4167
@Option(help = "file:doc-files/MitigateSpeculativeExecutionAttacksHelp.txt")
42-
public static final EnumOptionKey<SpectrePHTMitigations> SpectrePHTBarriers = new EnumOptionKey<>(None);
68+
public static final EnumOptionKey<SpectrePHTMitigations> SpectrePHTBarriers = new EnumOptionKey<>(None) {
69+
private boolean isSpeculativeExecutionBarriersEnabled(UnmodifiableEconomicMap<OptionKey<?>, Object> values) {
70+
Object value = values.get(SpeculativeExecutionBarriers);
71+
return value != null && (boolean) value;
72+
}
73+
74+
@Override
75+
public SpectrePHTMitigations getValue(OptionValues values) {
76+
if (isSpeculativeExecutionBarriersEnabled(values.getMap())) {
77+
return AllTargets;
78+
}
79+
return super.getValue(values);
80+
}
81+
82+
@Override
83+
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, SpectrePHTMitigations oldValue, SpectrePHTMitigations newValue) {
84+
if (values.containsKey(SpeculativeExecutionBarriers)) {
85+
boolean otherIsEnabled = isSpeculativeExecutionBarriersEnabled(values);
86+
if (otherIsEnabled && newValue != AllTargets || (!otherIsEnabled && newValue == AllTargets)) {
87+
throw new IllegalArgumentException("SpectrePHTBarriers can be set to 'AllTargets' if and only if SpeculativeExecutionBarriers is enabled or unspecified.");
88+
}
89+
}
90+
}
91+
};
92+
4393
@Option(help = "Mask indices to scope access to allocation size after bounds check.", type = OptionType.User, stability = OptionStability.STABLE)
4494
public static final OptionKey<Boolean> SpectrePHTIndexMasking = new OptionKey<>(false);
4595
// @formatter:on

compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/doc-files/MitigateSpeculativeExecutionAttacksHelp.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Select a strategy to mitigate speculative bounds check bypass (aka Spectre-PHT o
22
This is an experimental option - execution of untrusted code is not supported by GraalVM CE.
33
The accepted values are:
44
None - No mitigations are used in JIT compiled code.
5-
AllTargets - Speculative execution on all conditional branch targets is
5+
AllTargets - Speculative execution on all branch targets is
66
stopped using speculative execution barrier instructions.
7+
This option is equivalent to setting SpeculativeExecutionBarriers to true.
78
GuardTargets - Branch targets relevant to Java memory safety are instrumented
89
with barrier instructions. This option has less performance impact
910
than AllTargets.

compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SpectreFenceTest.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,19 @@
2525

2626
package org.graalvm.compiler.core.test;
2727

28+
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.AllTargets;
29+
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.GuardTargets;
30+
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.Options.SpectrePHTBarriers;
31+
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.Options.SpeculativeExecutionBarriers;
2832
import static org.junit.Assume.assumeTrue;
2933

34+
import org.graalvm.collections.EconomicMap;
3035
import org.graalvm.compiler.api.directives.GraalDirectives;
3136
import org.graalvm.compiler.api.test.Graal;
3237
import org.graalvm.compiler.core.common.SpectrePHTMitigations;
3338
import org.graalvm.compiler.nodes.AbstractBeginNode;
3439
import org.graalvm.compiler.nodes.StructuredGraph;
40+
import org.graalvm.compiler.options.OptionKey;
3541
import org.graalvm.compiler.options.OptionValues;
3642
import org.graalvm.compiler.runtime.RuntimeProvider;
3743
import org.junit.Assert;
@@ -128,4 +134,38 @@ public void test03() {
128134
test(getFenceOptions(), "test3Snippet", 10D);
129135
assertNumberOfFences("test3Snippet", 1);
130136
}
137+
138+
@Test
139+
public void testOptionConsistency() throws Exception {
140+
// If one side is unspecified, the options are synchronized
141+
OptionValues onlyExecutionBarriers = new OptionValues(getInitialOptions(), SpeculativeExecutionBarriers, true);
142+
Assert.assertTrue(SpeculativeExecutionBarriers.getValue(onlyExecutionBarriers));
143+
Assert.assertEquals(SpectrePHTBarriers.getValue(onlyExecutionBarriers), AllTargets);
144+
OptionValues onlyAllTargets = new OptionValues(getInitialOptions(), SpectrePHTMitigations.Options.SpectrePHTBarriers, AllTargets);
145+
Assert.assertTrue(SpeculativeExecutionBarriers.getValue(onlyAllTargets));
146+
Assert.assertEquals(SpectrePHTBarriers.getValue(onlyAllTargets), AllTargets);
147+
148+
// If both sides are set explicitly, they have to be consistent
149+
try {
150+
EconomicMap<OptionKey<?>, Object> optionValues = OptionValues.asMap(SpeculativeExecutionBarriers, false);
151+
SpectrePHTBarriers.update(optionValues, AllTargets);
152+
Assert.fail("Inconsistent option values are not prevented");
153+
} catch (IllegalArgumentException e) {
154+
// this should happen
155+
}
156+
157+
try {
158+
// If both sides are set explicitly, they have to be consistent
159+
EconomicMap<OptionKey<?>, Object> optionValues = OptionValues.asMap(SpectrePHTBarriers, GuardTargets);
160+
SpeculativeExecutionBarriers.update(optionValues, true);
161+
Assert.fail("Inconsistent option values are not prevented");
162+
} catch (IllegalArgumentException e) {
163+
// this should happen
164+
}
165+
166+
// Explicitly but consistent is fine
167+
EconomicMap<OptionKey<?>, Object> optionValues = OptionValues.asMap(SpectrePHTBarriers, AllTargets);
168+
SpeculativeExecutionBarriers.update(optionValues, true);
169+
170+
}
131171
}

compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,7 @@
2828
import static jdk.vm.ci.code.ValueUtil.isLegal;
2929
import static jdk.vm.ci.code.ValueUtil.isRegister;
3030
import static org.graalvm.compiler.core.common.GraalOptions.MatchExpressions;
31-
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.AllTargets;
32-
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.Options.SpectrePHTBarriers;
31+
import static org.graalvm.compiler.core.common.SpectrePHTMitigations.Options.SpeculativeExecutionBarriers;
3332
import static org.graalvm.compiler.core.match.ComplexMatchValue.INTERIOR_MATCH;
3433
import static org.graalvm.compiler.debug.DebugOptions.LogVerbose;
3534
import static org.graalvm.compiler.lir.LIR.verifyBlock;
@@ -102,8 +101,8 @@
102101
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
103102
import org.graalvm.compiler.nodes.calc.IntegerTestNode;
104103
import org.graalvm.compiler.nodes.calc.IsNullNode;
105-
import org.graalvm.compiler.nodes.cfg.HIRBlock;
106104
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
105+
import org.graalvm.compiler.nodes.cfg.HIRBlock;
107106
import org.graalvm.compiler.nodes.extended.ForeignCall;
108107
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
109108
import org.graalvm.compiler.nodes.extended.OpaqueLogicNode;
@@ -346,7 +345,7 @@ private Value[] createPhiOut(AbstractMergeNode merge, AbstractEndNode pred) {
346345

347346
public void doBlockPrologue(@SuppressWarnings("unused") HIRBlock block, @SuppressWarnings("unused") OptionValues options) {
348347

349-
if (SpectrePHTBarriers.getValue(options) == AllTargets) {
348+
if (SpeculativeExecutionBarriers.getValue(options)) {
350349
boolean hasControlSplitPredecessor = false;
351350
for (int i = 0; i < block.getPredecessorCount(); i++) {
352351
HIRBlock b = block.getPredecessorAt(i);

0 commit comments

Comments
 (0)