Skip to content

Commit 36adb27

Browse files
rrvajack-berg
andauthored
Allow SDK to run in environments prohibiting use of sun.misc.Unsafe (#4902)
Some applications run under strict java.security permissions which do not allow access to sun.misc.Unsafe. BatchSpanProcessor uses Unsafe via jctools, but has a fallback to ArrayBlockingQueue. Extending that fallback rule to cover java security exceptions as well. Co-authored-by: Jack Berg <[email protected]>
1 parent f83def7 commit 36adb27

File tree

5 files changed

+211
-2
lines changed

5 files changed

+211
-2
lines changed

sdk/trace-shaded-deps/build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ tasks {
2626
into("build/extracted/shadow")
2727
}
2828
}
29+
30+
tasks.withType<Test>().configureEach {
31+
// JcToolsSecurityManagerTest interferes with JcToolsTest
32+
setForkEvery(1)
33+
}

sdk/trace-shaded-deps/src/main/java/io/opentelemetry/sdk/trace/internal/JcTools.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55

66
package io.opentelemetry.sdk.trace.internal;
77

8+
import java.util.Objects;
89
import java.util.Queue;
910
import java.util.concurrent.ArrayBlockingQueue;
11+
import java.util.concurrent.atomic.AtomicBoolean;
1012
import java.util.function.Consumer;
13+
import java.util.logging.Level;
14+
import java.util.logging.Logger;
1115
import org.jctools.queues.MessagePassingQueue;
1216
import org.jctools.queues.MpscArrayQueue;
1317

