Skip to content

Commit 6b7d4cf

Browse files
authored
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 ); ```
1 parent 9bfd85a commit 6b7d4cf

File tree

56 files changed

+3645
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3645
-237
lines changed

include/FreeRTOS.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
#define configUSE_MPU_WRAPPERS_V1 0
8787
#endif
8888

89+
/* Set configENABLE_ACCESS_CONTROL_LIST to 1 to enable access control list support. */
90+
#ifndef configENABLE_ACCESS_CONTROL_LIST
91+
#define configENABLE_ACCESS_CONTROL_LIST 0
92+
#endif
93+
8994
/* Basic FreeRTOS definitions. */
9095
#include "projdefs.h"
9196

include/mpu_wrappers.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,35 @@
233233
#define PRIVILEGED_DATA __attribute__( ( section( "privileged_data" ) ) )
234234
#define FREERTOS_SYSTEM_CALL
235235

236+
237+
#if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
238+
239+
#define vGrantAccessToTask( xTask, xTaskToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToGrantAccess ) )
240+
#define vRevokeAccessToTask( xTask, xTaskToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToRevokeAccess ) )
241+
242+
#define vGrantAccessToSemaphore( xTask, xSemaphoreToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xSemaphoreToGrantAccess ) )
243+
#define vRevokeAccessToSemaphore( xTask, xSemaphoreToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xSemaphoreToRevokeAccess ) )
244+
245+
#define vGrantAccessToQueue( xTask, xQueueToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueToGrantAccess ) )
246+
#define vRevokeAccessToQueue( xTask, xQueueToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueToRevokeAccess ) )
247+
248+
#define vGrantAccessToQueueSet( xTask, xQueueSetToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueSetToGrantAccess ) )
249+
#define vRevokeAccessToQueueSet( xTask, xQueueSetToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xQueueSetToRevokeAccess ) )
250+
251+
#define vGrantAccessToEventGroup( xTask, xEventGroupToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xEventGroupToGrantAccess ) )
252+
#define vRevokeAccessToEventGroup( xTask, xEventGroupToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xEventGroupToRevokeAccess ) )
253+
254+
#define vGrantAccessToStreamBuffer( xTask, xStreamBufferToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xStreamBufferToGrantAccess ) )
255+
#define vRevokeAccessToStreamBuffer( xTask, xStreamBufferToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xStreamBufferToRevokeAccess ) )
256+
257+
#define vGrantAccessToMessageBuffer( xTask, xMessageBufferToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xMessageBufferToGrantAccess ) )
258+
#define vRevokeAccessToMessageBuffer( xTask, xMessageBufferToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xMessageBufferToRevokeAccess ) )
259+
260+
#define vGrantAccessToTimer( xTask, xTimerToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xTimerToGrantAccess ) )
261+
#define vRevokeAccessToTimer( xTask, xTimerToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xTimerToRevokeAccess ) )
262+
263+
#endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
264+
236265
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
237266

238267
/* Ensure API functions go in the privileged execution section. */

include/portable.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,21 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
247247
uint32_t ulAccessRequested ) PRIVILEGED_FUNCTION;
248248
#endif
249249

250+
/**
251+
* @brief Checks if the calling task is authorized to access the given kernel object.
252+
*
253+
* @param lInternalIndexOfKernelObject The index of the kernel object in the kernel
254+
* object handle pool.
255+
*
256+
* @return pdTRUE if the calling task is authorized to access the kernel object,
257+
* pdFALSE otherwise.
258+
*/
259+
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
260+
261+
BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;
262+
263+
#endif
264+
250265
/* *INDENT-OFF* */
251266
#ifdef __cplusplus
252267
}

include/task.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,6 +3206,27 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
32063206

32073207
#endif /* portUSING_MPU_WRAPPERS */
32083208

3209+
3210+
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
3211+
3212+
/*
3213+
* For internal use only. Grant/Revoke a task's access to a kernel object.
3214+
*/
3215+
void vGrantAccessToKernelObject( TaskHandle_t xExternalTaskHandle,
3216+
int32_t lExternalKernelObjectHandle ) PRIVILEGED_FUNCTION;
3217+
void vRevokeAccessToKernelObject( TaskHandle_t xExternalTaskHandle,
3218+
int32_t lExternalKernelObjectHandle ) PRIVILEGED_FUNCTION;
3219+
3220+
/*
3221+
* For internal use only. Grant/Revoke a task's access to a kernel object.
3222+
*/
3223+
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
3224+
int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;
3225+
void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
3226+
int32_t lInternalIndexOfKernelObject ) PRIVILEGED_FUNCTION;
3227+
3228+
#endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
3229+
32093230
/* *INDENT-OFF* */
32103231
#ifdef __cplusplus
32113232
}

portable/ARMv8M/non_secure/port.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
472472
#endif /* configENABLE_MPU == 1 */
473473
/*-----------------------------------------------------------*/
474474

475+
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
476+
477+
/**
478+
* @brief This variable is set to pdTRUE when the scheduler is started.
479+
*/
480+
PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE;
481+
482+
#endif
483+
475484
/**
476485
* @brief Each task maintains its own interrupt status in the critical nesting
477486
* variable.
@@ -1651,6 +1660,12 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
16511660
/* Initialize the critical nesting count ready for the first task. */
16521661
ulCriticalNesting = 0;
16531662

1663+
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
1664+
{
1665+
xSchedulerRunning = pdTRUE;
1666+
}
1667+
#endif
1668+
16541669
/* Start the first task. */
16551670
vStartFirstTask();
16561671

@@ -1931,3 +1946,98 @@ BaseType_t xPortIsInsideInterrupt( void )
19311946

19321947
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) */
19331948
/*-----------------------------------------------------------*/
1949+
1950+
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
1951+
1952+
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
1953+
int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1954+
{
1955+
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1956+
xMPU_SETTINGS * xTaskMpuSettings;
1957+
1958+
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
1959+
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
1960+
1961+
xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
1962+
1963+
xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit );
1964+
}
1965+
1966+
#endif /* #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
1967+
/*-----------------------------------------------------------*/
1968+
1969+
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
1970+
1971+
void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
1972+
int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1973+
{
1974+
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1975+
xMPU_SETTINGS * xTaskMpuSettings;
1976+
1977+
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
1978+
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
1979+
1980+
xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
1981+
1982+
xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit );
1983+
}
1984+
1985+
#endif /* #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
1986+
/*-----------------------------------------------------------*/
1987+
1988+
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
1989+
1990+
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
1991+
1992+
BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1993+
{
1994+
uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1995+
BaseType_t xAccessGranted = pdFALSE;
1996+
const xMPU_SETTINGS * xTaskMpuSettings;
1997+
1998+
if( xSchedulerRunning == pdFALSE )
1999+
{
2000+
/* Grant access to all the kernel objects before the scheduler
2001+
* is started. It is necessary because there is no task running
2002+
* yet and therefore, we cannot use the permissions of any
2003+
* task. */
2004+
xAccessGranted = pdTRUE;
2005+
}
2006+
else
2007+
{
2008+
xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
2009+
2010+
ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
2011+
ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
2012+
2013+
if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
2014+
{
2015+
xAccessGranted = pdTRUE;
2016+
}
2017+
else
2018+
{
2019+
if( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] & ( 1U << ulAccessControlListEntryBit ) ) != 0 )
2020+
{
2021+
xAccessGranted = pdTRUE;
2022+
}
2023+
}
2024+
}
2025+
2026+
return xAccessGranted;
2027+
}
2028+
2029+
#else /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
2030+
2031+
BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
2032+
{
2033+
( void ) lInternalIndexOfKernelObject;
2034+
2035+
/* If Access Control List feature is not used, all the tasks have
2036+
* access to all the kernel objects. */
2037+
return pdTRUE;
2038+
}
2039+
2040+
#endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
2041+
2042+
#endif /* #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) */
2043+
/*-----------------------------------------------------------*/

portable/ARMv8M/non_secure/portmacrocommon.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
287287
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
288288
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )
289289

290+
/* Size of an Access Control List (ACL) entry in bits. */
291+
#define portACL_ENTRY_SIZE_BITS ( 32U )
292+
290293
typedef struct MPU_SETTINGS
291294
{
292295
uint32_t ulMAIR0; /**< MAIR0 for the task containing attributes for all the 4 per task regions. */
@@ -296,6 +299,9 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
296299

297300
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
298301
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
302+
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
303+
uint32_t ulAccessControlList[ ( configPROTECTED_KERNEL_OBJECT_POOL_SIZE / portACL_ENTRY_SIZE_BITS ) + 1 ];
304+
#endif
299305
#endif
300306
} xMPU_SETTINGS;
301307

portable/Common/mpu_wrappers.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050

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

53+
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
54+
#error Access control list is not available with this MPU wrapper. Please set configENABLE_ACCESS_CONTROL_LIST to 0.
55+
#endif
56+
5357
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
5458
BaseType_t MPU_xTaskCreate( TaskFunction_t pvTaskCode,
5559
const char * const pcName,

0 commit comments

Comments
 (0)