CVE-2026-18418: Out-of-Bounds Read in Zephyr RTOS zbus Proxy Agent IPC
Navigation: TECH OPS > IT Security > CVE Analysis
Executive Summary
CVE-2026-18418 is an out-of-bounds read vulnerability in the Zephyr RTOS zbus proxy agent IPC subsystem that allows attackers with control over a peer domain (secondary core) on multi-core SoCs to disclose adjacent memory contents or trigger system crashes. The flaw stems from unbounded string logging of non-NUL-terminated buffers during IPC frame rejection handling. While the vulnerability does not enable code execution, it poses meaningful risks to system confidentiality and availability in embedded deployments.
Embedded systems engineers and security teams managing Zephyr RTOS deployments need to understand this vulnerability’s exploitation mechanics, detection methods, and immediate mitigation strategies.
What is CVE-2026-18418?
Vulnerability Overview
CVE-2026-18418 is a CWE-125 out-of-bounds read vulnerability located in subsys/zbus/proxy_agent/zbus_proxy_agent_ipc.c within the Zephyr RTOS project. The vulnerability occurs when the zbus proxy agent IPC subsystem logs rejected inter-process communication frames using an unbounded string format specifier (%s) on a non-NUL-terminated buffer.
When a malformed IPC frame arrives at the receiving domain, the error-handling path attempts to log the frame’s channel name using %s. Since the underlying buffer is not guaranteed to be NUL-terminated, the logging function’s strlen() call scans past the buffer boundary into adjacent memory, reading and disclosing whatever data exists there until a null byte is encountered.
Affected Components
The vulnerability affects:
- Primary Component:
subsys/zbus/proxy_agent/zbus_proxy_agent_ipc.c(error logging path) - Related Component:
subsys/zbus/proxy_agent/zbus_proxy_agent.c(frame validation logic) - Subsystem: Zephyr RTOS
zbus(zero-copy bus) proxy agent with IPC backend - Transport Backends: Both
icmsgandrpmsgIPC service implementations - Configuration: Systems with
CONFIG_ZBUS_PROXY_AGENT_IPCenabled
Why This Matters for Your Systems
This vulnerability is significant for several reasons:
-
Multi-Core SoC Prevalence: Modern embedded systems increasingly use multi-core architectures (ARM Cortex-M with co-processors, heterogeneous compute platforms). These systems rely on IPC mechanisms like those in Zephyr RTOS.
-
Default Configuration Risk: The vulnerability is active in default logging configurations (Warning level or higher), meaning most production deployments are affected without explicit hardening.
-
Information Disclosure: Stack memory and shared memory contents can be leaked into system logs, potentially exposing cryptographic keys, authentication tokens, or sensitive data.
-
Availability Impact: Maliciously crafted frames can trigger memory access faults, causing core resets or system hangs.
-
Supply Chain Exposure: Zephyr RTOS is widely used in IoT devices, automotive embedded systems, and industrial controllers where security is critical.
Technical Breakdown: How the Vulnerability Works
The Root Cause: Unbounded String Logging
The vulnerability originates in how the proxy agent IPC module handles rejected frames. When an incoming IPC message fails validation, the code logs a warning that includes the channel name from the rejected message:
// Vulnerable pattern (simplified)
struct zbus_proxy_msg *msg = (struct zbus_proxy_msg *)data;
if (msg->message_size > MAX_SIZE || !is_valid_channel(msg)) {
LOG_WRN("Rejected frame on channel %s", msg->channel_name);
// Problem: channel_name[] is not guaranteed to be NUL-terminated
}
The channel_name field is a fixed-size array within the struct zbus_proxy_msg structure. When the message arrives from an untrusted peer domain, there is no guarantee that this array contains a NUL terminator. The %s format specifier in LOG_WRN() calls strlen(), which scans memory sequentially looking for a 0x00 byte.
If the attacker fills the entire channel_name array with non-zero bytes, strlen() continues reading past the struct boundary into whatever memory follows it.
Memory Layout and Read Mechanics
The behavior differs based on the IPC backend in use:
With icmsg Backend:
Stack Frame (IPC Work-Queue Thread)
┌─────────────────────────────────┐
│ struct zbus_proxy_msg │
│ ├─ message_size │
│ ├─ channel_name[32] │ ← Non-terminated, filled with 0xFF
│ └─ (end of struct) │
├─────────────────────────────────┤
│ Adjacent Stack Variables │ ← strlen() reads here
│ ├─ Local pointers │
│ ├─ Return addresses │
│ └─ Other function data │
├─────────────────────────────────┤
│ Stack Guard / Boundary │
└─────────────────────────────────┘
The strlen() scan reads the adjacent stack frame data and packages it into the log output, disclosing stack memory contents.
With rpmsg Backend:
Shared vring Memory (Shared Between Domains)
┌─────────────────────────────────┐
│ struct zbus_proxy_msg │
│ ├─ message_size │
│ ├─ channel_name[32] │ ← Non-terminated
│ └─ (end of struct) │
├─────────────────────────────────┤
│ Adjacent Shared Memory │ ← strlen() reads here
│ ├─ Other domain's buffers │
│ ├─ Shared state variables │
│ └─ Inter-domain data │
└─────────────────────────────────┘
The scan reads adjacent shared memory contents, potentially disclosing data from the peer domain or other subsystems.
Why the Log Packager Doesn’t Prevent Exploitation
A critical detail: while the log packager enforces an internal -ENOSPC boundary check that prevents the output buffer from overflowing, this does not prevent the input scan from reading out-of-bounds memory. The sequence is:
strlen()scans unbounded memory (vulnerability occurs here)- Result is passed to log formatter
- Log formatter enforces output buffer limits (too late to prevent the read)
The -ENOSPC check protects against buffer overflow in the log output, not against out-of-bounds reads during input processing.
icmsg vs. rpmsg Backend Differences
| Aspect | icmsg Backend | rpmsg Backend |
|---|---|---|
| Buffer Location | IPC work-queue thread stack | Shared vring memory |
| Memory Disclosed | Stack frame data (local variables, return addresses) | Adjacent shared memory (peer domain buffers, shared state) |
| Disclosure Scope | Limited to single thread’s stack frame | Potentially broader (shared memory region) |
| Crash Risk | High (stack boundary crossing) | Medium (vring boundary crossing) |
| Exploitability | Requires stack layout knowledge | Requires shared memory layout knowledge |
Attack Scenarios and Real-World Impact
Scenario A: Inter-Core Memory Reconnaissance
Attacker Profile: Firmware compromise on secondary core (e.g., DSP, security processor, or co-processor)
Attack Flow:
- Attacker gains execution on a peer domain (secondary core) through firmware vulnerability, supply chain compromise, or physical attack
- Attacker crafts a malicious
struct zbus_proxy_msgwith:
- Valid message header fields (to pass initial checks)
channel_name[]filled entirely with non-zero bytes (0xFF, 0xAA, etc.)- No NUL terminator
- Attacker transmits the frame via
ipc_serviceto the primary domain - Primary domain receives frame and triggers validation
- Validation fails (malformed channel name)
- Error handler logs the rejected frame using
LOG_WRN("...%s...", msg->channel_name) strlen()scans past buffer boundary- Adjacent memory is read and packaged into log output
- Log output is transmitted to debug UART, network sink, or persistent storage
- Attacker retrieves logs and extracts leaked memory contents
Real-World Impact:
- Disclosure of cryptographic keys stored on stack
- Leakage of authentication tokens or session data
- Exposure of sensitive algorithm parameters
- Information gathering for secondary attacks
Scenario B: Denial of Service via Read Fault
Attacker Profile: Firmware compromise on secondary core
Attack Flow:
- Attacker crafts a frame where
channel_name[]is filled with non-zero bytes - Attacker ensures adjacent memory beyond the buffer contains no NUL terminators for a large distance
- Attacker crafts the payload such that
strlen()will eventually cross into an unmapped or protected memory region - Frame is transmitted to primary domain
- Primary domain processes frame and calls
strlen()on the malicious buffer strlen()walks through memory, crosses into unmapped region- Memory management unit (MMU) or memory protection unit (MPU) raises a fault
- Fault handler triggers system reset or core hang
- System becomes unavailable
Real-World Impact:
- Denial of service to primary domain
- Potential cascade failure in multi-core system
- Loss of critical functionality
- Unplanned system resets affecting reliability
Information Disclosure Risks
The vulnerability enables disclosure of:
- Stack Memory: Local variables, return addresses, saved registers
- Shared Memory: Inter-domain buffers, shared state, communication queues
- Sensitive Data: Cryptographic keys, authentication credentials, session tokens
- System State: Memory addresses (defeating ASLR), function pointers, object references
The amount of disclosed memory is limited by:
- Distance to the next NUL byte in memory
- Log output buffer size (internal
-ENOSPClimit) - Typical disclosure: 64-512 bytes per malformed frame
System Stability Threats
The vulnerability threatens availability through:
- Memory Faults: Crossing into unmapped memory regions
- Bus Errors: Accessing protected memory areas
- Core Hangs: Infinite loops in fault handlers
- Cascading Failures: Primary domain crash affecting dependent subsystems
- Watchdog Triggers: Unresponsive cores triggering system-wide resets
Who Is Vulnerable?
Required Configuration Settings
A system is vulnerable if all of the following are true:
# Build Configuration
CONFIG_ZBUS_PROXY_AGENT_IPC=y # Proxy agent IPC enabled
CONFIG_ZBUS=y # zbus subsystem enabled
CONFIG_IPC_SERVICE=y # IPC service enabled
# Logging Configuration
CONFIG_LOG=y # Logging enabled
CONFIG_ZBUS_PROXY_LOG_LEVEL_WRN=y # Warning level or higher (default)
# OR
CONFIG_ZBUS_PROXY_LOG_LEVEL_INF=y
CONFIG_ZBUS_PROXY_LOG_LEVEL_DBG=y
Multi-Core SoC Requirements
The vulnerability requires:
- Multi-core architecture with at least two processing domains
- Inter-domain communication via
ipc_service(icmsg or rpmsg backend) - Shared memory or stack accessibility between domains
- Attacker control over at least one peer domain
Single-core systems are not vulnerable because there is no peer domain to send malicious frames.
Logging Level Dependencies
| Log Level | Vulnerable? | Notes |
|---|---|---|
| OFF | No | Logging disabled entirely |
| ERROR | No | Only error-level logs enabled |
| WARNING | Yes | Default configuration; vulnerable |
| INFO | Yes | More verbose; vulnerable |
| DEBUG | Yes | Most verbose; vulnerable |
Firmware Prerequisites
Vulnerable systems typically have:
- Zephyr RTOS version prior to the patch (all versions before fix applied)
- Multi-core SoC (ARM Cortex-M with DSP, Cortex-A with Cortex-M, etc.)
- IPC service configured for inter-domain communication
- Debug logging enabled (standard for development and many production deployments)
Severity Assessment
CVSS Metrics and Ratings
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | Adjacent | Requires control of peer domain on same SoC |
| Attack Complexity | High | Requires prior compromise of peer domain; memory layout knowledge needed |
| Privileges Required | High | Must have execution on peer domain |
| User Interaction | None | No user interaction required |
| Scope | Changed | Affects primary domain from peer domain |
| Confidentiality | Low | Partial memory disclosure (limited by NUL terminator) |
| Integrity | None | No write capability; read-only vulnerability |
| Availability | Low | Potential DoS through memory faults |
CVSS v3.1 Vector: CVSS:3.1/AV:A/AC:H/PR:H/UI:N/S:C/C:L/I:N/A:L
CVSS v3.1 Score: 4.4 (Medium)
Confidentiality Impact
- Scope: Limited to contiguous memory adjacent to message buffer
- Disclosure Amount: Typically 64-512 bytes per malformed frame
- Sensitive Data Risk: Moderate (depends on what’s adjacent in memory)
- Mitigation: Log output controls, memory layout randomization
Availability Impact
- Crash Likelihood: Medium (depends on memory layout and adjacent unmapped regions)
- Recovery: System reset or watchdog intervention
- Service Disruption: Temporary (until reboot) or permanent (if cascading)
- Mitigation: Memory protection, fault handling, watchdog configuration
Access Complexity and Barriers
Barriers to Exploitation:
- Peer Domain Compromise: Attacker must first compromise firmware on secondary core
- Memory Layout Knowledge: Attacker needs to understand memory layout to craft effective payloads
- IPC Endpoint Access: Attacker must have access to bound
ipc_serviceendpoint - Logging Configuration: System must have warning-level logging enabled
- Log Access: Attacker must be able to retrieve log output
Reducing Barriers:
- Public memory layout information (datasheets, debug symbols)
- Fuzzing to discover memory layout
- Brute-force NUL byte scanning
- Log output accessible via debug interfaces (UART, network)
Detection: Finding Vulnerable Code and Behavior
Static Code Analysis Techniques
Pattern 1: Unbounded String Logging of IPC Buffers
Search for logging calls that use %s on IPC message fields:
# Find vulnerable patterns
grep -rn "LOG_WRN\|LOG_INF\|LOG_DBG" subsys/zbus/proxy_agent/ | grep "%s"
# Look for channel_name logging
grep -rn "channel_name" subsys/zbus/proxy_agent/zbus_proxy_agent_ipc.c
Pattern 2: Missing NUL-Termination Validation
// Vulnerable: No length check before %s
LOG_WRN("Rejected: %s", msg->channel_name);
// Vulnerable: Length check but still uses %s
if (msg->channel_name_len > 0) {
LOG_WRN("Rejected: %s", msg->channel_name); // Still unbounded!
}
// Safe: Precision-bounded format specifier
LOG_WRN("Rejected: %.*s", (int)msg->channel_name_len, msg->channel_name);
Pattern 3: IPC Frame Rejection Paths
# Find all rejection/error paths in proxy agent
grep -rn "reject\|invalid\|error" subsys/zbus/proxy_agent/ -i | grep -i "log"
Log Monitoring Indicators
Indicator 1: Anomalous Log Output
Monitor system logs for:
- Garbled or binary characters in proxy agent logs
- Unexpectedly long strings following “Rejected frame” messages
- Non-printable characters in channel name logs
- Repeated patterns suggesting memory scanning
Example Anomalous Log:
[zbus_proxy_agent] Rejected frame on channel: \x41\x42\x43\x44\x00\x12\x34\x56\x78\x9a\xbc\xde\xf0...
Indicator 2: Frequency Anomalies
- Sudden spike in rejected frame logs
- Repeated rejection of frames with identical malformed patterns
- Correlation with secondary core activity
System Crash Pattern Recognition
Indicator 1: Memory Fault Crashes
Monitor for:
[FAULT] Bus Error in strlen() called from zbus_proxy_agent_ipc.c
[FAULT] Memory Protection Fault at address 0x????????
[FAULT] Unhandled Exception in IPC work-queue thread
Indicator 2: Watchdog Resets
- Watchdog resets coinciding with IPC frame reception
- Repeated resets from same core
- Resets triggered during logging operations
Indicator 3: Core Dumps
- Stack traces showing
strlen()in call stack - Crash occurring in
zbus_proxy_agent_ipc.cerror path - Fault address in unmapped memory region
Automated Scanning Methods
Static Analysis Tool Configuration:
# Using Clang Static Analyzer
scan-build -o report make
# Using Coverity
cov-build --dir cov-int make
cov-analyze --dir cov-int --security
# Using Semgrep (custom rule)
semgrep --config=p/security-audit \
--include="*zbus_proxy_agent*.c" \
--pattern='LOG_WRN(..., "%s", $BUF)' \
.
Custom Semgrep Rule:
rules:
- id: zbus-unbounded-string-log
pattern-either:
- pattern: LOG_WRN(..., "%s", $MSG->channel_name)
- pattern: LOG_INF(..., "%s", $MSG->channel_name)
- pattern: LOG_DBG(..., "%s", $MSG->channel_name)
message: "Unbounded string logging of IPC buffer"
severity: WARNING

