| name | uninitialized-variable-analysis |
| description | Analyze C code for uninitialized stack variable vulnerabilities, detect information disclosure risks, and provide exploitation or mitigation guidance. Use this skill whenever the user mentions uninitialized variables, stack variables, C security, memory leaks, info disclosure, binary exploitation, or asks about analyzing C code for security vulnerabilities. Make sure to use this skill when reviewing C code for security issues, even if the user doesn't explicitly mention 'uninitialized' - partial struct initialization, copy_to_user calls, and stack buffer issues often indicate this vulnerability class. |
Uninitialized Variable Analysis
A skill for identifying, analyzing, and exploiting uninitialized stack variable vulnerabilities in C code.
When to Use This Skill
Trigger this skill when:
- User asks about uninitialized variables in C
- User wants to analyze C code for security vulnerabilities
- User mentions stack variables, memory disclosure, or info leaks
- User is doing binary exploitation research
- User asks about compiler flags related to stack initialization
- User wants to understand how uninitialized variables can be exploited
- User is reviewing kernel/driver code for security issues
Core Concepts
What Are Uninitialized Variables?
Uninitialized stack variables contain whatever data was previously at that memory location. They don't automatically get zeroed out, which means they can leak sensitive information or be exploited to control program behavior.
Key insight: When you declare int x; without initialization, x contains whatever bytes were last written to that stack slot - potentially sensitive data from previous function calls.
Security Risks
- Data Leakage: Sensitive information (passwords, keys, personal data) can be exposed
- Information Disclosure: Memory layout details can aid attackers in developing exploits
- Crashes and Instability: Undefined behavior from uninitialized data
- Arbitrary Code Execution: In some cases, can lead to ROP or function pointer overwrites
Detection Patterns
Code Review Patterns
Look for these patterns in C code:
struct msg {
char data[0x20];
uint32_t len;
};
ssize_t handler(int fd) {
struct msg m;
m.len = read(fd, m.data, sizeof(m.data));
write(1, &m, sizeof(m));
return m.len;
}
Red flags:
- Struct declared but only some fields initialized
copy_to_user, write, or memcpy of entire struct
- Debug helpers that print local structs
- Error paths where initialization is skipped
Compiler Diagnostics
Build with these flags to catch issues:
gcc -Wall -Wextra -Wuninitialized program.c
clang -Wall -Wextra -Wuninitialized program.c
clang-tidy -checks=cppcoreguidelines-init-variables
Dynamic Analysis Tools
- MemorySanitizer (MSan):
clang -fsanitize=memory program.c
- Valgrind:
valgrind --track-origins=yes ./program
These tools reliably flag reads of uninitialized stack bytes during execution.
Exploitation Patterns
Classic Read-Before-Write
When a struct is partially initialized and then copied to userland:
- Identify the struct - Look for structs with padding or unused fields
- Find the leak - Look for
copy_to_user, write, or memcpy of the whole struct
- Determine what's leaked - Stack canaries, saved frame pointers, kernel pointers
- Plan the exploit - Use leaked info to bypass ASLR or canaries
Practical Attack Surfaces (2024-2025)
- Partially initialized structs: Kernel/driver code that
memset only length fields
- Uninitialized indexes/lengths:
size_t len; used to bound reads/writes
- Compiler padding: Even when members are initialized, padding bytes aren't
- Debug helpers: Functions that copy local structs to stdout for debugging
- ROP/Canary disclosure: Uninitialized padding can reveal stack canaries
Minimal PoC Pattern
struct msg {
char data[0x20];
uint32_t len;
};
ssize_t handler(int fd) {
struct msg m;
m.len = read(fd, m.data, sizeof(m.data));
write(1, &m, sizeof(m));
return m.len;
}
Mitigations
Compiler Options
Code Fixes
struct msg m;
m.len = read(fd, m.data, sizeof(m.data));
struct msg m = {0};
m.len = read(fd, m.data, sizeof(m.data));
struct msg m;
memset(&m, 0, sizeof(m));
m.len = read(fd, m.data, sizeof(m.data));
Opt-out Attributes (Watch for These)
Clang allows __attribute__((uninitialized)) on specific locals/structs to keep performance-critical areas uninitialized. Review such annotations carefully - they often mark deliberate attack surface.
Analysis Workflow
When analyzing code for uninitialized variable vulnerabilities:
- Identify stack variables - Look for local variables in functions
- Check initialization - Verify all fields are initialized before use
- Find disclosure points - Look for
copy_to_user, write, memcpy of structs
- Assess impact - Determine what sensitive data could leak
- Recommend fixes - Suggest proper initialization or compiler flags
Example Analysis
Input
struct request {
char buffer[64];
int flags;
void (*callback)(void);
};
void process_request(int fd) {
struct request req;
req.flags = read(fd, req.buffer, sizeof(req.buffer));
send_response(fd, &req, sizeof(req));
}
Analysis Output
Vulnerability Found: Uninitialized stack variable
Location: process_request() function
Issue: req struct is not fully initialized before being sent
Leaked Data:
req.callback (function pointer) - 8 bytes
- Padding between
buffer and flags - 4 bytes
- Padding between
flags and callback - 4 bytes
Impact: Information disclosure of stack contents, potential ROP chain construction
Fix:
void process_request(int fd) {
struct request req = {0};
req.flags = read(fd, req.buffer, sizeof(req.buffer));
send_response(fd, &req, sizeof(req));
}
ARM64 Considerations
Uninitialized variable vulnerabilities work the same on ARM64 - local variables are still managed on the stack. The exploitation patterns and mitigations are identical to x86/x64.
References