1616
1717import  org .elasticsearch .core .SuppressForbidden ;
1818import  org .elasticsearch .entitlement .initialization .EntitlementInitialization ;
19+ import  org .elasticsearch .entitlement .runtime .api .NotEntitledException ;
1920import  org .elasticsearch .logging .LogManager ;
2021import  org .elasticsearch .logging .Logger ;
2122
2223import  java .io .IOException ;
2324import  java .nio .file .Files ;
2425import  java .nio .file .Path ;
2526import  java .util .Collection ;
26- import  java .util .Objects ;
2727import  java .util .function .Function ;
2828
29+ import  static  java .util .Objects .requireNonNull ;
30+ 
2931public  class  EntitlementBootstrap  {
3032
31-     public  record  PluginData (Path  pluginPath , boolean  isModular , boolean  isExternalPlugin ) {}
33+     public  record  BootstrapArgs (Collection <PluginData > pluginData , Function <Class <?>, String > pluginResolver ) {
34+         public  BootstrapArgs  {
35+             requireNonNull (pluginData );
36+             requireNonNull (pluginResolver );
37+         }
38+     }
3239
33-     public  record  BootstrapArgs (Collection <PluginData > pluginData , Function <Class <?>, String > pluginResolver ) {}
40+     public  record  PluginData (Path  pluginPath , boolean  isModular , boolean  isExternalPlugin ) {
41+         public  PluginData  {
42+             requireNonNull (pluginPath );
43+         }
44+     }
3445
3546    private  static  BootstrapArgs  bootstrapArgs ;
3647
@@ -50,9 +61,10 @@ public static void bootstrap(Collection<PluginData> pluginData, Function<Class<?
5061        if  (EntitlementBootstrap .bootstrapArgs  != null ) {
5162            throw  new  IllegalStateException ("plugin data is already set" );
5263        }
53-         EntitlementBootstrap .bootstrapArgs  = new  BootstrapArgs (Objects . requireNonNull ( pluginData ),  Objects . requireNonNull ( pluginResolver ) );
64+         EntitlementBootstrap .bootstrapArgs  = new  BootstrapArgs (pluginData ,  pluginResolver );
5465        exportInitializationToAgent ();
5566        loadAgent (findAgentJar ());
67+         selfTest ();
5668    }
5769
5870    @ SuppressForbidden (reason  = "The VirtualMachine API is the only way to attach a java agent dynamically" )
@@ -98,5 +110,63 @@ private static String findAgentJar() {
98110        }
99111    }
100112
113+     /** 
114+      * Attempt a few sensitive operations to ensure that some are permitted and some are forbidden. 
115+      * <p> 
116+      * 
117+      * This serves two purposes: 
118+      * 
119+      * <ol> 
120+      *     <li> 
121+      *         a smoke test to make sure the entitlements system is not completely broken, and 
122+      *     </li> 
123+      *     <li> 
124+      *         an early test of certain important operations so they don't fail later on at an awkward time. 
125+      *     </li> 
126+      * </ol> 
127+      * 
128+      * @throws IllegalStateException if the entitlements system can't prevent an unauthorized action of our choosing 
129+      */ 
130+     private  static  void  selfTest () {
131+         ensureCannotStartProcess ();
132+         ensureCanCreateTempFile ();
133+     }
134+ 
135+     private  static  void  ensureCannotStartProcess () {
136+         try  {
137+             // The command doesn't matter; it doesn't even need to exist 
138+             new  ProcessBuilder ("" ).start ();
139+         } catch  (NotEntitledException  e ) {
140+             logger .debug ("Success: Entitlement protection correctly prevented process creation" );
141+             return ;
142+         } catch  (IOException  e ) {
143+             throw  new  IllegalStateException ("Failed entitlement protection self-test" , e );
144+         }
145+         throw  new  IllegalStateException ("Entitlement protection self-test was incorrectly permitted" );
146+     }
147+ 
148+     /** 
149+      * Originally {@code Security.selfTest}. 
150+      */ 
151+     @ SuppressForbidden (reason  = "accesses jvm default tempdir as a self-test" )
152+     private  static  void  ensureCanCreateTempFile () {
153+         try  {
154+             Path  p  = Files .createTempFile (null , null );
155+             p .toFile ().deleteOnExit ();
156+ 
157+             // Make an effort to clean up the file immediately; also, deleteOnExit leaves the file if the JVM exits abnormally. 
158+             try  {
159+                 Files .delete (p );
160+             } catch  (IOException  ignored ) {
161+                 // Can be caused by virus scanner 
162+             }
163+         } catch  (NotEntitledException  e ) {
164+             throw  new  IllegalStateException ("Entitlement protection self-test was incorrectly forbidden" , e );
165+         } catch  (Exception  e ) {
166+             throw  new  IllegalStateException ("Unable to perform entitlement protection self-test" , e );
167+         }
168+         logger .debug ("Success: Entitlement protection correctly permitted temp file creation" );
169+     }
170+ 
101171    private  static  final  Logger  logger  = LogManager .getLogger (EntitlementBootstrap .class );
102172}
0 commit comments