Coding for renewable security
Support for renewable security is one of the seven properties of highly secured devices. In Azure Sphere, it means that all of the software on the device—including your own applications—can be updated as needed to address newly discovered vulnerabilities. Security is the reason Azure Sphere exists, and it cannot be stressed too often that keeping your device secure at all times is paramount. It is not possible to write completely secure code, but with good coding practices, extreme diligence in responding to newly discovered vulnerabilities, and a commitment to renewable security, you can ensure your high-level application code is as secure as possible. The Azure Sphere application isolation model provides a number of features to ensure this:
- All apps must be signed appropriately before they can be installed or run.
- Only those hardware capabilities and internet addresses that have been specified in the application's app manifest file can be accessed by the application.
- The APIs provided by the Azure Sphere SDK include a much-reduced subset of the standard C library, omitting potential security holes such as user accounts and shell access.
- The Azure Sphere OS and customer applications can be updated securely using the Azure Sphere Security Service as security concerns are identified and addressed.
However, code signing and attack surface minimization take you only so far. Following a set of best practices for secure software development can help ensure that the applications you sign are as safe and secure as possible. This article describes some of the tools the Azure Sphere team uses in its own development practices.
Schedule regular deployments
The Azure Sphere OS and the Azure Sphere SDK are updated at least quarterly. You should aim for a similar schedule for deployments of your own applications.
Ensure that your toolchain remains up-to-date
The Azure Sphere OS and SDK form a large part of the Azure Sphere toolchain, but you may have other components that you manage separately. Be sure to check regularly for updates for these components.
Common vulnerabilities and exposures (CVEs) are public reports that are used to describe a security vulnerability in a system, including in Azure Sphere. Azure Sphere OS updates regularly address CVEs and help keep your devices secure. If possible, include checks for CVEs in your build pipelines. Bookmark sites such as the CISA homepage that track security updates. Rebuild and redeploy your applications as you update your toolchain.
Propagate and adhere to coding standards
Code that adheres to a known standard is easier to maintain, easier to review, and easier to test. There are publicly available coding standards for C. MISRA is well-established and CERT also has a coding standard for C. In addition to these basic standards, we recommend the use of the Security Development Lifecycle wherever possible.
Ensure that you are compiling with essential security flags
All Azure Sphere apps are built with C language compilers from the Gnu Compiler Collection (GCC). The C compiler, gcc, provides hundreds of compiler and linker flags. In Azure Sphere, the following flags are used by default:
-fstack-protector-strong
: generates code to protect against stack smashing attacks.pie
: generates position-independent executables.fPIC
: generates position-independent code.
The -fstack-protector-all
flag provides more protection than -fstack-protector-strong
, but increases the memory stack usage. Because of the limited memory on current Azure Sphere hardware, -fstack-protector-all
is not used by default.
Azure Sphere also uses a number of warning flags—these can be used to identify problems with your code during compilation that can be fixed before deployment:
-Wall -Wswitch -Wempty-body -Wconversion -Wreturn-type -Wparentheses -Wno-format -Wuninitialized -Wunreachable-code -Wunused-function -Wunused-value -Wunused-variable -Wstrict-prototypes -Wno-pointer-sign -Werror=implicit-function-declaration
For more security, -Wl,-z,now
or -Wl,-z,relro
could be added, but again, these are not used by default because they cause extra memory usage.
Review all code
Code reviews are a simple but effective tool in ensuring high-quality code. We recommend that no code be checked in without a code review from a qualified reviewer. One-on-one code reviews, in which a developer walks through the new code with another developer, often help the original developer clarify the thought that went into producing the code. This can reveal design weaknesses or missed branch points even with no input from the reviewing developer.
Use automated tests
Automated test frameworks such as gtest enable you to run suites of test functions every time a project is built. A best practice is to ensure that all checked-in code be accompanied by at least one test function; more is usually better. Important types of testing include the following:
- Basic unit testing runs each piece of code to verify it is working as designed. Test cases should be designed that test the code at the edges; corner-cases and edge cases are usually a fruitful source of bugs.
- Fuzz testing exercises code by providing unexpected input of various types to ensure the function responds appropriately.
- Penetration testing is useful for identifying vulnerabilities that allow attackers to penetrate the application.
Use static code analyzers
Static code analyzers can help find a number of common code problems. Most focus on specific types of errors. The following free and open-source tools are among those used by the Azure Sphere development team and some Azure Sphere users:
- clang-tidy
- AddressSanitizer (ASan)
- MemorySanitizer (MSan)
- UndefinedBehaviorSanitizer (UBSan)
- Valgrind
Running some of these tools may require recompiling your application (or portions of it) for a different target operating system.
Remove unneeded code
The Azure Sphere SDK provides a stripped-down version of the standard C development libraries; wherever possible, you should look for opportunities to strip your own code to its bare essentials. The fewer lines of code, the smaller attack surface is available to potential threats. Warnings about unreachable or unused code can be used to identify unneeded code.