Skip to content

Commit 4012615

Browse files
authored
Avoid NullPointerException on empty enclave configuration during TEE pre-compute (#601)
1 parent 0b730f9 commit 4012615

File tree

5 files changed

+54
-43
lines changed

5 files changed

+54
-43
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
1414
- Fix `LoginServiceTests#shouldLoginOnceOnSimultaneousCalls` test. (#587)
1515
- Always use `WorkerpoolAuhorization` to retrieve JWT on Result Proxy. (#588)
1616
- Improve checks when receiving a `computed.json` file from a REST call. (#598)
17+
- Avoid `NullPointerException` on empty enclave configuration during TEE pre-compute. (#601)
1718

1819
### Quality
1920

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ iexecCommonVersion=8.4.0-NEXT-SNAPSHOT
33
iexecCommonsContainersVersion=1.2.1
44
iexecCommonsPocoVersion=3.2.0
55
iexecResultVersion=8.4.0
6-
iexecSmsVersion=8.5.0
6+
iexecSmsVersion=8.5.1-NEXT-SNAPSHOT
77
iexecCoreVersion=8.4.1-NEXT-SNAPSHOT
88
nexusUser
99
nexusPassword

src/main/java/com/iexec/worker/compute/pre/PreComputeService.java

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -50,7 +50,6 @@
5050
import static com.iexec.common.replicate.ReplicateStatusCause.*;
5151
import static com.iexec.sms.api.TeeSessionGenerationError.UNKNOWN_ISSUE;
5252

53-
5453
@Slf4j
5554
@Service
5655
public class PreComputeService {
@@ -89,22 +88,29 @@ public PreComputeService(
8988
* If the task contains a dataset or some input files, the pre-compute enclave
9089
* is started to handle them.
9190
*
92-
* @param taskDescription
93-
* @param workerpoolAuth
91+
* @param taskDescription Task description read on-chain
92+
* @param workerpoolAuth Workerpool authorization provided by scheduler
9493
* @return PreComputeResponse
9594
*/
9695
public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, WorkerpoolAuthorization workerpoolAuth) {
97-
String chainTaskId = taskDescription.getChainTaskId();
96+
final String chainTaskId = taskDescription.getChainTaskId();
9897
final PreComputeResponse.PreComputeResponseBuilder preComputeResponseBuilder = PreComputeResponse.builder()
9998
.isTeeTask(taskDescription.isTeeTask());
10099

101100
// verify enclave configuration for compute stage
102-
TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration();
101+
final TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration();
102+
if (enclaveConfig == null) {
103+
log.error("No enclave configuration found for task [chainTaskId:{}]", chainTaskId);
104+
return preComputeResponseBuilder
105+
.exitCause(PRE_COMPUTE_MISSING_ENCLAVE_CONFIGURATION)
106+
.build();
107+
}
103108
if (!enclaveConfig.getValidator().isValid()) {
104109
log.error("Invalid enclave configuration [chainTaskId:{}, violations:{}]",
105110
chainTaskId, enclaveConfig.getValidator().validate().toString());
106-
preComputeResponseBuilder.exitCause(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION);
107-
return preComputeResponseBuilder.build();
111+
return preComputeResponseBuilder
112+
.exitCause(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION)
113+
.build();
108114
}
109115
long teeComputeMaxHeapSize = DataSize
110116
.ofGigabytes(workerConfigService.getTeeComputeMaxHeapSizeGb())
@@ -117,8 +123,7 @@ public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, Work
117123
return preComputeResponseBuilder.build();
118124
}
119125
// create secure session
120-
TeeSessionGenerationResponse secureSession = null;
121-
TeeSessionGenerationError teeSessionGenerationError = null;
126+
final TeeSessionGenerationResponse secureSession;
122127
try {
123128
secureSession = smsService.createTeeSession(workerpoolAuth);
124129
if (secureSession == null) {
@@ -127,16 +132,15 @@ public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, Work
127132
preComputeResponseBuilder.secureSession(secureSession);
128133
} catch (TeeSessionGenerationException e) {
129134
log.error("Failed to create TEE secure session [chainTaskId:{}]", chainTaskId, e);
130-
teeSessionGenerationError = e.getTeeSessionGenerationError();
131-
preComputeResponseBuilder.exitCause(teeSessionGenerationErrorToReplicateStatusCause(e.getTeeSessionGenerationError()));
135+
return preComputeResponseBuilder
136+
.exitCause(teeSessionGenerationErrorToReplicateStatusCause(e.getTeeSessionGenerationError()))
137+
.build();
132138
}
133139

134140
// run TEE pre-compute container if needed
135-
if (teeSessionGenerationError == null &&
136-
(taskDescription.containsDataset() || taskDescription.containsInputFiles())) {
137-
log.info("Task contains TEE input data [chainTaskId:{}, containsDataset:{}, " +
138-
"containsInputFiles:{}]", chainTaskId, taskDescription.containsDataset(),
139-
taskDescription.containsInputFiles());
141+
if (taskDescription.containsDataset() || taskDescription.containsInputFiles()) {
142+
log.info("Task contains TEE input data [chainTaskId:{}, containsDataset:{}, containsInputFiles:{}]",
143+
chainTaskId, taskDescription.containsDataset(), taskDescription.containsInputFiles());
140144
final ReplicateStatusCause exitCause = downloadDatasetAndFiles(taskDescription, secureSession);
141145
preComputeResponseBuilder.exitCause(exitCause);
142146
}
@@ -152,8 +156,8 @@ private ReplicateStatusCause downloadDatasetAndFiles(
152156
if (exitCode == null || exitCode != 0) {
153157
String chainTaskId = taskDescription.getChainTaskId();
154158
ReplicateStatusCause exitCause = getExitCause(chainTaskId, exitCode);
155-
log.error("Failed to prepare TEE input data [chainTaskId:{}, " +
156-
"exitCode:{}, exitCause:{}]", chainTaskId, exitCode, exitCause);
159+
log.error("Failed to prepare TEE input data [chainTaskId:{}, exitCode:{}, exitCause:{}]",
160+
chainTaskId, exitCode, exitCause);
157161
return exitCause;
158162
}
159163
} catch (TimeoutException e) {

src/main/java/com/iexec/worker/executor/TaskManagerService.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ private ReplicateActionResponse triggerPostComputeHookOnError(String chainTaskId
228228

229229
ReplicateActionResponse compute(TaskDescription taskDescription) {
230230
final String chainTaskId = taskDescription.getChainTaskId();
231-
Optional<ReplicateStatusCause> oErrorStatus =
232-
contributionService.getCannotContributeStatusCause(chainTaskId);
233-
String context = "compute";
234-
if (oErrorStatus.isPresent()) {
235-
return getFailureResponseAndPrintError(oErrorStatus.get(), context, chainTaskId);
231+
final ReplicateStatusCause errorStatus = contributionService.getCannotContributeStatusCause(chainTaskId)
232+
.orElse(null);
233+
final String context = "compute";
234+
if (errorStatus != null) {
235+
return getFailureResponseAndPrintError(errorStatus, context, chainTaskId);
236236
}
237237

238238
if (!computeManagerService.isAppDownloaded(taskDescription.getAppUri())) {
@@ -255,13 +255,11 @@ ReplicateActionResponse compute(TaskDescription taskDescription) {
255255
computeManagerService.runPreCompute(taskDescription,
256256
workerpoolAuthorization);
257257
if (!preResponse.isSuccessful()) {
258-
final ReplicateActionResponse failureResponseAndPrintError;
259-
failureResponseAndPrintError = getFailureResponseAndPrintError(
258+
return getFailureResponseAndPrintError(
260259
preResponse.getExitCause(),
261260
context,
262261
chainTaskId
263262
);
264-
return failureResponseAndPrintError;
265263
}
266264

267265
AppComputeResponse appResponse =

src/test/java/com/iexec/worker/compute/pre/PreComputeServiceTests.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -56,6 +56,7 @@
5656

5757
import static com.iexec.common.replicate.ReplicateStatusCause.*;
5858
import static com.iexec.sms.api.TeeSessionGenerationError.*;
59+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
5960
import static org.mockito.ArgumentMatchers.any;
6061
import static org.mockito.Mockito.*;
6162

@@ -241,38 +242,47 @@ void shouldRunTeePreComputeAndPrepareInputDataWhenOnlyInputFilesArePresent() thr
241242
}
242243

243244
@Test
244-
void shouldFailToRunTeePreComputeSinceInvalidEnclaveConfiguration() throws TeeSessionGenerationException {
245+
void shouldFailToRunTeePreComputeSinceMissingEnclaveConfiguration() {
246+
final TaskDescription taskDescription = taskDescriptionBuilder.appEnclaveConfiguration(null).build();
247+
248+
final PreComputeResponse response = preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization);
249+
assertThat(response.isSuccessful()).isFalse();
250+
assertThat(response.getExitCause()).isEqualTo(PRE_COMPUTE_MISSING_ENCLAVE_CONFIGURATION);
251+
verifyNoInteractions(smsService);
252+
}
253+
254+
@Test
255+
void shouldFailToRunTeePreComputeSinceInvalidEnclaveConfiguration() {
245256
final TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder().build();
246257
final TaskDescription taskDescription = taskDescriptionBuilder.appEnclaveConfiguration(enclaveConfig).build();
247-
Assertions.assertThat(enclaveConfig.getValidator().isValid()).isFalse();
258+
assertThat(enclaveConfig.getValidator().isValid()).isFalse();
248259

249260
final PreComputeResponse response = preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization);
250-
Assertions.assertThat(response.isSuccessful()).isFalse();
251-
Assertions.assertThat(response.getExitCause()).isEqualTo(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION);
252-
verify(smsService, never()).createTeeSession(workerpoolAuthorization);
261+
assertThat(response.isSuccessful()).isFalse();
262+
assertThat(response.getExitCause()).isEqualTo(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION);
263+
verifyNoInteractions(smsService);
253264
}
254265

255266
@Test
256-
void shouldFailToRunTeePreComputeSinceTooHighComputeHeapSize() throws TeeSessionGenerationException {
267+
void shouldFailToRunTeePreComputeSinceTooHighComputeHeapSize() {
257268
final TeeEnclaveConfiguration enclaveConfiguration = TeeEnclaveConfiguration.builder()
258269
.fingerprint("01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b")
259270
.heapSize(DataSize.ofGigabytes(8).toBytes() + 1)
260271
.entrypoint("python /app/app.py")
261272
.build();
262273
final TaskDescription taskDescription = taskDescriptionBuilder.appEnclaveConfiguration(enclaveConfiguration).build();
263274

264-
Assertions.assertThat(preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization).isSuccessful())
275+
assertThat(preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization).isSuccessful())
265276
.isFalse();
266-
verify(smsService, never()).createTeeSession(workerpoolAuthorization);
277+
verifyNoInteractions(smsService);
267278
}
268279

269280
@Test
270281
void shouldFailToRunTeePreComputeSinceCantCreateTeeSession() throws TeeSessionGenerationException {
271282
final TaskDescription taskDescription = taskDescriptionBuilder.build();
283+
when(smsService.createTeeSession(workerpoolAuthorization)).thenReturn(null);
272284

273-
when(smsService.createTeeSession(workerpoolAuthorization)).thenReturn(secureSession);
274-
275-
Assertions.assertThat(preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization).isSuccessful())
285+
assertThat(preComputeService.runTeePreCompute(taskDescription, workerpoolAuthorization).isSuccessful())
276286
.isFalse();
277287
verify(smsService).createTeeSession(workerpoolAuthorization);
278288
verify(teeMockedService, never()).buildPreComputeDockerEnv(any(), any());
@@ -394,14 +404,12 @@ static Stream<Arguments> teeSessionGenerationErrorMap() {
394404
// Secure session generation
395405
Arguments.of(SECURE_SESSION_STORAGE_CALL_FAILED, TEE_SESSION_GENERATION_SECURE_SESSION_STORAGE_CALL_FAILED),
396406
Arguments.of(SECURE_SESSION_GENERATION_FAILED, TEE_SESSION_GENERATION_SECURE_SESSION_GENERATION_FAILED),
397-
Arguments.of(SECURE_SESSION_NO_TEE_PROVIDER, TEE_SESSION_GENERATION_SECURE_SESSION_NO_TEE_PROVIDER),
398-
Arguments.of(SECURE_SESSION_UNKNOWN_TEE_PROVIDER, TEE_SESSION_GENERATION_SECURE_SESSION_UNKNOWN_TEE_PROVIDER),
407+
Arguments.of(SECURE_SESSION_NO_TEE_FRAMEWORK, TEE_SESSION_GENERATION_SECURE_SESSION_NO_TEE_FRAMEWORK),
399408

400409
// Miscellaneous
401410
Arguments.of(GET_TASK_DESCRIPTION_FAILED, TEE_SESSION_GENERATION_GET_TASK_DESCRIPTION_FAILED),
402411
Arguments.of(NO_SESSION_REQUEST, TEE_SESSION_GENERATION_NO_SESSION_REQUEST),
403412
Arguments.of(NO_TASK_DESCRIPTION, TEE_SESSION_GENERATION_NO_TASK_DESCRIPTION),
404-
Arguments.of(GET_SESSION_FAILED, TEE_SESSION_GENERATION_GET_SESSION_FAILED),
405413

406414
Arguments.of(UNKNOWN_ISSUE, TEE_SESSION_GENERATION_UNKNOWN_ISSUE)
407415
);

0 commit comments

Comments
 (0)