AWE Core Integration Cybersecurity Recommendations
Purpose
This document is intended to provide recommendations to AWE Core library integrators to minimize the level of cybersecurity risk in a production application. The recommendations here are best practices to ensure that the interfaces with the AWE Core are protected, but the final cybersecurity responsibility lies with the integrator.
Scope
The AWE Core is a portable audio processing engine developed out-of-context. Since it can be integrated into a wide variety of systems, its final operating environment cannot be known in advance.
Because that environment is unknown, this guide treats every AWE Core interface as fully exposed to attack. This worst-case stance is deliberate, since it lets the guide cover as many potential vulnerabilities as possible, and a given system may already mitigate many of them.
The impact of an attack, by contrast, depends on the specific product, so each concern should be weighed against the integrator's own system. For example:
- corrupting or suppressing output audio is more serious in a product that plays safety chimes
- audio confidentiality matters more when the product supports telephony or other potentially sensitive audio
- code execution threats are more serious where the AWE Core shares hardware with higher trust or safety critical components than where the audio subsystem is well isolated
The boundary between what these recommendations treat as the AWE Core's responsibility and what is the integrator's responsibility is shown below. This particular diagram assumes an automotive context, multiple AWE Instances, and an isolated Infotainment system separate from safety critical components.

*Figure 1. AWE Core boundary diagram. The dashed boundary encloses the AWE Core instance(s). Every interface crossing it is the integrator's responsibility to protect. *
Recommendations
Tuning Interface
The tuning interface is implemented by the integrator and provides extensive control of the audio processing system. The communication protocol used for the tuning interface can be any method supported on the system, but the Audio Weaver tools directly support only TCP/IP, USB, SPI, and UART.
The tuning protocol itself provides no authentication, authorization, or encryption. The CRC included in each command is a transmission-integrity check, not a security control, and can be recomputed by any party. Consequently, and by design, anyone able to reach the tuning transport can issue any tuning command. These commands provide full control of the system (e.g., construct or destroy layouts and modules, set or read any module value, start or stop audio, and, when a flash filesystem is present, read, write, or delete files and erase flash). Depending on the system, this access could be used to steal intellectual property, cause denial of service (for example, by halting audio or erasing the stored layout), or corrupt or suppress output audio.
Because the tuning interface provides this level of control, it should be considered a privileged administrative interface. In production deployments, the tuning interface should be disabled unless a specific operational requirement exists. For example, TCP/IP-based tuning interfaces should not expose listening ports, and any unused tuning or diagnostic communication paths should be disabled. If tuning functionality is required in a production system for service, diagnostics, or field support purposes, access to the tuning interface should be restricted using appropriate security controls, such as certificate based authentication.
Note: The AWE Core library does validate the PFID_Set/GetValue commands in the same way as it validates the awe_ctrl* APIs, with the same limitations. See the Control APIs section for details.
Control APIs
The control APIs are used to access modules in the loaded layout, and require that the user pass in a module handle to the target object. The AWE Core validates the module handle and ensures that the writes or reads do not access memory outside the size of the target object (note that the AWE Core library can be built on request without the memory bounds checking performed - if unsure whether this is enabled in a given library, provide your DSPC contact with the library build number so they can verify it is built with -DENABLE_MEMORY_BOUNDS_CHECK).
In order to keep the APIs flexible and performant, no validation of the classId and no range checking on the values being applied to the module are performed. Depending on the integrator's system and goals, they may want to apply additional validation whenever using these APIs. For example, if any of the module handles or values used to set are generated by untrusted or unprotected applications or are from configuration files, then this additional validation can provide improved security.
Example code that wraps awe_ctrlSetValue to validate the classId and make sure no NaNs or +/-infs are included in the FLOAT32 array applied to the module is provided below.
#define E_INVALID_FLOAT (-1024) // arbitrary error code
#include <math.h>
INT32 validate_awe_ctrlSetValueFloat(AWEInstance * pAWE, UINT32 expectedModuleClassId, UINT32 moduleHandle, const FLOAT32 *value, INT32 arrayOffset, UINT32 length)
{
UINT32 classId;
INT32 ret;
ret = awe_ctrlGetModuleClass(pAWE, moduleHandle, &classId);
if (ret == E_SUCCESS)
{
/* Confirm the resolved object is the expected module class and that expectedModuleClassId is itself a valid module class ID. This wrapper is then safe even if called with a bad/untrusted expected class, and a handle resolving to a wire or layout can never pass */
if (classId >= 0xBEEF0800U && classId <= 0xBEEFFFFFU &&
classId == expectedModuleClassId)
{
UINT32 i;
for (i = 0; i < length; i++)
{
if (!isfinite(value[i]))
{
/* This simply aborts without writing, but integrator may want to log the event
or replace with a constant (e.g., 0.0f) */
return E_INVALID_FLOAT;
}
}
/* Inputs are validated, call the API */
ret = awe_ctrlSetValue(pAWE, moduleHandle, (const void *) value, arrayOffset, length);
}
else
{
ret = E_CLASS_NOT_SUPPORTED;
}
}
return ret;
}
For more sophisticated range checking, an .awc file, which contains range information for module arrays, can be generated in Designer and downstream tooling can generate appropriate range checking code.
Audio Input and Output
Audio enters and leaves the AWE Core through the import and export functions (awe_audioImportSamples and awe_audioExportSamples, or their AWECoreOS equivalents), which the integrator's audio driver calls to move samples between its buffers and the AWE Core's input and output pins. These functions perform channel matching and dataType conversion only. They do not validate or sanitize the audio content, and, like the control APIs, they trust the arguments they are given so the caller must pass valid channel and stride values and buffers large enough for fundamentalBlockSize samples.
Protecting the audio itself is largely outside the AWE Core boundary, because the audio exists in the wider system (codec, DMA buffers, inter-processor or network transport) before and after it passes through these functions. Securing that path is the integrator's responsibility. The relevant concerns are:
- Confidentiality: audio may carry sensitive content (for example, telephony audio), so an attacker able to read the audio buffers or tap the I/O path can eavesdrop.
- Integrity: an attacker able to modify the audio stream can corrupt or suppress output (for example, a safety chime), or inject audio into a downstream consumer such as a voice assistant.
Within a module, audio carried on wires should also be validated before use as appropriate. See the Module Writers section.
File System
AWB Files
A layout is delivered to the AWE Core as an AWB, supplied in one of three ways: compiled into the firmware as a C array (awe_loadAWBfromArray), read from a file on the application's filesystem (awe_loadAWBfromFile), or stored in the AWE Core flash file system (awe_loadAWBfromFlash).
Regardless of the source, the AWE Core does not authenticate the AWB before loading it. It simply parses and processes whatever tuning commands the AWB contains. Because the AWB defines the entire processing layout, an attacker who can modify or substitute it controls what the audio system does. Providing integrity and authenticity for the AWB is therefore the integrator's responsibility, and the delivery method can affect how easily that is achieved.
From a cybersecurity standpoint, compiling the AWB into the firmware as a C array is often the most straightforward option to secure. Because it becomes part of the firmware image, it can inherit whatever protection the firmware already has. With verified/secure boot and read-only storage, the AWB can gain integrity and authenticity with little additional work, and there is no separate runtime artifact to tamper with or replace. It also tends to have the smallest attack surface, since no external file is parsed and the flash file system is not required. The main tradeoff is functional rather than security related: updating the layout requires a firmware update. The right choice ultimately depends on the product's update needs and threat model.
The other two methods can be made secure, but that security is the integrator's to provide:
- AWB file on the application filesystem: store it on read-only media or a read-only filesystem, restrict access to it, and verify its integrity and authenticity (for example, a cryptographic signature checked by the application) before calling the load function, since the AWE Core will not.
- AWB in the AWE Core flash file system: the flash file system is written and erased through the unauthenticated tuning interface file commands, so the security of a stored AWB is tied to the security of the tuning interface (see the Flash File System and Tuning Interface sections).
Note on encryption: Designer can generate encrypted AWBs, which can be loaded by the AWE Core. However, AWB encryption is intended only for confidentiality, not security. Encryption does not detect or prevent tampering or substitution: a corrupted, malformed, or different encrypted AWB can still be loaded as long as it contains valid commands. For resistance to tampering or substitution, use integrity and authenticity measures such as signing and verified boot, not encryption.
Flash File System
Some targets will implement a Flash File System (see aweflashfsinstance_setup) in order to store data files, whether they are layouts, presets/tuning files, or audio files. The flash file system is read, written, and erased through the tuning interface file commands (PFID_OpenFile, PFID_ReadFile, PFID_WriteFile, PFID_DeleteFile, PFID_EraseFlash, and PFID_FileSystemReset). These commands are unauthenticated, so any party that can reach the tuning transport can read out stored files (for example, extracting layouts or audio data), overwrite or substitute them, or erase the flash entirely. The security of everything stored in the flash file system is therefore tied to the security of the tuning interface (see the Tuning Interface section).
If a flash file system is used in production:
- Restrict or disable the tuning interface, since it is the primary path for manipulating flash file system contents.
- Write-protect or lock the flash region once provisioning is complete, where the hardware allows it. This will of course cause the Write, Erase, and Delete PFIDs/APIs for the Flash File System to fail, and the files can not be updated in the field.
- AWE Core does not authenticate file content, and these files are typically read by AWE Core itself or by a module (for example, audio assets read by a playback module), not by the application, so there is usually no opportunity to check them at the point of use. Establish authenticity instead at provisioning time, when the integrator controls what is written, and preserve it afterward either by keeping the region immutable (as above) or by verifying the integrity of the flash region at boot (for example, a hash or signature over the partition, checked before AWE Core uses it).
Note that the Flash File System defines function callbacks to perform the read, write, and erase commands needed to control and use the flash memory. See the AWE Instance section for details on the protection of these callback function pointers.
Dynamic Module Packs
Modules are provided to the AWE Core in module pack libraries. These can be linked statically into the firmware, or, on platforms that support it, loaded dynamically at runtime as shared libraries (for example, a .so loaded through the AWE Plugin loader, which calls dlopen).
A module pack is native executable code: its Process, Set, and Constructor functions run in the audio process with the same privileges as the rest of the firmware. The AWE Core does not authenticate or integrity check a module pack before loading it. An attacker who can modify or substitute a module pack binary therefore gains arbitrary code execution in the audio process and, depending on how the system is integrated, potentially beyond it. Module pack integrity should be treated as seriously as firmware integrity.
As with AWB files, statically linking the module packs into the firmware image is generally the most straightforward to secure, since the code is then covered by the firmware's own protections and there is no separate artifact to tamper with. If dynamic loading is required:
- Store module pack binaries on read-only media or a read-only filesystem, and restrict access to them.
- Verify the integrity and authenticity of each binary (for example, a cryptographic signature or an OS code-signing or verified-boot mechanism) before loading, since the AWE Core will not.
- Load only from fixed, trusted locations, not from a path that can be influenced by untrusted input.
The AWE Plugin library, shipped with AWE Core, can optionally be used to load module packs stored as shared libraries on the target. The library exposes overridable function pointers for the loader's open, close, and symbol-resolution operations (by default dlopen/dlclose/dlsym, or LoadLibrary/FreeLibrary/GetProcAddress on Windows). Authenticity and integrity verification should be implemented in the open override and performed before the underlying dlopen/LoadLibrary is invoked (a shared library's constructor/init code runs during load, before any symbol lookup or entrypoint call). The override should reject a failed check by returning NULL. If using the AWE Plugin library, then the same considerations need to be applied to this component as discussed in the AWE Instance section, especially related to the callback function pointers.
Regardless of whether module packs are linked statically or loaded dynamically, the AWE Core locates each module class through the module table. This table is an array of pointers to the module class descriptors, referenced by the AWE Instance (pModuleDescriptorTable, populated by the application, often from ModuleList.h). Each descriptor holds the function pointers (Constructor, Process, Set) that the AWE Core calls to instantiate and run modules. Overwriting an entry in this table, or a function pointer within a descriptor, whether before or after awe_init, redirects those calls and can result in execution of an attacker's code. Because the table does not change after initialization, the strongest protection is to place it, and the descriptors it points to, in read-only memory, declared const so the build can locate it in ROM or write-protected flash where it cannot be modified at runtime. As with the AWE Instance, treat the module table as integrity critical (see the AWE Instance section).
See the reference code below for details on how this can be done. Declaring both the array and the descriptors it points to as const lets the build place them in read-only memory. The second const below is what makes the array of pointers itself immutable; the cast on assignment only satisfies the pModuleDescriptorTable member type and does not move the table out of read-only memory (the AWE Core only reads the table). The protection ultimately comes from that memory being genuinely non-writable on the target, such as ROM or write-protected flash, not from the const qualifier alone.
/* LISTOFCLASSOBJECTS is generated in ModuleList.h */
const void * const module_descriptor_table[] = { LISTOFCLASSOBJECTS };
/* ... during AWE Instance setup ... */
aweInstance.numModules = sizeof(module_descriptor_table) / sizeof(module_descriptor_table[0]);
aweInstance.pModuleDescriptorTable = (const ModClassModule **)module_descriptor_table;
Memory (heaps)
The AWE Heaps are static sections of memory provided by the application to the AWE Instance. There are typically 3 AWE Heaps allocated: FASTA, FASTB, and SLOW, where the integrator typically maps FASTA and FASTB to L1 or L2 memory, while SLOW heap is often mapped to abundant external or DDR memory.
The integrator is responsible for making sure that these heaps are never directly accessed (read or written to) by the application. Any queries or modifications to the audio system must come from processing tuning commands (PFIDs) or by calling AWE Core APIs.
In multi-instance systems, there is also a SHARED heap, which must be mapped by the integrator to memory accessibly by all AWE Instances. This SHARED heap is used for all inter-instance communications and is completely managed by the AWE Core. Because the shared heap is reachable by every instance and the cores they run on, any instance or core that can write it can affect all the others. The shared heap should be protected from untrusted access just like the other heaps.
AWE Instance
The AWE Instance structure, and the AWEFlashFSInstance it points to, is configured once during initialization and is then trusted implicitly by the AWE Core at runtime. It holds configuration values (such as fundamentalBlockSize and channel counts), pointers to the heaps and the packet and reply buffers, and function pointers (the callbacks the integrator registers, the AWE Core's internal handlers, and the flash file system callbacks cbInit, cbEraseSector, cbFlashWrite, and cbFlashRead).
If an attacker can modify this structure through a memory corruption exploitation elsewhere, the impact ranges from misconfiguration and crashes (for example, corrupting a buffer pointer or fundamentalBlockSize) up to arbitrary code execution. The function pointers are the most dangerous, because the AWE Core will call them as long as the function pointer is not NULL. Overwriting a function pointer with an attacker chosen address transfers control flow directly to the attacker. The flash file system write and erase callbacks are similarly powerful, since they grant write access to flash.
Treat the AWE Instance and flash file system instance as integrity critical. Populate them only from trusted code at initialization, and avoid setting any field, especially a callback or pointer, from untrusted input such as tuning commands, configuration files, or application messages. Where the platform supports it, place these structures in memory that untrusted components cannot write, and do not share pointers to them across trust boundaries.
System Configuration
This section covers system and platform level measures that protect the AWE Core integration beyond the AWE Core's own interfaces. These depend on the target platform and are the integrator's responsibility.
Diagnostic Interfaces
Interfaces such as JTAG/SWD, debug UART or console ports, USB debug, and the automotive OBD-II diagnostic access can grant direct access to memory and firmware. This bypasses every software protection described in this document, for example reading out the layout and other intellectual property, or modifying the AWE Instance and its callbacks to achieve code execution. Disable these interfaces in production, or where one must remain for service, gate it behind an authenticated and secure debug mechanism. Note that a tuning interface is often carried over such a port (see the Tuning Interface section).
Configuration Files
A configuration file that can be modified at runtime is an attack surface, since changing it changes how the system behaves. Where configuration files are necessary, store them in read-only memory or media so they cannot be altered, and validate their contents before use.
Input Validation
Treat any input that reaches the AWE Core or the application from untrusted sources (for example, control messages from companion apps, configuration files, or network and IPC messages) as potentially malicious, and validate it before use. The AWE Core does not range-check the values it is given (see the Control APIs section).
Secure Update
If AWE Core artifacts (firmware, AWB layouts, or module pack libraries) can be updated in the field, the integrator's update mechanism should authenticate and validate each update before applying it. This is part of the platform's own secure update process rather than an AWE Core feature, but it matters here because an unauthenticated update can substitute a malicious layout or module pack (see the Dynamic Module Packs section).
Threading Model
Robust audio processing by the AWE Core relies on the system's threading model preventing undue preemption of the audio processing threads. See scheduling_priority for the relative priorities of the AWE Core threads that minimize the chance of disrupted audio processing.
The integrator must prevent unauthorized changes to the priorities or execution rates of the AWE Core threads, and must also prevent any untrusted code from running at a higher priority than the AWE Core audio threads. If higher priority code is allowed to preempt the audio processing threads, it can starve them and cause sustained dropouts or permanent loss of output audio, which can include suppression of safety chimes.
Module Writers
Custom module writers have a lot of freedom to implement algorithms however they see fit. It is assumed module writers themselves have no malicious intent with their code, so the following recommendations are provided in order to limit the cybersecurity vulnerabilities of modules from outside attack.
It is also assumed that module writers follow cybersecurity-minded development practices. Examples include security focused static analysis (e.g., CERT C, MISRA C), unit testing with coverage measurement, and code review. The recommendations below are AWE Core-specific guidance on top of those general practices, not a substitute for them.
Note: These recommendations address vulnerabilities in a module's own code. The integrity and authenticity of the compiled module pack binaries themselves, such as protecting against a modified or substituted module pack, is a separate concern. See the File System section.
- Use the awe_fwMalloc function to allocate all memory required by the module. Don't use system malloc. awe_fwMalloc will use the AWE Heap for memory allocation, and the AWE Core library is able to validate access to this memory from Control APIs and PFIDs. It is also able to profile and reset the AWE Heap, whereas system memory is completely hidden. Always check the return value of awe_fwMalloc and fail the Constructor gracefully (propagate the error code) rather than dereferencing a failed (NULL) allocation.
- Define variables and arrays as part of the module instance structure rather than using globals. There can be multiple instances of a module class in a layout, and the same instance's Process function can run concurrently on different cores or be preempted mid-Set, so per-instance state must live in the instance structure. Globals would be shared across instances, leading to data corruption and non-reentrant behavior that an attacker could provoke.
- Wire data is not validated before or after calling the module. If values that could cause problems with the module (NaN, ±inf, or inputs that lead to divide-by-zero) are possible in the wire buffers, then the data should be validated in the Process function before use.
- Wire buffer data should only ever be accessed in the Process function, not in the Set or Constructor functions. The wire's metadata (block size, channel count, sample rate — read via the wire accessor macros) can be safely accessed by any module function.
- Validate any array index, offset, or length that is computed inside the module before using it to access memory. The AWE Core's memory bounds checking protects framework induced access (Control API and tuning reads/writes into module arrays), but it does not protect the module's own code from indexing its arrays out of range. Wherever an index, offset, or length is derived from a module parameter, a control value, or wire metadata (e.g. block size or channel count), confirm it lies within the bounds of the target array before reading or writing. An out-of-bounds access is a direct memory-corruption vector and, depending on the system, a path to arbitrary code execution or system crash.
- Design the Process function so that execution time is as deterministic and consistent as possible. Spikes in CPU load can potentially be exploited by attackers to cause persistent audio dropouts. This includes avoiding system calls, which can have inconsistent execution times.
- Offload tasks that are not real-time-critical to the Set function. The Set function is normally processed in the deferred processing context, which is lower priority than the audio processing threads and does not have any real-time constraints. For example, expensive coefficient calculations triggered by changed module parameters should be accomplished in the Set function, rather than the Process function. Note that a module's Process function can pre-empt the Set function, so it is the module writer's responsibility to ensure that any variables and arrays that are shared between the two functions are safely managed. If system calls must be made, they should be done in the Set function.