Immediate Mitigation Steps
Official Code Fix Implementation
The official remediation replaces unbounded %s format specifiers with precision-bounded %.*s specifiers:
Before (Vulnerable):
// subsys/zbus/proxy_agent/zbus_proxy_agent_ipc.c
LOG_WRN("Rejected frame on channel %s", msg->channel_name);
After (Fixed):
// Precision-bounded string logging
LOG_WRN("Rejected frame on channel %.*s",
(int)MIN(msg->channel_name_len, sizeof(msg->channel_name)),
msg->channel_name);
Implementation Steps:
- Obtain the patch: Download from Zephyr RTOS repository or security advisory
- Apply to source: Patch
subsys/zbus/proxy_agent/zbus_proxy_agent_ipc.c - Rebuild firmware: Recompile with patched source
- Validate: Verify patch applied correctly with
grepor code review - Deploy: Update firmware on all affected devices
Precision-Bounded String Logging Pattern
The safe pattern for logging untrusted buffers:
// Safe pattern: Use %.*s with explicit length bound
#define SAFE_LOG_STR(fmt, buf, len) \
LOG_WRN(fmt " %.*s", (int)MIN(len, sizeof(buf)), buf)
// Usage
SAFE_LOG_STR("Rejected frame on channel:", msg->channel_name, msg->channel_name_len);
// Or inline
LOG_WRN("Rejected: %.*s",
(int)MIN(msg->channel_name_len, ZBUS_CHANNEL_NAME_MAX),
msg->channel_name);
Key Points:
- Use
%.*sinstead of%s(precision specifier) - Precision value is the maximum bytes to read
- Bound to minimum of: actual length field, buffer size, or safe constant
- Cast to
intfor format specifier compatibility
Log Level Workarounds
Temporary Workaround 1: Disable Proxy Agent Logging
# In prj.conf or board configuration
CONFIG_ZBUS_PROXY_LOG_LEVEL_OFF=y
This disables warning-level logs for the proxy agent IPC module, preventing the vulnerable code path from executing. Note: This is a temporary workaround; patching is still required.
Temporary Workaround 2: Reduce Log Level
# Set to error-level only (skips warning logs)
CONFIG_ZBUS_PROXY_LOG_LEVEL_ERR=y
Temporary Workaround 3: Disable Logging Entirely
# Disable all logging (not recommended for production)
CONFIG_LOG=n
Firmware Integrity Controls
Implement Secure Boot on Peer Domains:
// Pseudo-code for secure boot verification
int verify_peer_domain_firmware(const uint8_t *firmware, size_t size) {
uint8_t expected_hash[32];
uint8_t computed_hash[32];
// Load expected hash from secure storage
load_trusted_hash(expected_hash);
// Compute hash of firmware
sha256(firmware, size, computed_hash);
// Compare (constant-time)
if (constant_time_compare(expected_hash, computed_hash, 32) != 0) {
return -EINVAL; // Firmware verification failed
}
return 0; // Firmware verified
}
Benefits:
- Prevents untrusted code execution on peer domains
- Eliminates primary attack vector
- Requires cryptographic key management
- Adds boot-time overhead
Long-Term Remediation Strategy
Patching and Deployment Timeline
Immediate (Week 1):
- Apply log level workaround (
CONFIG_ZBUS_PROXY_LOG_LEVEL_OFF=y) - Assess affected devices in deployment
- Prioritize critical systems
Short-term (Week 2-4):
- Obtain official patch from Zephyr RTOS
- Test patch in development environment
- Validate against regression test suite
- Prepare firmware update package
Medium-term (Month 1-2):
- Deploy patched firmware to production devices
- Implement staged rollout (test devices first)
- Monitor for issues and crashes
- Collect telemetry on patch effectiveness
Long-term (Ongoing):
- Maintain patch currency with Zephyr RTOS releases
- Implement secure boot on peer domains
- Establish firmware update procedures
- Monitor for related vulnerabilities
Secure Boot Implementation
Step 1: Generate Cryptographic Keys
# Generate RSA-2048 key pair
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
# Generate ECDSA key pair (alternative)
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
openssl ec -in private_key.pem -pubout -out public_key.pem
Step 2: Sign Firmware
# Sign firmware image
openssl dgst -sha256 -sign private_key.pem firmware.bin > firmware.sig
# Embed public key in bootloader
# (Bootloader verifies signature before executing firmware)
Step 3: Configure Bootloader
// Bootloader verification logic
int bootloader_verify_firmware(const uint8_t *firmware, size_t size,
const uint8_t *signature, size_t sig_size) {
// Load embedded public key
const uint8_t *public_key = get_embedded_public_key();
// Verify signature
if (crypto_verify_signature(firmware, size, signature, sig_size, public_key) != 0) {
return -EINVAL; // Signature verification failed
}
return 0; // Firmware verified
}
Co-Processor Verification
Implement Attestation:
// Peer domain attestation
int attest_peer_domain(void) {
uint8_t nonce[32];
uint8_t attestation[256];
// Generate random nonce
generate_random_nonce(nonce, sizeof(nonce));
// Request attestation from peer domain
send_attestation_request(nonce);
// Receive attestation response
receive_attestation_response(attestation, sizeof(attestation));
// Verify attestation
if (verify_attestation(attestation, nonce) != 0) {
return -EINVAL; // Attestation failed
}
return 0; // Peer domain verified
}
Testing and Validation
Test Case 1: Malformed Frame Handling
// Test: Send frame with non-terminated channel name
void test_malformed_channel_name(void) {
struct zbus_proxy_msg msg = {
.message_size = sizeof(msg),
.channel_name = {0xFF, 0xFF, 0xFF, ...} // No NUL terminator
};
// Send frame and verify:
// 1. No memory disclosure in logs
// 2. No system crash
// 3. Frame properly rejected
}
Test Case 2: Boundary Conditions
// Test: Frame with channel name at buffer boundary
void test_boundary_channel_name(void) {
struct zbus_proxy_msg msg;
// Fill entire channel_name array
memset(msg.channel_name, 0xAA, sizeof(msg.channel_name));
// Verify no out-of-bounds read
}
Test Case 3: Crash Resistance
// Test: Fuzzing with random malformed frames
void test_fuzzing_malformed_frames(void) {
for (int i = 0; i < 10000; i++) {
struct zbus_proxy_msg msg;
generate_random_frame(&msg);
// Send frame and verify system remains stable
send_frame(&msg);
verify_system_stability();
}
}
Prevention: Secure Development Practices
Format String Vulnerability Prevention
Rule 1: Never Use User-Controlled Format Strings
// VULNERABLE
LOG_WRN(user_input); // User input as format string
// SAFE
LOG_WRN("%s", user_input); // User input as argument
Rule 2: Bound All String Logging
// VULNERABLE
LOG_WRN("Channel: %s", untrusted_buffer);
// SAFE
LOG_WRN("Channel: %.*s", (int)buffer_len, untrusted_buffer);
Rule 3: Validate Before Logging
// SAFE: Validate NUL-termination first
if (strnlen(buffer, MAX_LEN) < MAX_LEN) {
LOG_WRN("Channel: %s", buffer); // Now safe
} else {
LOG_WRN("Channel: %.*s", (int)MAX_LEN, buffer); // Bounded
}
Input Validation Best Practices
Validation Pattern 1: Length Checking
// Validate message size
if (msg->message_size != sizeof(struct zbus_proxy_msg)) {
LOG_WRN("Invalid message size: %u", msg->message_size);
return -EINVAL;
}
Validation Pattern 2: NUL-Termination Checking
// Validate NUL-termination
if (msg->channel_name[sizeof(msg->channel_name) - 1] != '\0') {
LOG_WRN("Channel name not NUL-terminated");
return -EINVAL;
}
Validation Pattern 3: Content Validation
// Validate channel name content
for (int i = 0; i < sizeof(msg->channel_name); i++) {
if (msg->channel_name[i] == '\0') {
break; // Found terminator
}
if (!isprint(msg->channel_name[i])) {
LOG_WRN("Invalid character in channel name");
return -EINVAL;
}
}
IPC Security Hardening
Hardening 1: Message Authentication
// Add HMAC to IPC messages
struct zbus_proxy_msg_authenticated {
struct zbus_proxy_msg msg;
uint8_t hmac[32]; // HMAC-SHA256
};
// Verify HMAC before processing
int verify_message_authenticity(const struct zbus_proxy_msg_authenticated *auth_msg) {
uint8_t computed_hmac[32];
// Compute HMAC over message
hmac_sha256(auth_key, &auth_msg->msg, sizeof(auth_msg->msg), computed_hmac);
// Compare (constant-time)
if (constant_time_compare(computed_hmac, auth_msg->hmac, 32) != 0) {
return -EINVAL; // Authentication failed
}
return 0; // Message authenticated
}
Hardening 2: Rate Limiting
// Rate limit rejected frames to prevent DoS
static int rejected_frame_count = 0;
static uint32_t last_reset_time = 0;
int rate_limit_rejected_frames(void) {
uint32_t now = k_uptime_get_32();
// Reset counter every second
if (now - last_reset_time > 1000) {
rejected_frame_count = 0;
last_reset_time = now;
}
// Allow max 10 rejected frames per second
if (rejected_frame_count++ > 10) {
LOG_WRN("Rejected frame rate limit exceeded");
return -EBUSY;
}
return 0;
}
Hardening 3: Memory Isolation
// Use separate buffers for untrusted data
static uint8_t untrusted_buffer[256] __attribute__((section(".untrusted")));
// Process untrusted data in isolated buffer
int process_untrusted_frame(const uint8_t *frame, size_t size) {
// Copy to isolated buffer
if (size > sizeof(untrusted_buffer)) {
return -EINVAL;
}
memcpy(untrusted_buffer, frame, size);
// Process in isolation
return validate_frame((struct zbus_proxy_msg *)untrusted_buffer);
}
Code Review Checklist
Checklist for Reviewing IPC Message Handling:
- [ ] All format strings are compile-time constants (not user-controlled)
- [ ] All
%sformat specifiers are bounded with precision specifiers (%.*s) - [ ] All untrusted buffers are validated for length before use
- [ ] All untrusted strings are checked for NUL-termination
- [ ] All logging of untrusted data uses bounded format specifiers
- [ ] Error paths do not disclose sensitive information
- [ ] Memory access is bounds-checked before dereferencing
- [ ] No buffer overflows possible in error handling
- [ ] No information leakage through log output
- [ ] Crash handling prevents cascading failures
**