Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow SDK to run in environments prohibiting use of sun.misc.Unsafe #4902

Merged
merged 2 commits into from Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions sdk/trace-shaded-deps/build.gradle.kts
Expand Up @@ -26,3 +26,8 @@ tasks {
into("build/extracted/shadow")
}
}

tasks.withType<Test>().configureEach {
// JcToolsSecurityManagerTest interferes with JcToolsTest
setForkEvery(1)
}
Expand Up @@ -5,9 +5,13 @@

package io.opentelemetry.sdk.trace.internal;

import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jctools.queues.MessagePassingQueue;
import org.jctools.queues.MpscArrayQueue;

Expand All @@ -19,14 +23,24 @@
*/
public final class JcTools {

private static final AtomicBoolean queueCreationWarningLogged = new AtomicBoolean();
private static final Logger logger = Logger.getLogger(JcTools.class.getName());

/**
* Returns a new {@link Queue} appropriate for use with multiple producers and a single consumer.
*/
public static <T> Queue<T> newFixedSizeQueue(int capacity) {
try {
return new MpscArrayQueue<>(capacity);
} catch (java.lang.NoClassDefFoundError e) {
// Happens when modules such as jdk.unsupported are disabled in a custom JRE distribution
} catch (java.lang.NoClassDefFoundError | java.lang.ExceptionInInitializerError e) {
if (!queueCreationWarningLogged.getAndSet(true)) {
logger.log(
Level.WARNING,
"Cannot create high-performance queue, reverting to ArrayBlockingQueue ({0})",
Objects.toString(e, "unknown cause"));
}
// Happens when modules such as jdk.unsupported are disabled in a custom JRE distribution,
// or a security manager preventing access to Unsafe is installed.
return new ArrayBlockingQueue<>(capacity);
}
}
Expand Down
@@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.internal;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;

public class JcToolsSecurityManagerTest {

@Test
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_17})
rrva marked this conversation as resolved.
Show resolved Hide resolved
@SuppressLogger(JcTools.class)
void newFixedSizeQueue_SunMiscProhibited() {
rrva marked this conversation as resolved.
Show resolved Hide resolved
assertThat(System.getSecurityManager()).isNull();
SunMiscProhibitedSecurityManager testingSecurityManager =
new SunMiscProhibitedSecurityManager();
try {
System.setSecurityManager(testingSecurityManager);
Queue<Object> queue =
AccessController.doPrivileged(
(PrivilegedAction<Queue<Object>>) () -> JcTools.newFixedSizeQueue(10));
assertThat(queue).isInstanceOf(ArrayBlockingQueue.class);
} finally {
System.setSecurityManager(null);
}
}
}
@@ -0,0 +1,111 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.internal;

import java.io.FileDescriptor;
import java.net.InetAddress;
import java.security.AccessControlException;
import java.security.Permission;

/**
* A security manager which disallows access to classes in sun.misc. Running the tests with a
* standard security manager is too invasive.
*/
public class SunMiscProhibitedSecurityManager extends SecurityManager {

public SunMiscProhibitedSecurityManager() {}

@Override
protected Class<?>[] getClassContext() {
return super.getClassContext();
}

@Override
public void checkPermission(Permission perm) {
if (perm.getName().equals("accessClassInPackage.sun.misc")) {
throw new AccessControlException("access denied " + perm, perm);
}
}

@Override
public void checkPermission(Permission perm, Object context) {}

@Override
public void checkCreateClassLoader() {}

@Override
public void checkAccess(Thread t) {}

@Override
public void checkAccess(ThreadGroup g) {}

@Override
public void checkExit(int status) {}

@Override
public void checkExec(String cmd) {}

@Override
public void checkLink(String lib) {}

@Override
public void checkRead(FileDescriptor fd) {}

@Override
public void checkRead(String file) {}

@Override
public void checkRead(String file, Object context) {}

@Override
public void checkWrite(FileDescriptor fd) {}

@Override
public void checkWrite(String file) {}

@Override
public void checkDelete(String file) {}

@Override
public void checkConnect(String host, int port) {}

@Override
public void checkConnect(String host, int port, Object context) {}

@Override
public void checkListen(int port) {}

@Override
public void checkAccept(String host, int port) {}

@Override
public void checkMulticast(InetAddress maddr) {}

@Override
public void checkPropertiesAccess() {}

@Override
public void checkPropertyAccess(String key) {}

@Override
public void checkPrintJobAccess() {}

@Override
public void checkPackageAccess(String pkg) {
if (pkg.equals("sun.misc")) {
super.checkPackageAccess(pkg);
}
}

@Override
public void checkPackageDefinition(String pkg) {}

@Override
public void checkSetFactory() {}

@Override
public void checkSecurityAccess(String target) {}
}
@@ -0,0 +1,41 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.internal;

import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.security.AccessControlException;
import org.junit.jupiter.api.Test;

class SunMiscProhibitedSecurityManagerTest {

@Test
public void checkPackageAccess_ProhibitsSunMisc() {
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();
assertThatThrownBy(() -> sm.checkPackageAccess("sun.misc"))
.isInstanceOf(AccessControlException.class)
.hasMessage(
"access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.misc\")");
}

@Test
public void checkPackageAccess_ProhibitsSunMiscRuntimePermission() {
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();

assertThatThrownBy(
() -> sm.checkPermission(new RuntimePermission("accessClassInPackage.sun.misc")))
.isInstanceOf(AccessControlException.class)
.hasMessage(
"access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.misc\")");
}

@Test
public void checkPackageAccess_AllowsOtherPackage() {
SunMiscProhibitedSecurityManager sm = new SunMiscProhibitedSecurityManager();
assertThatNoException().isThrownBy(() -> sm.checkPackageAccess("io.opentelemetry.sdk"));
}
}