Skip to content

Restrict apm agent entitlements to the system classloader unnamed module #120546

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

Merged
merged 17 commits into from
Jan 28, 2025

Conversation

jdconrad
Copy link
Contributor

@jdconrad jdconrad commented Jan 21, 2025

This change closes a hole where we assumed any check against an unnamed-module from any classloader was for one of our apm agent. This was not the case and made it so scripts could in theory have the same entitlements as apm agent. Instead we now check to see if a class in an unnamed module is part of the system classloader to ensure it's actually for the apm agent.

Relates to ES-10192

@jdconrad jdconrad added >bug :Core/Infra/Plugins Plugin API and infrastructure auto-backport Automatically create backport pull requests when merged v9.0.0 v8.18.0 labels Jan 21, 2025
@elasticsearchmachine elasticsearchmachine added the Team:Core/Infra Meta label for core/infra team label Jan 21, 2025
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

@elasticsearchmachine
Copy link
Collaborator

Hi @jdconrad, I've created a changelog YAML for you.

@jdconrad jdconrad changed the title Restrict agent entitlements to the system classloader unnamed module Restrict apm agent entitlements to the system classloader unnamed module Jan 21, 2025
Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, a couple suggestions

@@ -236,8 +268,8 @@ private static Class<?> makeClassInItsOwnModule() throws IOException, ClassNotFo
return layer.findLoader("org.example.plugin").loadClass("q.B");
}

private static PolicyManager policyManagerWithEntitlementsModule(Module entitlementsModule) {
return new PolicyManager(createEmptyTestServerPolicy(), List.of(), Map.of(), c -> "test", entitlementsModule);
private static PolicyManager policyManagerWithEntitlementsModule(Module agentsModule, Module entitlementsModule) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, the method name is no longer accurate. Could this just be policyManager(...) now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@@ -209,7 +238,10 @@ public void testRequestingModuleWithStackWalk() throws IOException, ClassNotFoun
var instrumentedClass = makeClassInItsOwnModule(); // The class that called the check method
var ignorableClass = makeClassInItsOwnModule();

var policyManager = policyManagerWithEntitlementsModule(entitlementsClass.getModule());
var policyManager = policyManagerWithEntitlementsModule(
ClassLoader.getSystemClassLoader().getUnnamedModule(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of relying on the real classloader, can we create a test class in its own loader, similar to the above makeClassInItsOwnModule above? Then we can test that class gets the right policy when another class in an unnamed module does not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test for a test agents module.

@@ -59,6 +59,7 @@ public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule() {
List.of(),
Map.of("plugin1", createPluginPolicy("plugin.module")),
c -> "plugin1",
NO_ENTITLEMENTS_MODULE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than reuse NO_ENTITLEMENTS_MODULE, can we create a test specific agents module?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@ldematte
Copy link
Contributor

Looks good to me too, but ++ on all of Ryan's comments above

@jdconrad
Copy link
Contributor Author

@rjernst @ldematte Thank you for the reviews! I have updated this PR based on the feedback.

@jdconrad
Copy link
Contributor Author

@elasticmachine run elasticsearch-ci/part-2

Copy link
Contributor

@ldematte ldematte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; I'd add one additional test, but that's up to you

ModuleEntitlements agentsEntitlements = policyManager.getEntitlements(agentsClass);
assertThat(agentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(true));
ModuleEntitlements notAgentsEntitlements = policyManager.getEntitlements(notAgentsClass);
assertThat(notAgentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(false));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd like a check that uses two unnamed modules, to show that using named/unnamed is no longer a factor.
It should be simple, create 2 classloaders, load 2 classes (even the same) with them, and use classloader.getUnnamedModule() to pass to PolicyManager fot the agent module for one of the 2.
Even if it's the "same" class, one should pass, the other should not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea! I will add this.

@jdconrad jdconrad requested a review from a team as a code owner January 27, 2025 19:37
@@ -12,4 +12,4 @@
</RunnerSettings>
<method v="2" />
</configuration>
</component>
</component>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to commit this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, sigh.

@jdconrad jdconrad merged commit 343ec0b into elastic:main Jan 28, 2025
21 checks passed
jdconrad added a commit to jdconrad/elasticsearch that referenced this pull request Jan 28, 2025
…le (elastic#120546)

This change closes a hole where we assumed any check against an unnamed-module from any 
classloader was for one of our apm agent. This was not the case and made it so scripts could in theory 
have the same entitlements as apm agent. Instead we now check to see if a class is part of the apm 
package in an unnamed module to ensure it's actually for the apm agent.

Relates to ES-10192
@elasticsearchmachine
Copy link
Collaborator

💚 Backport successful

Status Branch Result
8.x

elasticsearchmachine pushed a commit that referenced this pull request Jan 28, 2025
…le (#120546) (#121054)

This change closes a hole where we assumed any check against an unnamed-module from any 
classloader was for one of our apm agent. This was not the case and made it so scripts could in theory 
have the same entitlements as apm agent. Instead we now check to see if a class is part of the apm 
package in an unnamed module to ensure it's actually for the apm agent.

Relates to ES-10192
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Automatically create backport pull requests when merged >bug :Core/Infra/Plugins Plugin API and infrastructure Team:Core/Infra Meta label for core/infra team v8.18.0 v9.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants