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