| Titre | RT-Thread v5.0.2 Improper Handling of Parameters |
|---|
| Description | I have already reported this vulnerability in the project's GitHub issue tracker for review by the maintainers. The report is provided below.
# sys_getaddrinfo trusts nested user pointer and can write outside validated user memory
## Summary
I identified an insufficient user-pointer validation issue in the `sys_getaddrinfo` system call in RT-Thread Smart.
When `ARCH_MM_MMU` is enabled, `sys_getaddrinfo()` validates that the outer `res` pointer is user-accessible. However, after a successful name lookup it reads `res->ai_addr` directly from that user-controlled structure and passes it to `sockaddr_tomusl()`. `sockaddr_tomusl()` then writes a `struct musl_sockaddr` result through that nested pointer without checking that the nested destination is valid user memory.
This gives an unprivileged user process control over the kernel write destination used for the returned socket address. If the nested pointer targets mapped kernel or otherwise sensitive memory, the syscall can perform an unauthorized write. If it targets unmapped or faulting memory, the direct kernel write can crash the system, causing a denial of service.
## Vulnerable Code Location
The vulnerable syscall is registered in the LWP syscall table:
```text
components/lwp/lwp_syscall.c:11085 SYSCALL_NET(SYSCALL_SIGN(sys_getaddrinfo)),
```
The affected code is in:
```text
components/lwp/lwp_syscall.c:7051 sys_getaddrinfo(...)
components/lwp/lwp_syscall.c:7163 sockaddr_tomusl(k_res->ai_addr, res->ai_addr)
components/lwp/lwp_syscall.c:314 sockaddr_tomusl(...)
components/lwp/lwp_sys_socket.h:105 struct musl_sockaddr
```
The important data flow is:
```text
user-controlled res
-> sys_getaddrinfo(..., struct musl_addrinfo *res)
-> lwp_user_accessable(res, sizeof(*res)) checks only the outer object
-> res->ai_addr is read directly from user memory
-> sockaddr_tomusl(k_res->ai_addr, res->ai_addr)
-> std->sa_family write and memcpy(std->sa_data, ...)
-> attacker-selected destination write or kernel fault
```
Relevant code:
```c
struct musl_addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct musl_sockaddr *ai_addr;
char *ai_canonname;
struct musl_addrinfo *ai_next;
};
sysret_t sys_getaddrinfo(const char *nodename,
const char *servname,
const struct musl_addrinfo *hints,
struct musl_addrinfo *res)
{
...
#ifdef ARCH_MM_MMU
if (!lwp_user_accessable((void *)res, sizeof(*res)))
{
SET_ERRNO(EFAULT);
goto exit;
}
#endif
...
ret = sal_getaddrinfo(k_nodename, k_servname, k_hints, &k_res);
if (ret == 0)
{
/* res is validated, but res->ai_addr is not. */
sockaddr_tomusl(k_res->ai_addr, res->ai_addr);
res->ai_addrlen = k_res->ai_addrlen;
res->ai_family = k_res->ai_family;
res->ai_flags = k_res->ai_flags;
res->ai_next = NULL;
...
}
...
}
```
`sockaddr_tomusl()` only checks for NULL. It does not validate that `std` points to writable user memory and it does not use `lwp_put_to_user()`:
```c
static void sockaddr_tomusl(const struct sockaddr *lwip, struct musl_sockaddr *std)
{
if (std && lwip)
{
std->sa_family = (uint16_t) lwip->sa_family;
memcpy(std->sa_data, lwip->sa_data, sizeof(std->sa_data));
}
}
```
The destination type is 16 bytes:
```c
struct musl_sockaddr
{
uint16_t sa_family;
char sa_data[14];
};
```
## Vulnerability Description
The syscall validates only the top-level `res` pointer:
```c
lwp_user_accessable((void *)res, sizeof(*res))
```
That check proves only that the `struct musl_addrinfo` object itself is in accessible user memory. It does not prove that the pointer stored inside `res->ai_addr` is safe to write to.
After `sal_getaddrinfo()` succeeds, the kernel directly evaluates `res->ai_addr` and uses it as the output destination for the resolved socket address:
```c
sockaddr_tomusl(k_res->ai_addr, res->ai_addr);
```
Because `res` is user-controlled, `res->ai_addr` is also user-controlled. A malicious process can set it to:
1. A kernel or sensitive memory address that should not be writable from user mode, causing an unauthorized kernel write.
2. An unmapped or invalid address, causing a kernel fault and denial of service.
3. Another user process's mapped memory, if such mappings are reachable in the current address-space configuration.
The bug is similar in shape to other nested-pointer syscall bugs: checking the outer structure is not enough. Each user-supplied pointer contained inside that structure must be copied into kernel memory and validated before use, and writes back to user space should go through the kernel's user-copy helpers.
## Steps to Reproduce
I have not reproduced this on physical RT-Thread Smart hardware. The issue is visible from source-level inspection of the syscall path.
Required configuration:
```text
RT_USING_SMART or RT_USING_LWP enabled
ARCH_MM_MMU enabled
RT_USING_SAL enabled
SAL_USING_POSIX enabled
```
Several Smart/MMU board configurations in the checked tree enable the relevant pieces, including:
```text
bsp/nxp/imx/imx6ull-smart/rtconfig.h
bsp/k230/rtconfig.h
bsp/cvitek/cv18xx_risc-v/rtconfig.h
bsp/rockchip/rk3500/rtconfig.h
bsp/raspberry-pi/raspi-dm2.0/rtconfig.h
```
Conceptual trigger from an unprivileged process:
```c
struct musl_addrinfo res;
memset(&res, 0, sizeof(res));
/*
* The outer object &res is a valid user pointer, so sys_getaddrinfo()
* accepts it. The nested pointer is attacker-controlled.
*/
res.ai_addr = (struct musl_sockaddr *)ATTACKER_CHOSEN_ADDRESS;
sys_getaddrinfo("127.0.0.1", "80", NULL, &res);
```
If `ATTACKER_CHOSEN_ADDRESS` is writable kernel memory, the syscall writes the returned address family and 14 bytes of address data there. If it is invalid or unmapped, the same direct write can fault in kernel context.
Expected safe behavior:
```text
sys_getaddrinfo() should reject an inaccessible nested res->ai_addr pointer with EFAULT,
or copy the result through a validated kernel temporary and lwp_put_to_user().
```
Current behavior:
```text
sys_getaddrinfo() validates only res, then writes through res->ai_addr directly.
```
## Impact
This vulnerability can allow an unprivileged process to influence where the kernel writes the resolved socket address returned by `sys_getaddrinfo()`.
Potential impacts include:
```text
Unauthorized memory write:
The attacker controls res->ai_addr, and sockaddr_tomusl() writes a 16-byte
musl_sockaddr result to that address.
Denial of service:
If res->ai_addr points to unmapped or otherwise faulting memory, the direct
kernel write can crash or destabilize the system.
Privilege escalation risk:
On targets where user-controlled syscall writes can reach sensitive kernel
state, the write may corrupt kernel objects or control data.
```
The exact exploitability depends on the target MMU mapping, kernel address exposure, and RT-Thread Smart memory protection configuration. The core issue is that the syscall crosses the user/kernel boundary with a nested attacker-controlled pointer and writes through it without validation.
## Suggested Fix
Do not read or write nested user pointers directly from `res`.
One safer pattern is:
```text
1. Copy the outer musl_addrinfo from user memory into a kernel temporary.
2. Validate copied_res.ai_addr with lwp_user_accessable(copied_res.ai_addr, sizeof(struct musl_sockaddr)).
3. Convert the kernel sockaddr into a kernel musl_sockaddr temporary.
4. Use lwp_put_to_user(copied_res.ai_addr, &tmp_sockaddr, sizeof(tmp_sockaddr)).
5. Use lwp_put_to_user(res, &tmp_addrinfo, sizeof(tmp_addrinfo)) for the outer result fields.
```
The same pattern should also be used for reading `hints`: copy it once with `lwp_get_from_user()` and use the kernel copy, instead of repeatedly reading fields from the user pointer.
## Environment
```text
Initial RT-Thread commit checked: c39e92f4c1
Checked tree description: v5.0.2-2360-gc39e92f4c1-dirty
Affected file: components/lwp/lwp_syscall.c
Affected syscall: sys_getaddrinfo
Affected configuration: RT-Thread Smart / LWP with ARCH_MM_MMU and SAL POSIX networking
Target hardware: not tested on board yet
Verification: source-level syscall data-flow review
```
|
|---|
| La source | ⚠️ https://github.com/RT-Thread/rt-thread/issues/11428 |
|---|
| Utilisateur | Zephyr Saxon (UID 80853) |
|---|
| Soumission | 01/06/2026 08:54 (il y a 1 mois) |
|---|
| Modérer | 03/07/2026 15:51 (1 month later) |
|---|
| Statut | Accepté |
|---|
| Entrée VulDB | 376115 [RT-Thread jusqu’à 5.0.2 lwp_syscall.c sys_getaddrinfo ai_addr buffer overflow] |
|---|
| Points | 20 |
|---|