Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions src/sec_adapter_processor.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ Sec_Result SecProcessor_GetInstance_Directories(Sec_ProcessorHandle** processorH
return SEC_RESULT_FAILURE;
}

// Register handle in global list before any sa_invoke calls during init
pthread_mutex_lock(&mutex);
newProcessorHandle->nextHandle = processorHandleList;
processorHandleList = newProcessorHandle;
pthread_mutex_unlock(&mutex);

/* generate sec store proc ins */
result = SecStore_GenerateLadderInputs(newProcessorHandle, SEC_STORE_AES_LADDER_INPUT, NULL,
(SEC_BYTE*) &derived_inputs, sizeof(derived_inputs));
Expand Down Expand Up @@ -238,10 +244,6 @@ Sec_Result SecProcessor_GetInstance_Directories(Sec_ProcessorHandle** processorH
return result;
}

pthread_mutex_lock(&mutex);
newProcessorHandle->nextHandle = processorHandleList;
processorHandleList = newProcessorHandle;
pthread_mutex_unlock(&mutex);
*processorHandle = newProcessorHandle;
return SEC_RESULT_SUCCESS;
}
Expand Down Expand Up @@ -640,12 +642,33 @@ sa_status sa_invoke(Sec_ProcessorHandle* processorHandle, SA_COMMAND_ID command_
if (processorHandle == NULL)
return SA_STATUS_INVALID_PARAMETER;

// Validate processorHandle is still in the global list before locking
pthread_mutex_lock(&mutex);
Sec_ProcessorHandle* tempHandle = processorHandleList;
bool handle_found = false;
while (tempHandle != NULL) {
if (tempHandle == processorHandle) {
handle_found = true;
break;
}
tempHandle = tempHandle->nextHandle;
}
Comment thread
riwoh marked this conversation as resolved.

if (!handle_found) {
pthread_mutex_unlock(&mutex);
SEC_LOG_ERROR("Use after processor handle free detected %u", command_id);
return SA_STATUS_INVALID_PARAMETER;
}
Comment thread
riwoh marked this conversation as resolved.

// Now safely lock the processor mutex while still holding global mutex
Comment thread
riwoh marked this conversation as resolved.
pthread_mutex_lock(&processorHandle->mutex);
pthread_mutex_unlock(&mutex);

va_list va_args;
va_start(va_args, command_id);
sa_command command = {command_id, &va_args, -1};

bool command_queued = false;
pthread_mutex_lock(&processorHandle->mutex);
while (!processorHandle->shutdown && command.result == -1) {
if (processorHandle->queue_size < MAX_QUEUE_SIZE && !command_queued) {
processorHandle->queue[(processorHandle->queue_front + processorHandle->queue_size) % MAX_QUEUE_SIZE] =
Expand Down
26 changes: 26 additions & 0 deletions test/main/cpp/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,29 @@ Sec_Result testProcessorInitReleaseInit() {

return SEC_RESULT_SUCCESS;
}

Sec_Result testProcessorUseAfterFree() {
Sec_ProcessorHandle* proc = nullptr;
if (SecProcessor_GetInstance_Directories(&proc, nullptr, nullptr) != SEC_RESULT_SUCCESS) {
SEC_LOG_ERROR("SecProcessor_GetInstance_Directories failed");
return SEC_RESULT_FAILURE;
}

// Save the handle pointer before releasing
Sec_ProcessorHandle* dangling = proc;

if (SecProcessor_Release(proc) != SEC_RESULT_SUCCESS) {
SEC_LOG_ERROR("SecProcessor_Release failed");
return SEC_RESULT_FAILURE;
}

// Attempt to use the freed handle - sa_invoke should detect this and return failure
Sec_Result result = SecKey_Generate(dangling, SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128,
SEC_STORAGELOC_RAM);
if (result == SEC_RESULT_SUCCESS) {
SEC_LOG_ERROR("SecKey_Generate should have failed on a freed handle");
return SEC_RESULT_FAILURE;
Comment on lines +151 to +156
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This unit test will pass even if SecKey_Generate fails for unrelated reasons (e.g., unsupported SA backend), because it only asserts that generation fails after release. To make the test actually validate the regression, consider first calling SecKey_Generate(proc, ...) (or another sa_invoke-based operation) and asserting it succeeds before releasing, then repeat the call with the dangling pointer and assert it fails.

Copilot uses AI. Check for mistakes.
}

return SEC_RESULT_SUCCESS;
}
2 changes: 2 additions & 0 deletions test/main/cpp/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ Sec_Result testProcessorGetInfo();

Sec_Result testProcessorInitReleaseInit();

Sec_Result testProcessorUseAfterFree();

#endif // PROCESSOR_H
1 change: 1 addition & 0 deletions test/main/cpp/sec_api_utest_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void runProcessorTests(SuiteCtx* suite) {
RUN_TEST(suite, testProcessorGetKeyLadderMinMaxDepth(SEC_KEYLADDERROOT_SHARED))
RUN_TEST(suite, testProcessorNativeMallocFree())
RUN_TEST(suite, testProcessorInitReleaseInit())
RUN_TEST(suite, testProcessorUseAfterFree())
}

void runBundleTests(SuiteCtx* suite) {
Expand Down
Loading