@@ -174,41 +174,22 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
174174 dest_len = (socklen_t ) ml ;
175175 }
176176
177- if (lmsg .msg_iovlen > 64 ) {
177+ /* msg_iovlen is uint64_t on Linux; bound it against SYSCALL_IOV_MAX
178+ * before the int narrowing below so a 64-bit value whose low 32 bits
179+ * fall inside [0, SYSCALL_IOV_MAX] cannot slip past the cap.
180+ */
181+ if (lmsg .msg_iovlen > SYSCALL_IOV_MAX ) {
178182 host_fd_ref_close (& host_ref );
179183 return - LINUX_EINVAL ;
180184 }
185+ int send_iovcnt = (int ) lmsg .msg_iovlen ;
181186
182- struct {
183- uint64_t iov_base , iov_len ;
184- } guest_iov [64 ];
185-
186- if (lmsg .msg_iovlen > 0 ) {
187- if (guest_read (g , lmsg .msg_iov , guest_iov , lmsg .msg_iovlen * 16 ) < 0 ) {
188- host_fd_ref_close (& host_ref );
189- return - LINUX_EFAULT ;
190- }
191- }
192-
193- struct iovec host_iov [64 ];
194- for (uint64_t i = 0 ; i < lmsg .msg_iovlen ; i ++ ) {
195- if (guest_iov [i ].iov_len == 0 ) {
196- host_iov [i ].iov_base = NULL ;
197- host_iov [i ].iov_len = 0 ;
198- continue ;
199- }
200- uint64_t avail = 0 ;
201- void * base = guest_ptr_bound (g , guest_iov [i ].iov_base , & avail ,
202- MEM_PERM_R , guest_iov [i ].iov_len );
203- if (!base ) {
204- host_fd_ref_close (& host_ref );
205- return - LINUX_EFAULT ;
206- }
207- uint64_t len = guest_iov [i ].iov_len ;
208- if (len > avail )
209- len = avail ;
210- host_iov [i ].iov_base = base ;
211- host_iov [i ].iov_len = len ;
187+ host_iov_buf_t host_iov ;
188+ int64_t iov_err = host_iov_prepare_msg (g , lmsg .msg_iov , send_iovcnt ,
189+ MEM_PERM_R , & host_iov );
190+ if (iov_err < 0 ) {
191+ host_fd_ref_close (& host_ref );
192+ return iov_err ;
212193 }
213194
214195 uint8_t linux_ctrl_stack [512 ], mac_ctrl_stack [512 ];
@@ -223,6 +204,7 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
223204 if (lmsg .msg_control && lmsg .msg_controllen > 0 ) {
224205 size_t clen = lmsg .msg_controllen ;
225206 if (clen > 65536 ) {
207+ host_iov_free (& host_iov );
226208 host_fd_ref_close (& host_ref );
227209 return - LINUX_EINVAL ;
228210 }
@@ -232,6 +214,7 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
232214 if (!linux_ctrl_heap || !mac_ctrl_heap ) {
233215 free (linux_ctrl_heap );
234216 free (mac_ctrl_heap );
217+ host_iov_free (& host_iov );
235218 host_fd_ref_close (& host_ref );
236219 return - LINUX_ENOMEM ;
237220 }
@@ -242,6 +225,7 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
242225 if (guest_read (g , lmsg .msg_control , linux_ctrl , clen ) < 0 ) {
243226 free (linux_ctrl_heap );
244227 free (mac_ctrl_heap );
228+ host_iov_free (& host_iov );
245229 host_fd_ref_close (& host_ref );
246230 return - LINUX_EFAULT ;
247231 }
@@ -300,6 +284,7 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
300284 if (rc < 0 ) {
301285 free (linux_ctrl_heap );
302286 free (mac_ctrl_heap );
287+ host_iov_free (& host_iov );
303288 host_fd_ref_close (& host_ref );
304289 return rc ;
305290 }
@@ -318,8 +303,8 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
318303 struct msghdr msg = {
319304 .msg_name = dest_sa ,
320305 .msg_namelen = dest_len ,
321- .msg_iov = host_iov ,
322- .msg_iovlen = ( int ) lmsg . msg_iovlen ,
306+ .msg_iov = host_iov . iov ,
307+ .msg_iovlen = send_iovcnt ,
323308 .msg_control = ctrl_ptr ,
324309 .msg_controllen = ctrl_len ,
325310 .msg_flags = 0 ,
@@ -328,6 +313,7 @@ int64_t sys_sendmsg(guest_t *g, int fd, uint64_t msg_gva, int linux_flags)
328313 ssize_t ret = sendmsg (host_ref .fd , & msg , mac_flags );
329314 free (linux_ctrl_heap );
330315 free (mac_ctrl_heap );
316+ host_iov_free (& host_iov );
331317 host_fd_ref_close (& host_ref );
332318 if (ret < 0 ) {
333319 if (errno == EPIPE && !suppress_sigpipe )
@@ -410,41 +396,19 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
410396 return ret ;
411397 }
412398
413- if (lmsg .msg_iovlen > 64 ) {
399+ /* See sys_sendmsg above: bound msg_iovlen before the int narrowing. */
400+ if (lmsg .msg_iovlen > SYSCALL_IOV_MAX ) {
414401 host_fd_ref_close (& host_ref );
415402 return - LINUX_EINVAL ;
416403 }
404+ int recv_iovcnt = (int ) lmsg .msg_iovlen ;
417405
418- struct {
419- uint64_t iov_base , iov_len ;
420- } guest_iov [64 ];
421-
422- if (lmsg .msg_iovlen > 0 ) {
423- if (guest_read (g , lmsg .msg_iov , guest_iov , lmsg .msg_iovlen * 16 ) < 0 ) {
424- host_fd_ref_close (& host_ref );
425- return - LINUX_EFAULT ;
426- }
427- }
428-
429- struct iovec host_iov [64 ];
430- for (uint64_t i = 0 ; i < lmsg .msg_iovlen ; i ++ ) {
431- if (guest_iov [i ].iov_len == 0 ) {
432- host_iov [i ].iov_base = NULL ;
433- host_iov [i ].iov_len = 0 ;
434- continue ;
435- }
436- uint64_t avail = 0 ;
437- void * base = guest_ptr_bound (g , guest_iov [i ].iov_base , & avail ,
438- MEM_PERM_W , guest_iov [i ].iov_len );
439- if (!base ) {
440- host_fd_ref_close (& host_ref );
441- return - LINUX_EFAULT ;
442- }
443- uint64_t len = guest_iov [i ].iov_len ;
444- if (len > avail )
445- len = avail ;
446- host_iov [i ].iov_base = base ;
447- host_iov [i ].iov_len = len ;
406+ host_iov_buf_t host_iov ;
407+ int64_t iov_err = host_iov_prepare_msg (g , lmsg .msg_iov , recv_iovcnt ,
408+ MEM_PERM_W , & host_iov );
409+ if (iov_err < 0 ) {
410+ host_fd_ref_close (& host_ref );
411+ return iov_err ;
448412 }
449413
450414 struct sockaddr_storage mac_sa ;
@@ -477,8 +441,8 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
477441 struct msghdr msg = {
478442 .msg_name = lmsg .msg_name ? & mac_sa : NULL ,
479443 .msg_namelen = lmsg .msg_name ? sa_len : 0 ,
480- .msg_iov = host_iov ,
481- .msg_iovlen = ( int ) lmsg . msg_iovlen ,
444+ .msg_iov = host_iov . iov ,
445+ .msg_iovlen = recv_iovcnt ,
482446 .msg_control = ctrl_alloc > 0 ? mac_ctrl : NULL ,
483447 .msg_controllen = ctrl_alloc ,
484448 .msg_flags = 0 ,
@@ -491,6 +455,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
491455 ssize_t ret = recvmsg (host_ref .fd , & msg , mac_flags );
492456 if (ret < 0 ) {
493457 free (mac_ctrl_heap );
458+ host_iov_free (& host_iov );
494459 host_fd_ref_close (& host_ref );
495460 return linux_errno ();
496461 }
@@ -508,6 +473,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
508473 if (guest_write_small (g , lmsg .msg_name , linux_sa , write_len ) <
509474 0 ) {
510475 free (mac_ctrl_heap );
476+ host_iov_free (& host_iov );
511477 host_fd_ref_close (& host_ref );
512478 return - LINUX_EFAULT ;
513479 }
@@ -518,6 +484,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
518484 msg_gva + offsetof(linux_msghdr_t , msg_namelen ),
519485 & nl , sizeof (nl )) < 0 ) {
520486 free (mac_ctrl_heap );
487+ host_iov_free (& host_iov );
521488 host_fd_ref_close (& host_ref );
522489 return - LINUX_EFAULT ;
523490 }
@@ -534,6 +501,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
534501 lctrl_heap = malloc (lctrl_size );
535502 if (!lctrl_heap ) {
536503 free (mac_ctrl_heap );
504+ host_iov_free (& host_iov );
537505 host_fd_ref_close (& host_ref );
538506 return - LINUX_ENOMEM ;
539507 }
@@ -581,6 +549,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
581549 recvmsg_cleanup_scm_rights (scm_gfds , scm_hfds , scm_nfds );
582550 free (lctrl_heap );
583551 free (mac_ctrl_heap );
552+ host_iov_free (& host_iov );
584553 host_fd_ref_close (& host_ref );
585554 return - LINUX_EINVAL ;
586555 }
@@ -654,6 +623,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
654623 recvmsg_cleanup_scm_rights (scm_gfds , scm_hfds , scm_nfds );
655624 free (lctrl_heap );
656625 free (mac_ctrl_heap );
626+ host_iov_free (& host_iov );
657627 host_fd_ref_close (& host_ref );
658628 return - LINUX_EFAULT ;
659629 }
@@ -664,6 +634,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
664634 recvmsg_cleanup_scm_rights (scm_gfds , scm_hfds , scm_nfds );
665635 free (lctrl_heap );
666636 free (mac_ctrl_heap );
637+ host_iov_free (& host_iov );
667638 host_fd_ref_close (& host_ref );
668639 return - LINUX_EFAULT ;
669640 }
@@ -674,6 +645,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
674645 & zero64 , sizeof (zero64 )) < 0 ) {
675646 free (lctrl_heap );
676647 free (mac_ctrl_heap );
648+ host_iov_free (& host_iov );
677649 host_fd_ref_close (& host_ref );
678650 return - LINUX_EFAULT ;
679651 }
@@ -722,6 +694,7 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
722694 g , msg_gva + offsetof(linux_msghdr_t , msg_controllen ), & zero64 ,
723695 sizeof (zero64 )) < 0 ) {
724696 free (mac_ctrl_heap );
697+ host_iov_free (& host_iov );
725698 host_fd_ref_close (& host_ref );
726699 return - LINUX_EFAULT ;
727700 }
@@ -734,11 +707,13 @@ int64_t sys_recvmsg(guest_t *g, int fd, uint64_t msg_gva, int flags)
734707 & mflags , sizeof (mflags )) < 0 ) {
735708 recvmsg_cleanup_scm_rights (scm_gfds , scm_hfds , scm_nfds );
736709 free (mac_ctrl_heap );
710+ host_iov_free (& host_iov );
737711 host_fd_ref_close (& host_ref );
738712 return - LINUX_EFAULT ;
739713 }
740714
741715 free (mac_ctrl_heap );
716+ host_iov_free (& host_iov );
742717 host_fd_ref_close (& host_ref );
743718 return ret ;
744719}
0 commit comments