Enforcing MISRA using GCC
GCC and CLANG go a long way to make your cybersecurity product MISRA compliant. In this blog post we share our path towards our Guideline Enforcement Plan. Interested parties can find the MISRA Guideline Enforcement Plan for Kinibi at the end of this post. As part of MISRA Compliance, Trustonic provides this document on its website, as part of an on-going quality initiative.
Introduction
GCC and CLANG are common tools used to develop cost-efficient Trusted Execution Environments [TEE]. To use TEEs in automotive and safety-critical environments, MISRA-compliance is a strong and sensible requirement. Following the MISRA Coding Standard helps to overcome programming issues that can occur when using the C language without safety net. In this blog post we will take you on our journey towards MISRA Compliance for the upcoming Kinibi-520A. While being a considerable effort, you will see that it was not as difficult as one might think.
While enormously popular and versatile, the C programming language has several drawbacks that can lead to safety and security issues in the final program. The C language allows many ways to solve a problem and the C code alone, is not enough to know what the final program will really do. The missing piece is in the compiler settings and as TEE developers for ARM TrustZone, we know these settings by heart.
MISRA addresses the following problems with C:
- Code that depends on Compiler settings:
- MISRA requires you to use compiler-setting independent code, for example using
uin32_t
, addingU
to unsigned constants. - This is called language sub-setting, MISRA-C:2012 is a C language where you have less ways to solve a problem.
- MISRA requires you to use compiler-setting independent code, for example using
- Code that can easily lead to confusion:
- Duplicated identifiers for different things, unused functions and parameters
- Missing braces and relying on operator precedence
- Code that abuses the freedom of C:
- Float variable as a counter in
for(;;)
statements, wildgotos
, malformedswitch
–case
statements, octal constants.
- Float variable as a counter in
- Code that can cause problems on poor compilers.
Kinibi
MISRA-C:2012 defines 157 rules to address these issues. When examining the individual rules lately, I realized that we would address many of them easily in Kinibi:
- Section 21 and 22 handle the C standard-library, like stdlib.h:
- Since Kinibi is an OS, we run on bare-metal and avoid standard libraries
- Consequently, the checkers for using the problematic functions will not find regressions.
- Kinibi itself does not provide the C standard library to Trusted Applications (TAs)
- Instead, Kinibi provides the GlobalPlatform TEE Internal Core API to TAs.
- This standardized API avoids some of the shortcomings of the C standard library and has a reduced feature set.
- Regarding #4, rules for poor compilers: Kinibi always uses the latest GCC and CLANG compilers which have huge user bases that ensure that problems will be found quickly and fixed in the stable version.
- Regarding #3, rules that abuse the freedom of C: most of our developers are not masterminds of C and avoid such constructs naturally.
- Regarding #2, rules that can lead to confusion: We use coding standards that are enforced by astyle (“Artistic Style”) to enforce braces in if() statement bodies (Rule 15.6). Moreover, we use GCC (“GNU C Compiler”) and CLANG (“C LANGuage compiler of LLVM project”) with a high number of warnings activated to detect unused items and non-unique definitions.
- Regarding #1, rules that depend on compiler settings – We already use many of the MISRA recommendations:
uint32_t
from C99, activate compiler warnings, use a static analyzer.
When we started to mature our software couple of years ago, we took many steps to improve the robustness of Kinibi and its applications:
- Kinibi-302: we made sure to fix all the default warnings of the compiler
- Kinibi-310: we activated
-Werror
to fail the build on compiler warnings, together with-Wno-error=
or#pragma
s to deviate certain warnings where necessary - Kinibi-400: we added
-Wall
- Kinibi-400b: we added
-fstack-protector-strong
- Kinibi-410: we added
-Wextra
, fixing all the code where necessary. - Kinibi-500: we switched to a 64-bit TEE and added initial support for Clang, which meant fixing additional default warnings.
- Kinibi-510a: we added
-fsanitize=shadow-call-stack
and a heap of non-default warnings from GCC, like-Wshadow
,-Wcast-qual
,-Wwrite-strings
,-Wstrict-prototypes
,-Wmissing-prototypes
,-Wpointer-arith
. - Kinibi-520: we target Clang-9
-Weverything
with only 3-Wno=
deviations
These changes improve the code quality, but also protect the runtime of applications, as in the form of stack canaries. While protecting that way our own TEE components, these protections are also exported in the Kinibi SDK and protect the Trusted Applications of our customers.
Many of these warnings are linked to evolution of the C language. The initial C version was quite simple and only later versions added type-safety features. By default, the compiler will not check that a developer uses these features correctly. Enabling the respective compiler warnings ensures that code that a developer wants to compile respects the type safety that later C versions allow.
Example
For example, the following code is valid C:
char *world = "Hello World";
However, only a junior programmer would write code like that: The string literal in C ("Hello World"
) is usually read-only memory. Let us assume the programmer would go on to write:
world[1] = 'a';
This would lead to the program crashing with a segmentation fault trying to write to read-only memory.
Such a program should not pass the code review, where senior engineers would advise to change the code. For example, the string should be copied to modifiable memory first.
However, code review is an expensive and not always reliable safety net. Compiler warnings are a way to bring best practices and feedback closer to the time of code development.
In this example, the warning -Wwrite-strings
will warn you that the variable world should be a const
variable. The resulting code would look like that:
const char *world = "Hello World";
Now, when the developer goes on to modify “Hello World”
to “Hallo World”
, the compiler will throw another warning saying that a const
variable cannot be modified:
world[1] = 'a';
^ warning: Writing to const-variable 'world' is forbidden.
Normally, at this point, we expect that the developer will realize that he should create a copy of the string into writeable memory. But hey, let us assume for a moment the developer tries to be clever and knows about casts. With casts you can disable the type-safety system in C. While casting is required in some places, it can also be abused. Special warnings exist to explicitly disable certain casts. Coming back to the example, our junior developer would write something like this to disable the warning:
char * worldmut = (char *)world;
worldmut[1] = 'a'
;
To prevent such unexpected behavior, we add the warning -Wcast-qual
to warn when a qualifier (“const
”) is removed during a cast.
All these compiler warnings are good game and will enforce to write only secure and safe code going forward. However, the compiler is far from enough to detect more high-level code issues and that is why we use static code analyzer software as well. Our code is clean of any relevant findings found by Coverity since Kinibi-300 series. Naturally, going forward with MISRA, we also rely on and work with Coverity MISRA Analysis to identify places in the code that need attention.
To summarize, we use warnings developed in GCC project and warnings developed in CLANG project to enforce discipline among developers. Before merging back to the mainline, the developer must also pass the MISRA Analysis from Coverity over his branch to proof that he did not add new violations. Such check can also be done locally at the developer’s workstation to better analyze and fix the problem. This brings us to the MISRA Guideline Enforcement Plan as required by MISRA Compliance 2020.
MISRA Guideline Enforcement Plan
For starters, the Kinibi project in Trustonic uses Coverity and hence we use its MISRA checkers which can be found on the Synopsys website.
The following table is an exert of the full mapping of GCC and CLANG compiler warnings to the relevant MISRA guideline.