Add Access Control List to MPU ports (#897)

This PR adds Access Control to kernel objects on a per task basis to MPU
ports. The following needs to be defined in the `FreeRTOSConfig.h` to
enable this feature:

```c
```

This PR adds the following new APIs:

```c
void vGrantAccessToTask( TaskHandle_t xTask,
                         TaskHandle_t xTaskToGrantAccess );
void vRevokeAccessToTask( TaskHandle_t xTask,
                          TaskHandle_t xTaskToRevokeAccess );

void vGrantAccessToSemaphore( TaskHandle_t xTask,
                              SemaphoreHandle_t xSemaphoreToGrantAccess );
void vRevokeAccessToSemaphore( TaskHandle_t xTask,
                               SemaphoreHandle_t xSemaphoreToRevokeAccess );

void vGrantAccessToQueue( TaskHandle_t xTask,
                          QueueHandle_t xQueueToGrantAccess );
void vRevokeAccessToQueue( TaskHandle_t xTask,
                           QueueHandle_t xQueueToRevokeAccess );

void vGrantAccessToQueueSet( TaskHandle_t xTask,
                             QueueSetHandle_t xQueueSetToGrantAccess );
void vRevokeAccessToQueueSet( TaskHandle_t xTask,
                              QueueSetHandle_t xQueueSetToRevokeAccess );

void vGrantAccessToEventGroup( TaskHandle_t xTask,
                               EventGroupHandle_t xEventGroupToGrantAccess );
void vRevokeAccessToEventGroup( TaskHandle_t xTask,
                                EventGroupHandle_t xEventGroupToRevokeAccess );

void vGrantAccessToStreamBuffer( TaskHandle_t xTask,
                                 StreamBufferHandle_t xStreamBufferToGrantAccess );
void vRevokeAccessToStreamBuffer( TaskHandle_t xTask,
                                  StreamBufferHandle_t xStreamBufferToRevokeAccess );

void vGrantAccessToMessageBuffer( TaskHandle_t xTask,
                                  MessageBufferHandle_t xMessageBufferToGrantAccess );
void vRevokeAccessToMessageBuffer( TaskHandle_t xTask,
                                   MessageBufferHandle_t xMessageBufferToRevokeAccess );

void vGrantAccessToTimer( TaskHandle_t xTask,
                          TimerHandle_t xTimerToGrantAccess );
void vRevokeAccessToTimer( TaskHandle_t xTask,
                           TimerHandle_t xTimerToRevokeAccess );
```

An unprivileged task by default has access to itself only and no other
kernel object. The application writer needs to explicitly grant an
unprivileged task access to all the kernel objects it needs. The best
place to do that is before starting the scheduler when all the kernel
objects are created.

For example, let's say an unprivileged tasks needs access to a queue and
an event group, the application writer needs to do the following:

```c
vGrantAccessToQueue( xUnprivilegedTaskHandle, xQueue );
vGrantAccessToEventGroup( xUnprivilegedTaskHandle, xEventGroup );
```

The application writer MUST revoke all the accesses before deleting a
task. Failing to do so will result in undefined behavior. In the above
example, the application writer needs to make the following 2 calls
before deleting the task:

```c
vRevokeAccessToQueue( xUnprivilegedTaskHandle, xQueue );
vRevokeAccessToEventGroup( xUnprivilegedTaskHandle, xEventGroup );

```
This commit is contained in:
Gaurav-Aggarwal-AWS 2023-11-23 10:45:58 +05:30 committed by GitHub
parent 9bfd85a253
commit 6b7d4cf41b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 3645 additions and 237 deletions

View file

@ -252,6 +252,15 @@ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
* switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
/*
* This variable is set to pdTRUE when the scheduler is started.
*/
PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE;
#endif
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
@ -824,6 +833,12 @@ BaseType_t xPortStartScheduler( void )
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
{
xSchedulerRunning = pdTRUE;
}
#endif
/* Start the first task. */
__asm volatile
(
@ -1367,3 +1382,98 @@ BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer,
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
{
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
xMPU_SETTINGS * xTaskMpuSettings;
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit );
}
#endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
/*-----------------------------------------------------------*/
#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
{
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
xMPU_SETTINGS * xTaskMpuSettings;
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit );
}
#endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
/*-----------------------------------------------------------*/
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
{
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
BaseType_t xAccessGranted = pdFALSE;
const xMPU_SETTINGS * xTaskMpuSettings;
if( xSchedulerRunning == pdFALSE )
{
/* Grant access to all the kernel objects before the scheduler
* is started. It is necessary because there is no task running
* yet and therefore, we cannot use the permissions of any
* task. */
xAccessGranted = pdTRUE;
}
else
{
xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
{
xAccessGranted = pdTRUE;
}
else
{
if( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] & ( 1U << ulAccessControlListEntryBit ) ) != 0 )
{
xAccessGranted = pdTRUE;
}
}
}
return xAccessGranted;
}
#else /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
{
( void ) lInternalIndexOfKernelObject;
/* If Access Control List feature is not used, all the tasks have
* access to all the kernel objects. */
return pdTRUE;
}
#endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/

View file

@ -127,7 +127,10 @@
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#define MAX_CONTEXT_SIZE 20
#define MAX_CONTEXT_SIZE ( 20 )
/* Size of an Access Control List (ACL) entry in bits. */
#define portACL_ENTRY_SIZE_BITS ( 32U )
/* Flags used for xMPU_SETTINGS.ulTaskFlags member. */
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
@ -140,10 +143,13 @@
uint32_t ulContext[ MAX_CONTEXT_SIZE ];
uint32_t ulTaskFlags;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
uint32_t ulAccessControlList[ ( configPROTECTED_KERNEL_OBJECT_POOL_SIZE / portACL_ENTRY_SIZE_BITS ) + 1 ];
#endif
} xMPU_SETTINGS;
#endif
} xMPU_SETTINGS;
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )