Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
**Vulnerability:** The `ead` service writes its process ID to a file using `sprintf(pid, "%d\n", getpid())` into a stack-allocated buffer `char pid[8];`. Since `getpid()` can return up to 7 digits on modern Linux systems, adding `\n` and `\0` requires at least 9 bytes, overflowing the 8-byte buffer.
**Learning:** Hardcoded small buffer sizes for formatting integer PIDs can lead to stack memory corruption (CWE-121) as OS configurations like `kernel.pid_max` allow PIDs to exceed traditional limits.
**Prevention:** Always allocate sufficiently large stack buffers (e.g., 32 bytes) when formatting PIDs, or preferably use `snprintf` with `sizeof(buffer)` to enforce explicit bounds checking.
## 2024-05-09 - [ead-client.c buffer overflow vulnerabilities]
**Vulnerability:** Multiple buffer overflows in the OpenWrt Emergency Access Daemon client (`ead-client.c`) due to missing bounds checks on variables `len` (derived from attacker-controlled `msg->len`) before using them as index assignments (`pong->name[len] = 0;`) or size limits in `memcpy` operations.
**Learning:** Decrypting untrusted network data (`ead_decrypt_message()`) does not guarantee the contents or length of the data are valid for local struct allocations. Values computed from network headers (like `msg->len`) must be strictly validated against constant bounds before being used in memory operations.
**Prevention:** Always implement explicit maximum bounds checks on derived length variables before using them in functions like `memcpy` or array assignments, particularly when the length affects fixed-size buffers. Also ensure lengths don't evaluate to <= 0 before doing arithmetic or using them as indices.
8 changes: 7 additions & 1 deletion package/network/services/ead/src/ead-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ handle_pong(void)
struct ead_msg_pong *pong = EAD_DATA(msg, pong);
int len = ntohl(msg->len) - sizeof(struct ead_msg_pong);

if (len <= 0)
if (len <= 0 || len >= 1024)
return false;