@@ -19,14 +23,24 @@
1923
*/
2024
public final class JcTools {
2125

26+
private static final AtomicBoolean queueCreationWarningLogged = new AtomicBoolean();
27+
private static final Logger logger = Logger.getLogger(JcTools.class.getName());
28+
2229
/**
2330
* Returns a new {@link Queue} appropriate for use with multiple producers and a single consumer.
2431
*/
2532
public static <T> Queue<T> newFixedSizeQueue(int capacity) {
2633
try {
2734
return new MpscArrayQueue<>(capacity);
28-
} catch (java.lang.NoClassDefFoundError e) {
29-
// Happens when modules such as jdk.unsupported are disabled in a custom JRE distribution
35+
} catch (java.lang.NoClassDefFoundError | java.lang.ExceptionInInitializerError e) {
36+
if (!queueCreationWarningLogged.getAndSet(true)) {
37+
logger.log(
38+
Level.WARNING,
39+
"Cannot create high-performance queue, reverting to ArrayBlockingQueue ({0})",
40+
Objects.toString(e, "unknown cause"));
41+
}
42+
// Happens when modules such as jdk.unsupported are disabled in a custom JRE distribution,
43+
// or a security manager preventing access to Unsafe is installed.
3044
return new ArrayBlockingQueue<>(capacity);
3145
}
3246
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.trace.internal;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
11+
import java.security.AccessController;
12+
import java.security.PrivilegedAction;
13+
import java.util.Queue;
14+
import java.util.concurrent.ArrayBlockingQueue;
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.condition.EnabledOnJre;
17+
import org.junit.jupiter.api.condition.JRE;
18+
19+
public class JcToolsSecurityManagerTest {
20+
21+
@Test
22+
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_17})
23+
@SuppressLogger(JcTools.class)
24+
void newFixedSizeQueue_SunMiscProhibited() {
25+
assertThat(System.getSecurityManager()).isNull();
26+
SunMiscProhibitedSecurityManager testingSecurityManager =
27+
new SunMiscProhibitedSecurityManager();
28+
try {
29+
System.setSecurityManager(testingSecurityManager);
30+
Queue<Object> queue =
31+
AccessController.doPrivileged(
32+
(PrivilegedAction<Queue<Object>>) () -> JcTools.newFixedSizeQueue(10));
33+
assertThat(queue).isInstanceOf(ArrayBlockingQueue.class);
34+
} finally {
35+
System.setSecurityManager(null);
36+
}
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.trace.internal;
7+
8+
import java.io.FileDescriptor;
9+
import java.net.InetAddress;
10+
import java.security.AccessControlException;
11+
import java.security.Permission;
12+
13+
/**
14+
* A security manager which disallows access to classes in sun.misc. Running the tests with a
15+
* standard security manager is too invasive.
16+
*/
17+
public class SunMiscProhibitedSecurityManager extends SecurityManager {
18+
19+
public SunMiscProhibitedSecurityManager() {}
20+
21+
@Override
22+
protected Class<?>[] getClassContext() {
23+
return super.getClassContext();
24+
}
25+
26+
@Override
27+
public void checkPermission(Permission perm) {
28+
if (perm.getName().equals("accessClassInPackage.sun.misc")) {
29+
throw new AccessControlException("access denied " + perm, perm);
30+
}
31+
}
32+
33+
@Override
34+
public void checkPermission(Permission perm, Object context) {}
35+
36+
@Override
37+
public void checkCreateClassLoader() {}
38+
39+
@Override
40+
public void checkAccess(Thread t) {}
41+
42+
@Override
43+
public void checkAccess(ThreadGroup g) {}
44+
45+
@Override
46+
public void checkExit(int status) {}
47+
48+
@Override
49+
public void checkExec(String cmd) {}
50+
51+
@Override
52+
public void checkLink(String lib) {}
53+
54+
@Override
55+
public void checkRead(FileDescriptor fd) {}
56+
57+
@Override
58+
public void checkRead(String file) {}
59+
60+
@Override
61+
public void checkRead(String file, Object context) {}
62+
63+
@Override
64+
public void checkWrite(FileDescriptor fd) {}
65+
66+
@Override
67+
public void checkWrite(String file) {}
68+
69+
@Override
70+
public void checkDelete(String file) {}
71+
72+
@Override
73+
public void checkConnect(String host, int port) {}
74+
75+
@Override
76+
public void checkConnect(String host, int port, Object context) {}
77+
78+
@Override
79+
public void checkListen(int port) {}
80+
81+
@Override
82+
public void checkAccept(String host, int port) {}
83+
84+
@Override
85+
public void checkMulticast(InetAddress maddr) {}
86+
87+
@Override
88+
public void checkPropertiesAccess() {}
89+
90+
@Override
91+
public void checkPropertyAccess(String key) {}
92+
93+
@Override
94+
public void checkPrintJobAccess() {}
95+
96+
@Override
97+
public void checkPackageAccess(String pkg) {
98+
if (pkg.equals("sun.misc")) {
99+
super.checkPackageAccess(pkg);
100+
}
101+
}
102+
103+
@Override
104+
public void checkPackageDefinition(String pkg) {}
105+
106+
@Override
107+
public void checkSetFactory() {}
108+
109+
@Override
110+
public void checkSecurityAccess(String target) {}
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.trace.internal;
7+
8+
import static org.assertj.core.api.Assertions.assertThatNoException;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
11+
import java.security.AccessControlException;
12+
import org.junit.jupiter.api.Test;
13+
14+
class SunMiscProhibitedSecurityManagerTest {
15+
16+
@Test
17+
public void checkPackageAccess_ProhibitsSunMisc() {
18+
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();
19+
assertThatThrownBy(() -> sm.checkPackageAccess("sun.misc"))
20+
.isInstanceOf(AccessControlException.class)
21+
.hasMessage(
22+
"access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.misc\")");
23+
}
24+
25+
@Test
26+
public void checkPackageAccess_ProhibitsSunMiscRuntimePermission() {
27+
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();
28+
29+
assertThatThrownBy(
30+
() -> sm.checkPermission(new RuntimePermission("accessClassInPackage.sun.misc")))
31+
.isInstanceOf(AccessControlException.class)
32+
.hasMessage(
33+
"access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.misc\")");
34+
}
35+
36+
@Test
37+
public void checkPackageAccess_AllowsOtherPackage() {
38+
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();
39+
assertThatNoException().isThrownBy(() -> sm.checkPackageAccess("io.opentelemetry.sdk"));
40+
}
41+
}

0 commit comments

Comments
 (0)