Skip to content

Commit a9451df

Browse files
authored
Fix SecureSM to allow innocuous threads and threadgroups for parallel streams (#117277)
When a parallel stream is opened, the jdk uses an internal fork join pool to do work on processing the stream. This pool is internal to the jdk, and so it should always be allowed to create threads. This commit modifies SecureSM to account for this innocuous thread group and threads.
1 parent 8e6e087 commit a9451df

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

libs/secure-sm/src/main/java/org/elasticsearch/secure_sm/SecureSM.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ private static void debugThreadGroups(final ThreadGroup caller, final ThreadGrou
157157
// Returns true if the given thread is an instance of the JDK's InnocuousThread.
158158
private static boolean isInnocuousThread(Thread t) {
159159
final Class<?> c = t.getClass();
160-
return c.getModule() == Object.class.getModule() && c.getName().equals("jdk.internal.misc.InnocuousThread");
160+
return c.getModule() == Object.class.getModule()
161+
&& (c.getName().equals("jdk.internal.misc.InnocuousThread")
162+
|| c.getName().equals("java.util.concurrent.ForkJoinWorkerThread$InnocuousForkJoinWorkerThread"));
161163
}
162164

163165
protected void checkThreadAccess(Thread t) {
@@ -184,19 +186,29 @@ protected void checkThreadAccess(Thread t) {
184186
private static final Permission MODIFY_THREADGROUP_PERMISSION = new RuntimePermission("modifyThreadGroup");
185187
private static final Permission MODIFY_ARBITRARY_THREADGROUP_PERMISSION = new ThreadPermission("modifyArbitraryThreadGroup");
186188

189+
// Returns true if the given thread is an instance of the JDK's InnocuousThread.
190+
private static boolean isInnocuousThreadGroup(ThreadGroup t) {
191+
final Class<?> c = t.getClass();
192+
return c.getModule() == Object.class.getModule() && t.getName().equals("InnocuousForkJoinWorkerThreadGroup");
193+
}
194+
187195
protected void checkThreadGroupAccess(ThreadGroup g) {
188196
Objects.requireNonNull(g);
189197

198+
boolean targetThreadGroupIsInnocuous = isInnocuousThreadGroup(g);
199+
190200
// first, check if we can modify thread groups at all.
191-
checkPermission(MODIFY_THREADGROUP_PERMISSION);
201+
if (targetThreadGroupIsInnocuous == false) {
202+
checkPermission(MODIFY_THREADGROUP_PERMISSION);
203+
}
192204

193205
// check the threadgroup, if its our thread group or an ancestor, its fine.
194206
final ThreadGroup source = Thread.currentThread().getThreadGroup();
195207
final ThreadGroup target = g;
196208

197209
if (source == null) {
198210
return; // we are a dead thread, do nothing
199-
} else if (source.parentOf(target) == false) {
211+
} else if (source.parentOf(target) == false && targetThreadGroupIsInnocuous == false) {
200212
checkPermission(MODIFY_ARBITRARY_THREADGROUP_PERMISSION);
201213
}
202214
}

libs/secure-sm/src/test/java/org/elasticsearch/secure_sm/SecureSMTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
import java.security.Permission;
1515
import java.security.Policy;
1616
import java.security.ProtectionDomain;
17+
import java.util.ArrayList;
18+
import java.util.List;
1719
import java.util.concurrent.atomic.AtomicBoolean;
20+
import java.util.stream.Collectors;
1821

1922
/** Simple tests for SecureSM */
2023
public class SecureSMTests extends TestCase {
@@ -128,4 +131,12 @@ public void run() {
128131
t1.join();
129132
assertTrue(interrupted1.get());
130133
}
134+
135+
public void testParallelStreamThreadGroup() throws Exception {
136+
List<Integer> list = new ArrayList<>();
137+
for (int i = 0; i < 100; ++i) {
138+
list.add(i);
139+
}
140+
list.parallelStream().collect(Collectors.toSet());
141+
}
131142
}

0 commit comments

Comments
 (0)