pong->name[len] = 0;
Expand All @@ -167,6 +167,9 @@ handle_prime(void)
{
struct ead_msg_salt *sb = EAD_DATA(msg, salt);

if (sb->len > MAXSALTLEN)
return false;

salt.len = sb->len;
memcpy(salt.data, sb->salt, salt.len);

Expand All @@ -191,6 +194,9 @@ handle_b(void)
struct ead_msg_number *num = EAD_DATA(msg, number);
int len = ntohl(msg->len) - sizeof(struct ead_msg_number);

if (len <= 0 || len > MAXPARAMLEN)
return false;

B.data = bbuf;
B.len = len;
memcpy(bbuf, num->data, len);
Expand Down
14 changes: 6 additions & 8 deletions scripts/cfe-bin-header.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import argparse
import os
import struct
import shutil

def auto_int(x):
return int(x, 0)
Expand All @@ -18,14 +19,11 @@ def create_output(args):
header = create_header(args, in_size)
print(header)

in_f = open(args.input_file, 'r+b')
in_bytes = in_f.read(in_size)
in_f.close()

out_f = open(args.output_file, 'w+b')
out_f.write(header)
out_f.write(in_bytes)
out_f.close()
# Optimization: stream file contents with shutil.copyfileobj to avoid loading entire file in memory
with open(args.output_file, 'wb') as out_f:
out_f.write(header)
with open(args.input_file, 'rb') as in_f:
shutil.copyfileobj(in_f, out_f)

def main():
global args
Expand Down
23 changes: 14 additions & 9 deletions scripts/cfe-partition-tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def str_to_bytes_pad(string, size):
return str_bytes


def create_tag(args, in_bytes, size):
def create_tag(args, crc, size):
# JAM CRC32 is bitwise not and unsigned
crc = ~binascii.crc32(in_bytes) & 0xFFFFFFFF
crc = ~crc & 0xFFFFFFFF

tag = bytearray()
tag += struct.pack(">I", args.part_id)
Expand All @@ -57,15 +57,20 @@ def create_output(args):
in_st = os.stat(args.input_file)
in_size = in_st.st_size

in_f = open(args.input_file, "r+b")
in_bytes = in_f.read(in_size)
in_f.close()
# Optimization: compute CRC32 in 64K chunks instead of loading entire file into memory
# This prevents O(N) memory allocation and improves performance for large files.
crc = 0
with open(args.input_file, "rb") as in_f:
while True:
chunk = in_f.read(65536)
if not chunk:
break
crc = binascii.crc32(chunk, crc)

tag = create_tag(args, in_bytes, in_size)
tag = create_tag(args, crc, in_size)

out_f = open(args.output_file, "w+b")
out_f.write(tag)
out_f.close()
with open(args.output_file, "wb") as out_f:
out_f.write(tag)


def main():
Expand Down
32 changes: 20 additions & 12 deletions scripts/cfe-wfi-tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@
import os
import struct
import binascii
import shutil


def auto_int(x):
return int(x, 0)


def create_tag(args, in_bytes):
def create_tag(args, crc):
# JAM CRC32 is bitwise not and unsigned
crc = ~binascii.crc32(in_bytes) & 0xFFFFFFFF
crc = ~crc & 0xFFFFFFFF
tag = struct.pack(
">IIIII",
crc,
Expand All @@ -68,16 +69,23 @@ def create_output(args):
in_st = os.stat(args.input_file)
in_size = in_st.st_size

in_f = open(args.input_file, "r+b")
in_bytes = in_f.read(in_size)
in_f.close()

tag = create_tag(args, in_bytes)

out_f = open(args.output_file, "w+b")
out_f.write(in_bytes)
out_f.write(tag)
out_f.close()
# Optimization: compute CRC32 in 64K chunks instead of loading entire file into memory
# This prevents O(N) memory allocation and improves performance for large files.
crc = 0
with open(args.input_file, "rb") as in_f:
while True:
chunk = in_f.read(65536)
if not chunk:
break
crc = binascii.crc32(chunk, crc)

tag = create_tag(args, crc)

# Optimization: use shutil.copyfileobj to stream the file contents without O(N) memory overhead
with open(args.output_file, "wb") as out_f:
with open(args.input_file, "rb") as in_f:
shutil.copyfileobj(in_f, out_f)
out_f.write(tag)


def main():
Expand Down
14 changes: 6 additions & 8 deletions scripts/sercomm-partition-tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import argparse
import os
import struct
import shutil

def create_header(args, size):
header = struct.pack('32s32s32s32s32s',
Expand All @@ -21,14 +22,11 @@ def create_output(args):
header = create_header(args, in_size)
print(header)

in_f = open(args.input_file, 'r+b')
in_bytes = in_f.read(in_size)
in_f.close()

out_f = open(args.output_file, 'w+b')
out_f.write(header)
out_f.write(in_bytes)
out_f.close()
# Optimization: stream file contents with shutil.copyfileobj to avoid loading entire file in memory
with open(args.output_file, 'wb') as out_f:
out_f.write(header)
with open(args.input_file, 'rb') as in_f:
shutil.copyfileobj(in_f, out_f)

def main():
global args
Expand Down
31 changes: 16 additions & 15 deletions scripts/sercomm-payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,34 @@
import argparse
import hashlib
import os
import shutil

def create_output(args):
in_st = os.stat(args.input_file)
in_size = in_st.st_size

in_f = open(args.input_file, 'r+b')
in_bytes = in_f.read(in_size)
in_f.close()

if (args.pid_file):
pid_st = os.stat(args.pid_file)
pid_size = pid_st.st_size

pid_f = open(args.pid_file, 'r+b')
pid_f = open(args.pid_file, 'rb')
pid_bytes = pid_f.read(pid_size)
pid_f.close()
else:
pid_bytes = bytes.fromhex(args.pid)

# Optimization: compute SHA256 in 64K chunks to avoid O(N) memory overhead for large files
sha256 = hashlib.sha256()
sha256.update(in_bytes)

out_f = open(args.output_file, 'w+b')
out_f.write(pid_bytes)
out_f.write(sha256.digest())
out_f.write(in_bytes)
out_f.close()
with open(args.input_file, 'rb') as in_f:
while True:
chunk = in_f.read(65536)
if not chunk:
break
sha256.update(chunk)

# Optimization: stream the file contents with shutil.copyfileobj
with open(args.output_file, 'wb') as out_f:
out_f.write(pid_bytes)
out_f.write(sha256.digest())
with open(args.input_file, 'rb') as in_f:
shutil.copyfileobj(in_f, out_f)

def main():
global args
Expand Down
Loading