Skip to content

Commit f122df6

Browse files
committed
net/socket: Copy sendmsg iov into kernel heap for BUILD_KERNEL.
When CONFIG_BUILD_KERNEL is enabled, user-space iovec bases and ancillary pointers must not be dereferenced from the network stack. Mirror the existing sendto() bounce-buffer approach: copy the msghdr fields, iovec array, and payload into kernel memory before calling psock_sendmsg(). This fixes corrupted CAN frames (and similar protocols) where data was copied via memcpy from user VAs during devif_send/iob_trycopyin. Signed-off-by: Arjav Patel <arjav1528@gmail.com>
1 parent 62629d5 commit f122df6

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

net/socket/sendmsg.c

Lines changed: 134 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"
@@ -145,11 +149,129 @@ ssize_t sendmsg(int sockfd, FAR const struct msghdr *msg, int flags)
145149
FAR struct socket *psock;
146150
FAR struct file *filep;
147151
ssize_t ret;
152+
#ifdef CONFIG_BUILD_KERNEL
153+
struct msghdr kmsg;
154+
struct msghdr umsg;
155+
FAR struct iovec *uiov = NULL;
156+
FAR uint8_t *kdata = NULL;
157+
FAR void *kname = NULL;
158+
FAR void *kcontrol = NULL;
159+
FAR const struct msghdr *send_msg = msg;
160+
size_t total_len;
161+
size_t i;
162+
FAR uint8_t *ptr;
163+
#endif
148164

149165
/* sendmsg() is a cancellation point */
150166

151167
enter_cancellation_point();
152168

169+
#ifdef CONFIG_BUILD_KERNEL
170+
/* Copy user msghdr, iovec array, and payload into kernel memory so the
171+
* network stack can safely memcpy from iov bases (see sendto()).
172+
*/
173+
174+
memcpy(&umsg, msg, sizeof(struct msghdr));
175+
176+
if (umsg.msg_iov == NULL)
177+
{
178+
ret = -EINVAL;
179+
goto errout_with_cleanup;
180+
}
181+
182+
if (umsg.msg_iovlen > 0)
183+
{
184+
uiov = kmm_malloc(umsg.msg_iovlen * sizeof(struct iovec));
185+
if (uiov == NULL)
186+
{
187+
ret = -ENOMEM;
188+
goto errout_with_cleanup;
189+
}
190+
191+
memcpy(uiov, msg->msg_iov, umsg.msg_iovlen * sizeof(struct iovec));
192+
193+
total_len = 0;
194+
for (i = 0; i < umsg.msg_iovlen; i++)
195+
{
196+
total_len += uiov[i].iov_len;
197+
}
198+
199+
if (total_len > 0)
200+
{
201+
kdata = kmm_malloc(total_len);
202+
if (kdata == NULL)
203+
{
204+
ret = -ENOMEM;
205+
goto errout_with_cleanup;
206+
}
207+
208+
ptr = kdata;
209+
for (i = 0; i < umsg.msg_iovlen; i++)
210+
{
211+
if (uiov[i].iov_len > 0)
212+
{
213+
memcpy(ptr, uiov[i].iov_base, uiov[i].iov_len);
214+
uiov[i].iov_base = ptr;
215+
ptr += uiov[i].iov_len;
216+
}
217+
else
218+
{
219+
uiov[i].iov_base = NULL;
220+
}
221+
}
222+
}
223+
else
224+
{
225+
for (i = 0; i < umsg.msg_iovlen; i++)
226+
{
227+
uiov[i].iov_base = NULL;
228+
}
229+
}
230+
}
231+
232+
memcpy(&kmsg, &umsg, sizeof(kmsg));
233+
kmsg.msg_iov = uiov;
234+
kmsg.msg_iovlen = umsg.msg_iovlen;
235+
236+
if (umsg.msg_name != NULL && umsg.msg_namelen > 0)
237+
{
238+
kname = kmm_malloc(umsg.msg_namelen);
239+
if (kname == NULL)
240+
{
241+
ret = -ENOMEM;
242+
goto errout_with_cleanup;
243+
}
244+
245+
memcpy(kname, umsg.msg_name, umsg.msg_namelen);
246+
kmsg.msg_name = (FAR struct sockaddr *)kname;
247+
}
248+
else
249+
{
250+
kmsg.msg_name = NULL;
251+
kmsg.msg_namelen = 0;
252+
}
253+
254+
if (umsg.msg_control != NULL && umsg.msg_controllen > 0)
255+
{
256+
kcontrol = kmm_malloc(umsg.msg_controllen);
257+
if (kcontrol == NULL)
258+
{
259+
ret = -ENOMEM;
260+
goto errout_with_cleanup;
261+
}
262+
263+
memcpy(kcontrol, umsg.msg_control, umsg.msg_controllen);
264+
kmsg.msg_control = kcontrol;
265+
}
266+
else
267+
{
268+
kmsg.msg_control = NULL;
269+
kmsg.msg_controllen = 0;
270+
}
271+
272+
send_msg = &kmsg;
273+
#endif
274+
153275
/* Get the underlying socket structure */
154276

155277
ret = sockfd_socket(sockfd, &filep, &psock);
@@ -158,10 +280,22 @@ ssize_t sendmsg(int sockfd, FAR const struct msghdr *msg, int flags)
158280

159281
if (ret == OK)
160282
{
283+
#ifdef CONFIG_BUILD_KERNEL
284+
ret = psock_sendmsg(psock, send_msg, flags);
285+
#else
161286
ret = psock_sendmsg(psock, msg, flags);
287+
#endif
162288
file_put(filep);
163289
}
164290

291+
#ifdef CONFIG_BUILD_KERNEL
292+
errout_with_cleanup:
293+
kmm_free(kcontrol);
294+
kmm_free(kname);
295+
kmm_free(kdata);
296+
kmm_free(uiov);
297+
#endif
298+
165299
if (ret < 0)
166300
{
167301
set_errno(-ret);

0 commit comments

Comments
 (0)