Skip to content

Commit 8563706

Browse files
committed
net/socket: Bounce recvmsg through kernel buffers for BUILD_KERNEL.
When CONFIG_BUILD_KERNEL is enabled, copy the msghdr iovec snapshot, receive into kernel heap buffers via psock_recvmsg(), then copy payload, sockaddr, and ancillary data back to the user msghdr. This matches recvfrom() and keeps the network stack from writing to user virtual addresses from kernel context. Signed-off-by: Arjav Patel <arjav1528@gmail.com>
1 parent f122df6 commit 8563706

1 file changed

Lines changed: 172 additions & 0 deletions

File tree

net/socket/recvmsg.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@
2828

2929
#include <assert.h>
3030
#include <errno.h>
31+
#include <string.h>
32+
33+
#include <sys/socket.h>
3134

3235
#include <nuttx/cancelpt.h>
3336
#include <nuttx/fs/fs.h>
37+
#include <nuttx/kmalloc.h>
3438
#include <nuttx/net/net.h>
3539

3640
#include "socket/socket.h"
@@ -165,11 +169,139 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
165169
FAR struct socket *psock;
166170
FAR struct file *filep;
167171
ssize_t ret;
172+
#ifdef CONFIG_BUILD_KERNEL
173+
struct msghdr kmsg;
174+
struct msghdr umsg;
175+
FAR struct msghdr *recv_msg = msg;
176+
FAR struct iovec *user_iov = NULL;
177+
FAR struct iovec *kiov = NULL;
178+
FAR uint8_t *kdata = NULL;
179+
FAR void *kname = NULL;
180+
FAR void *kcontrol = NULL;
181+
size_t total_len;
182+
size_t i;
183+
FAR uint8_t *ptr;
184+
ssize_t remaining;
185+
size_t chunk;
186+
#endif
168187

169188
/* recvmsg() is a cancellation point */
170189

171190
enter_cancellation_point();
172191

192+
#ifdef CONFIG_BUILD_KERNEL
193+
/* Receive into kernel buffers, then copy out to the user msghdr (see
194+
* recvfrom()).
195+
*/
196+
197+
memcpy(&umsg, msg, sizeof(struct msghdr));
198+
199+
if (umsg.msg_iov == NULL)
200+
{
201+
ret = -EINVAL;
202+
goto errout_with_cleanup;
203+
}
204+
205+
if (umsg.msg_iovlen > 0)
206+
{
207+
user_iov = kmm_malloc(umsg.msg_iovlen * sizeof(struct iovec));
208+
if (user_iov == NULL)
209+
{
210+
ret = -ENOMEM;
211+
goto errout_with_cleanup;
212+
}
213+
214+
memcpy(user_iov, msg->msg_iov, umsg.msg_iovlen * sizeof(struct iovec));
215+
216+
kiov = kmm_malloc(umsg.msg_iovlen * sizeof(struct iovec));
217+
if (kiov == NULL)
218+
{
219+
ret = -ENOMEM;
220+
goto errout_with_cleanup;
221+
}
222+
223+
total_len = 0;
224+
for (i = 0; i < umsg.msg_iovlen; i++)
225+
{
226+
total_len += user_iov[i].iov_len;
227+
}
228+
229+
if (total_len > 0)
230+
{
231+
kdata = kmm_malloc(total_len);
232+
if (kdata == NULL)
233+
{
234+
ret = -ENOMEM;
235+
goto errout_with_cleanup;
236+
}
237+
238+
ptr = kdata;
239+
for (i = 0; i < umsg.msg_iovlen; i++)
240+
{
241+
if (user_iov[i].iov_len > 0)
242+
{
243+
kiov[i].iov_base = ptr;
244+
kiov[i].iov_len = user_iov[i].iov_len;
245+
ptr += user_iov[i].iov_len;
246+
}
247+
else
248+
{
249+
kiov[i].iov_base = NULL;
250+
kiov[i].iov_len = 0;
251+
}
252+
}
253+
}
254+
else
255+
{
256+
for (i = 0; i < umsg.msg_iovlen; i++)
257+
{
258+
kiov[i].iov_base = NULL;
259+
kiov[i].iov_len = 0;
260+
}
261+
}
262+
}
263+
264+
memcpy(&kmsg, &umsg, sizeof(kmsg));
265+
kmsg.msg_iov = kiov;
266+
kmsg.msg_iovlen = umsg.msg_iovlen;
267+
268+
if (umsg.msg_name != NULL && umsg.msg_namelen > 0)
269+
{
270+
kname = kmm_malloc(umsg.msg_namelen);
271+
if (kname == NULL)
272+
{
273+
ret = -ENOMEM;
274+
goto errout_with_cleanup;
275+
}
276+
277+
kmsg.msg_name = (FAR struct sockaddr *)kname;
278+
}
279+
else
280+
{
281+
kmsg.msg_name = NULL;
282+
kmsg.msg_namelen = 0;
283+
}
284+
285+
if (umsg.msg_control != NULL && umsg.msg_controllen > 0)
286+
{
287+
kcontrol = kmm_malloc(umsg.msg_controllen);
288+
if (kcontrol == NULL)
289+
{
290+
ret = -ENOMEM;
291+
goto errout_with_cleanup;
292+
}
293+
294+
kmsg.msg_control = kcontrol;
295+
}
296+
else
297+
{
298+
kmsg.msg_control = NULL;
299+
kmsg.msg_controllen = 0;
300+
}
301+
302+
recv_msg = &kmsg;
303+
#endif
304+
173305
/* Get the underlying socket structure */
174306

175307
ret = sockfd_socket(sockfd, &filep, &psock);
@@ -178,10 +310,50 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
178310

179311
if (ret == OK)
180312
{
313+
#ifdef CONFIG_BUILD_KERNEL
314+
ret = psock_recvmsg(psock, recv_msg, flags);
315+
#else
181316
ret = psock_recvmsg(psock, msg, flags);
317+
#endif
182318
file_put(filep);
183319
}
184320

321+
#ifdef CONFIG_BUILD_KERNEL
322+
if (ret >= 0)
323+
{
324+
remaining = ret;
325+
for (i = 0; i < umsg.msg_iovlen && remaining > 0; i++)
326+
{
327+
chunk = kiov[i].iov_len < (size_t)remaining ? kiov[i].iov_len :
328+
(size_t)remaining;
329+
memcpy(user_iov[i].iov_base, kiov[i].iov_base, chunk);
330+
remaining -= (ssize_t)chunk;
331+
}
332+
333+
msg->msg_namelen = kmsg.msg_namelen;
334+
if (umsg.msg_name != NULL && kmsg.msg_namelen > 0)
335+
{
336+
memcpy(umsg.msg_name, kname, kmsg.msg_namelen);
337+
}
338+
339+
msg->msg_flags = kmsg.msg_flags;
340+
341+
if (umsg.msg_control != NULL && umsg.msg_controllen > 0)
342+
{
343+
memcpy(umsg.msg_control, kcontrol, kmsg.msg_controllen);
344+
}
345+
346+
msg->msg_controllen = kmsg.msg_controllen;
347+
}
348+
349+
errout_with_cleanup:
350+
kmm_free(kcontrol);
351+
kmm_free(kname);
352+
kmm_free(kdata);
353+
kmm_free(kiov);
354+
kmm_free(user_iov);
355+
#endif
356+
185357
if (ret < 0)
186358
{
187359
set_errno(-ret);

0 commit comments

Comments
 (0)