-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Description / Steps to reproduce the issue
In arch/arm/src/nrf91/nrf91_modem_sock.c, nrf91_usrsock_ioctl_handler() trusts the arglen field of a
USRSOCK_REQUEST_IOCTL message and copies req->arglen bytes from the request payload into the fixed-size
usrsock->out buffer without validating either the actual request length or the destination capacity:
ack = (struct usrsock_message_datareq_ack_s *)usrsock->out;
memcpy(ack + 1, req + 1, req->arglen);
Because arglen is derived from untrusted input, a process able to submit a crafted usrsock ioctl request can
trigger:
- an out-of-bounds read from the input buffer when arglen exceeds the number of bytes actually present after
the request header; and - an out-of-bounds write into g_usrsock.out when arglen exceeds the remaining space after the ack header.
The copied data is later returned through nrf91_usrsock_send_dack(), so the first case can disclose memory
beyond the received request, while the second case can corrupt adjacent fields in struct nrf91_usrsock_s.
Vulnerability details
usrsock_request() copies request data into g_usrsock.in and passes the resulting byte count (len) to
nrf91_usrsock_ioctl_handler(). The handler immediately casts the buffer and dereferences request fields without
first verifying that the full header is present, and it does not check that req->arglen fits either the received
request or the fixed-size output buffer.
Relevant code path:
static int nrf91_usrsock_ioctl_handler(struct nrf91_usrsock_s *usrsock,
const void *data, size_t len)
{
const struct usrsock_request_ioctl_s *req = data;
struct usrsock_message_datareq_ack_s *ack = NULL;
int ret = 0;
ack = (struct usrsock_message_datareq_ack_s *)usrsock->out;
memcpy(ack + 1, req + 1, req->arglen);
ret = nrf91_usrsock_ioctl(req->usockid,
req->cmd,
(unsigned long)(ack + 1));
return nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, ret,
req->arglen, req->arglen);
}
Missing validations:
- len >= sizeof(*req) before reading req->...
- req->arglen <= len - sizeof(*req) to ensure the payload is fully present
- req->arglen <= NRF91_USRSOCK_BUFSIZE - sizeof(*ack) to ensure the destination buffer is large enough
Issue 1: Out-of-bounds read
If req->arglen > len - sizeof(*req), memcpy() reads past the end of the received request buffer. Because the
handler later sends a data ack using the same arglen value, this can disclose memory adjacent to g_usrsock.in.
Issue 2: Out-of-bounds write
g_usrsock.out is fixed at NRF91_USRSOCK_BUFSIZE (4096 bytes). Since ack points to the start of this buffer, the
maximum safe copy size is:
NRF91_USRSOCK_BUFSIZE - sizeof(struct usrsock_message_datareq_ack_s)
If req->arglen exceeds this limit, memcpy() writes past g_usrsock.out and corrupts adjacent fields in struct
nrf91_usrsock_s.
Steps to reproduce
- Build and run NuttX on an nRF91 target with the modem/usrsock path enabled.
- Obtain the ability to submit a USRSOCK_REQUEST_IOCTL message to the usrsock interface.
- For the OOB read case, send a request whose arglen is larger than the number of bytes actually supplied after
struct usrsock_request_ioctl_s. - For the OOB write case, send a request whose arglen is larger than NRF91_USRSOCK_BUFSIZE - sizeof(struct
usrsock_message_datareq_ack_s); for example, 0xffff. - Observe memory disclosure in the returned data ack and/or corruption of adjacent fields in struct
nrf91_usrsock_s.
Suggested fix
static int nrf91_usrsock_ioctl_handler(struct nrf91_usrsock_s *usrsock,
const void *data, size_t len)
{
const struct usrsock_request_ioctl_s *req = data;
struct usrsock_message_datareq_ack_s *ack;
int ret;
if (len < sizeof(*req))
{
return -EINVAL;
}
if (req->arglen > len - sizeof(*req))
{
return -EINVAL;
}
ack = (struct usrsock_message_datareq_ack_s *)usrsock->out;
if (req->arglen > NRF91_USRSOCK_BUFSIZE - sizeof(*ack))
{
return -EINVAL;
}
memcpy(ack + 1, req + 1, req->arglen);
ret = nrf91_usrsock_ioctl(req->usockid, req->cmd,
(unsigned long)(ack + 1));
return nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, ret,
req->arglen, req->arglen);
}
Impact
A local actor able to submit crafted usrsock ioctl requests can trigger out-of-bounds reads and writes in the
nRF91 usrsock handler. This can lead to memory disclosure, corruption of adjacent usrsock state, denial of
service, and potentially further exploitation depending on build configuration and runtime memory layout.
On which OS does this issue occur?
[OS: Windows], [OS: Linux]
What is the version of your OS?
Ubuntu 22.04.5 LTS
NuttX Version
master
Issue Architecture
[Arch: arm]
Issue Area
[Area: Networking]
Host information
This is a source-level vulnerability in arch/arm/src/nrf91/nrf91_modem_sock.c and is not dependent on a
host-specific build environment. Confirmed by code inspection on Apache NuttX master and nuttx-12.12.0.
Verification
- I have verified before submitting the report.