Skip to content

Commit

Permalink
Add Access Control List to MPU ports (#765)
Browse files Browse the repository at this point in the history
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
#define configUSE_MPU_WRAPPERS_V1 0
#define configENABLE_ACCESS_CONTROL_LIST 1
```

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 );

```
  • Loading branch information
kar-rahul-aws authored Sep 18, 2023
1 parent 7db0e87 commit 170a291
Show file tree
Hide file tree
Showing 56 changed files with 2,952 additions and 219 deletions.
5 changes: 5 additions & 0 deletions include/FreeRTOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@
#define configUSE_MPU_WRAPPERS_V1 0
#endif

/* Set configENABLE_ACCESS_CONTROL_LIST to 1 to enable access control list support. */
#ifndef configENABLE_ACCESS_CONTROL_LIST
#define configENABLE_ACCESS_CONTROL_LIST 0
#endif

/* Set default value of configNUMBER_OF_CORES to 1 to use single core FreeRTOS. */
#ifndef configNUMBER_OF_CORES
#define configNUMBER_OF_CORES 1
Expand Down
29 changes: 29 additions & 0 deletions include/mpu_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,35 @@
#define PRIVILEGED_DATA __attribute__( ( section( "privileged_data" ) ) )
#define FREERTOS_SYSTEM_CALL


#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )

#define vGrantAccessToTask( xTask, xTaskToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToGrantAccess ) )
#define vRevokeAccessToTask( xTask, xTaskToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToRevokeAccess ) )

#define vGrantAccessToSemaphore( xTask, xSemaphoreToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xSemaphoreToGrantAccess ) )
#define vRevokeAccessToSemaphore( xTask, xSemaphoreToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xSemaphoreToRevokeAccess ) )

#define vGrantAccessToQueue( xTask, xQueueToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueToGrantAccess ) )
#define vRevokeAccessToQueue( xTask, xQueueToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueToRevokeAccess ) )

#define vGrantAccessToQueueSet( xTask, xQueueSetToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueSetToGrantAccess ) )
#define vRevokeAccessToQueueSet( xTask, xQueueSetToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueSetToRevokeAccess ) )

#define vGrantAccessToEventGroup( xTask, xEventGroupToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xEventGroupToGrantAccess ) )
#define vRevokeAccessToEventGroup( xTask, xEventGroupToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xEventGroupToRevokeAccess ) )

#define vGrantAccessToStreamBuffer( xTask, xStreamBufferToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xStreamBufferToGrantAccess ) )
#define vRevokeAccessToStreamBuffer( xTask, xStreamBufferToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xStreamBufferToRevokeAccess ) )

#define vGrantAccessToMessageBuffer( xTask, xMessageBufferToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xMessageBufferToGrantAccess ) )
#define vRevokeAccessToMessageBuffer( xTask, xMessageBufferToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xMessageBufferToRevokeAccess ) )

#define vGrantAccessToTimer( xTask, xTimerToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xTimerToGrantAccess ) )
#define vRevokeAccessToTimer( xTask, xTimerToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xTimerToRevokeAccess ) )

#endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */

#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */

/* Ensure API functions go in the privileged execution section. */
Expand Down
15 changes: 15 additions & 0 deletions include/portable.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,21 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
uint32_t ulAccessRequested ) PRIVILEGED_FUNCTION;
#endif

/**
* @brief Checks if the calling task is authorized to access the given kernel object.
*
* @param lInternalIndexOfKernelObject The index of the kernel object in the kernel
* object handle pool.
*
* @return pdTRUE if the calling task is authorized to access the kernel object,
* pdFALSE otherwise.
*/
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )

BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;

#endif

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
21 changes: 21 additions & 0 deletions include/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -3469,6 +3469,27 @@ void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );

#endif /* portUSING_MPU_WRAPPERS */


#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )

/*
* For internal use only. Grant/Revoke a task's access to a kernel object.
*/
void vGrantAccessToKernelObject( TaskHandle_t xExternalTaskHandle,
int32_t lExternalKernelObjectHandle ) PRIVILEGED_FUNCTION;
void vRevokeAccessToKernelObject( TaskHandle_t xExternalTaskHandle,
int32_t lExternalKernelObjectHandle ) PRIVILEGED_FUNCTION;

/*
* For internal use only. Grant/Revoke a task's access to a kernel object.
*/
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;
void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;

#endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
82 changes: 82 additions & 0 deletions portable/ARMv8M/non_secure/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -2019,3 +2019,85 @@ BaseType_t xPortIsInsideInterrupt( void )

#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
/*-----------------------------------------------------------*/

#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 = 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 ) */
/*-----------------------------------------------------------*/
7 changes: 7 additions & 0 deletions portable/ARMv8M/non_secure/portmacrocommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )

/* Size of an Access Control List (ACL) entry in bits and bytes. */
#define portACL_ENTRY_SIZE_BYTES ( 4U )
#define portACL_ENTRY_SIZE_BITS ( 32U )

typedef struct MPU_SETTINGS
{
uint32_t ulMAIR0; /**< MAIR0 for the task containing attributes for all the 4 per task regions. */
Expand All @@ -296,6 +300,9 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P

#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_BYTES ) + 1 ];
#endif
#endif
} xMPU_SETTINGS;

Expand Down
4 changes: 4 additions & 0 deletions portable/Common/mpu_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@

#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) )

#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
#error Access control list is not available with this MPU wrapper. Please set configENABLE_ACCESS_CONTROL_LIST to 0.
#endif

#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t MPU_xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
Expand Down
Loading

0 comments on commit 170a291

Please sign in to comment.