Skip to content

Commit 9e29e32

Browse files
BernardXiongclaude
authored andcommitted
[components][lwp] harden sys_getaddrinfo user pointer handling
sys_getaddrinfo() validated the top-level res buffer, then wrote the resolved socket address through res->ai_addr, a user-controlled nested pointer that was never checked. On Smart/MMU builds a user program could therefore turn getaddrinfo() into an arbitrary kernel write. The hints fields were also read directly from user memory after the access check, leaving a TOCTOU window. Copy res and hints into kernel temporaries with lwp_get_from_user() so all nested pointers come from one validated snapshot. Write the nested sockaddr and the outer addrinfo back with lwp_put_to_user(), which validates the destination range and never dereferences an unchecked user pointer in kernel context. Also fix the servname copy check (a size_t result can never be < 0), allocate the kernel addrinfo with sizeof(*k_hints), and release k_res on the new error paths. Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 2c88a3b commit 9e29e32

1 file changed

Lines changed: 57 additions & 17 deletions

File tree

‎components/lwp/syscall/syscall_netdb.c‎

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,24 @@ sysret_t sys_getaddrinfo(const char *nodename,
6363
char *k_nodename = NULL;
6464
char *k_servname = NULL;
6565
struct addrinfo *k_hints = NULL;
66+
struct musl_addrinfo k_res_musl = { 0 };
67+
struct musl_addrinfo k_hints_musl = { 0 };
6668
#ifdef ARCH_MM_MMU
6769
int len = 0;
6870
#endif
6971

72+
/*
73+
* Work on a kernel copy of res: ai_addr is a user pointer and must not be
74+
* re-read from user memory after validation (TOCTOU).
75+
*/
7076
#ifdef ARCH_MM_MMU
71-
if (!lwp_user_accessable((void *)res, sizeof(*res)))
77+
if (lwp_get_from_user(&k_res_musl, (void *)res, sizeof(k_res_musl)) != sizeof(k_res_musl))
7278
{
7379
SET_ERRNO(EFAULT);
7480
goto exit;
7581
}
82+
#else
83+
k_res_musl = *res;
7684
#endif
7785
if (nodename)
7886
{
@@ -122,7 +130,7 @@ sysret_t sys_getaddrinfo(const char *nodename,
122130
goto exit;
123131
}
124132

125-
if (lwp_get_from_user(k_servname, (void *)servname, len + 1) < 0)
133+
if (lwp_get_from_user(k_servname, (void *)servname, len + 1) != len + 1)
126134
{
127135
SET_ERRNO(EFAULT);
128136
goto exit;
@@ -140,45 +148,73 @@ sysret_t sys_getaddrinfo(const char *nodename,
140148
if (hints)
141149
{
142150
#ifdef ARCH_MM_MMU
143-
if (!lwp_user_accessable((void *)hints, sizeof(*hints)))
151+
if (lwp_get_from_user(&k_hints_musl, (void *)hints, sizeof(k_hints_musl)) != sizeof(k_hints_musl))
144152
{
145153
SET_ERRNO(EFAULT);
146154
goto exit;
147155
}
156+
#else
157+
k_hints_musl = *hints;
148158
#endif
149-
k_hints = (struct addrinfo *)rt_malloc(sizeof *hints);
159+
k_hints = (struct addrinfo *)rt_malloc(sizeof(*k_hints));
150160
if (!k_hints)
151161
{
152162
SET_ERRNO(ENOMEM);
153163
goto exit;
154164
}
155165

156-
rt_memset(k_hints, 0x0, sizeof(struct addrinfo));
157-
k_hints->ai_flags = hints->ai_flags;
158-
k_hints->ai_family = hints->ai_family;
159-
k_hints->ai_socktype = hints->ai_socktype;
160-
k_hints->ai_protocol = hints->ai_protocol;
161-
k_hints->ai_addrlen = hints->ai_addrlen;
166+
rt_memset(k_hints, 0x0, sizeof(*k_hints));
167+
k_hints->ai_flags = k_hints_musl.ai_flags;
168+
k_hints->ai_family = k_hints_musl.ai_family;
169+
k_hints->ai_socktype = k_hints_musl.ai_socktype;
170+
k_hints->ai_protocol = k_hints_musl.ai_protocol;
171+
k_hints->ai_addrlen = k_hints_musl.ai_addrlen;
162172
}
163173

164174
ret = sal_getaddrinfo(k_nodename, k_servname, k_hints, &k_res);
165175
if (ret == 0)
166176
{
167177
/* set sockaddr */
168-
sockaddr_tomusl(k_res->ai_addr, res->ai_addr);
169-
res->ai_addrlen = k_res->ai_addrlen;
178+
if (k_res->ai_addr && k_res_musl.ai_addr)
179+
{
180+
#ifdef ARCH_MM_MMU
181+
struct musl_sockaddr k_sockaddr;
182+
183+
sockaddr_tomusl(k_res->ai_addr, &k_sockaddr);
184+
if (lwp_put_to_user(k_res_musl.ai_addr, &k_sockaddr, sizeof(k_sockaddr)) != sizeof(k_sockaddr))
185+
{
186+
SET_ERRNO(EFAULT);
187+
ret = -1;
188+
goto exit;
189+
}
190+
#else
191+
sockaddr_tomusl(k_res->ai_addr, k_res_musl.ai_addr);
192+
#endif
193+
}
194+
k_res_musl.ai_addrlen = k_res->ai_addrlen;
170195

171196
/* set up addrinfo */
172-
res->ai_family = k_res->ai_family;
173-
res->ai_flags = k_res->ai_flags;
174-
res->ai_next = NULL;
197+
k_res_musl.ai_family = k_res->ai_family;
198+
k_res_musl.ai_flags = k_res->ai_flags;
199+
k_res_musl.ai_next = NULL;
175200

176201
if (hints != NULL)
177202
{
178203
/* copy socktype & protocol from hints if specified */
179-
res->ai_socktype = hints->ai_socktype;
180-
res->ai_protocol = hints->ai_protocol;
204+
k_res_musl.ai_socktype = k_hints_musl.ai_socktype;
205+
k_res_musl.ai_protocol = k_hints_musl.ai_protocol;
206+
}
207+
208+
#ifdef ARCH_MM_MMU
209+
if (lwp_put_to_user(res, &k_res_musl, sizeof(k_res_musl)) != sizeof(k_res_musl))
210+
{
211+
SET_ERRNO(EFAULT);
212+
ret = -1;
213+
goto exit;
181214
}
215+
#else
216+
*res = k_res_musl;
217+
#endif
182218

183219
sal_freeaddrinfo(k_res);
184220
k_res = NULL;
@@ -215,6 +251,10 @@ sysret_t sys_getaddrinfo(const char *nodename,
215251
{
216252
rt_free(k_hints);
217253
}
254+
if (k_res)
255+
{
256+
sal_freeaddrinfo(k_res);
257+
}
218258

219259
return ret;
220260
}

0 commit comments

Comments
 (0)