1313import org .elasticsearch .core .SuppressForbidden ;
1414import org .elasticsearch .entitlement .instrumentation .InstrumentationService ;
1515import org .elasticsearch .entitlement .runtime .api .NotEntitledException ;
16+ import org .elasticsearch .entitlement .runtime .policy .FileAccessTree .ExclusiveFileEntitlement ;
17+ import org .elasticsearch .entitlement .runtime .policy .FileAccessTree .ExclusivePath ;
1618import org .elasticsearch .entitlement .runtime .policy .entitlements .CreateClassLoaderEntitlement ;
1719import org .elasticsearch .entitlement .runtime .policy .entitlements .Entitlement ;
1820import org .elasticsearch .entitlement .runtime .policy .entitlements .ExitVMEntitlement ;
3234import java .lang .module .ModuleFinder ;
3335import java .lang .module .ModuleReference ;
3436import java .nio .file .Path ;
37+ import java .util .ArrayList ;
3538import java .util .HashSet ;
3639import java .util .List ;
3740import java .util .Map ;
@@ -91,7 +94,7 @@ ModuleEntitlements defaultEntitlements(String componentName) {
9194 }
9295
9396 // pkg private for testing
94- ModuleEntitlements policyEntitlements (String componentName , List <Entitlement > entitlements ) {
97+ ModuleEntitlements policyEntitlements (String componentName , String moduleName , List <Entitlement > entitlements ) {
9598 FilesEntitlement filesEntitlement = FilesEntitlement .EMPTY ;
9699 for (Entitlement entitlement : entitlements ) {
97100 if (entitlement instanceof FilesEntitlement ) {
@@ -101,7 +104,7 @@ ModuleEntitlements policyEntitlements(String componentName, List<Entitlement> en
101104 return new ModuleEntitlements (
102105 componentName ,
103106 entitlements .stream ().collect (groupingBy (Entitlement ::getClass )),
104- FileAccessTree .of (filesEntitlement , pathLookup )
107+ FileAccessTree .of (componentName , moduleName , filesEntitlement , pathLookup , exclusivePaths )
105108 );
106109 }
107110
@@ -143,6 +146,13 @@ private static Set<Module> findSystemModules() {
143146 */
144147 private final Module entitlementsModule ;
145148
149+ /**
150+ * Paths that are only allowed for a single module. Used to generate
151+ * structures to indicate other modules aren't allowed to use these
152+ * files in {@link FileAccessTree}s.
153+ */
154+ private final List <ExclusivePath > exclusivePaths ;
155+
146156 public PolicyManager (
147157 Policy serverPolicy ,
148158 List <Entitlement > apmAgentEntitlements ,
@@ -162,25 +172,40 @@ public PolicyManager(
162172 this .apmAgentPackageName = apmAgentPackageName ;
163173 this .entitlementsModule = entitlementsModule ;
164174 this .pathLookup = requireNonNull (pathLookup );
165- this .defaultFileAccess = FileAccessTree .of (FilesEntitlement .EMPTY , pathLookup );
175+ this .defaultFileAccess = FileAccessTree .of (
176+ UNKNOWN_COMPONENT_NAME ,
177+ UNKNOWN_COMPONENT_NAME ,
178+ FilesEntitlement .EMPTY ,
179+ pathLookup ,
180+ List .of ()
181+ );
166182 this .mutedClasses = suppressFailureLogClasses ;
167183
184+ List <ExclusiveFileEntitlement > exclusiveFileEntitlements = new ArrayList <>();
168185 for (var e : serverEntitlements .entrySet ()) {
169- validateEntitlementsPerModule (SERVER_COMPONENT_NAME , e .getKey (), e .getValue ());
186+ validateEntitlementsPerModule (SERVER_COMPONENT_NAME , e .getKey (), e .getValue (), exclusiveFileEntitlements );
170187 }
171- validateEntitlementsPerModule (APM_AGENT_COMPONENT_NAME , "unnamed" , apmAgentEntitlements );
188+ validateEntitlementsPerModule (APM_AGENT_COMPONENT_NAME , ALL_UNNAMED , apmAgentEntitlements , exclusiveFileEntitlements );
172189 for (var p : pluginsEntitlements .entrySet ()) {
173190 for (var m : p .getValue ().entrySet ()) {
174- validateEntitlementsPerModule (p .getKey (), m .getKey (), m .getValue ());
191+ validateEntitlementsPerModule (p .getKey (), m .getKey (), m .getValue (), exclusiveFileEntitlements );
175192 }
176193 }
194+ List <ExclusivePath > exclusivePaths = FileAccessTree .buildExclusivePathList (exclusiveFileEntitlements , pathLookup );
195+ FileAccessTree .validateExclusivePaths (exclusivePaths );
196+ this .exclusivePaths = exclusivePaths ;
177197 }
178198
179199 private static Map <String , List <Entitlement >> buildScopeEntitlementsMap (Policy policy ) {
180200 return policy .scopes ().stream ().collect (toUnmodifiableMap (Scope ::moduleName , Scope ::entitlements ));
181201 }
182202
183- private static void validateEntitlementsPerModule (String componentName , String moduleName , List <Entitlement > entitlements ) {
203+ private static void validateEntitlementsPerModule (
204+ String componentName ,
205+ String moduleName ,
206+ List <Entitlement > entitlements ,
207+ List <ExclusiveFileEntitlement > exclusiveFileEntitlements
208+ ) {
184209 Set <Class <? extends Entitlement >> found = new HashSet <>();
185210 for (var e : entitlements ) {
186211 if (found .contains (e .getClass ())) {
@@ -189,6 +214,9 @@ private static void validateEntitlementsPerModule(String componentName, String m
189214 );
190215 }
191216 found .add (e .getClass ());
217+ if (e instanceof FilesEntitlement fe ) {
218+ exclusiveFileEntitlements .add (new ExclusiveFileEntitlement (componentName , moduleName , fe ));
219+ }
192220 }
193221 }
194222
@@ -498,7 +526,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
498526
499527 if (requestingModule .isNamed () == false && requestingClass .getPackageName ().startsWith (apmAgentPackageName )) {
500528 // The APM agent is the only thing running non-modular in the system classloader
501- return policyEntitlements (APM_AGENT_COMPONENT_NAME , apmAgentEntitlements );
529+ return policyEntitlements (APM_AGENT_COMPONENT_NAME , ALL_UNNAMED , apmAgentEntitlements );
502530 }
503531
504532 return defaultEntitlements (UNKNOWN_COMPONENT_NAME );
@@ -513,7 +541,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
513541 if (entitlements == null ) {
514542 return defaultEntitlements (componentName );
515543 }
516- return policyEntitlements (componentName , entitlements );
544+ return policyEntitlements (componentName , moduleName , entitlements );
517545 }
518546
519547 private static boolean isServerModule (Module requestingModule ) {
0 commit comments