3131#define TUN_DEV_MAJOR 10
3232#define TUN_DEV_MINOR 200
3333
34+ #define ETH_HEADER_LEN 14
35+
36+ /*
37+ * Read exactly n bytes into the buffer, retrying on partial reads.
38+ * Returns n on success, 0 on clean EOF, or -1 on error.
39+ */
40+ static ssize_t read_exact (int fd , void * buf , size_t n )
41+ {
42+ size_t total = 0 ;
43+
44+ while (total < n ) {
45+ ssize_t r = read (fd , (char * )buf + total , n - total );
46+ if (r < 0 ) {
47+ if (errno == EINTR )
48+ continue ;
49+ return -1 ;
50+ } else if (r == 0 ) {
51+ if (total > 0 ) {
52+ errno = EIO ;
53+ return -1 ;
54+ }
55+ return 0 ;
56+ }
57+ total += r ;
58+ }
59+ return (ssize_t )total ;
60+ }
61+
62+ /*
63+ * Write exactly n bytes from the buffer to the fd, retrying on partial writes.
64+ * Returns n on success, or -1 on error.
65+ */
66+ static ssize_t write_all (int fd , const void * buf , size_t n )
67+ {
68+ size_t total = 0 ;
69+
70+ while (total < n ) {
71+ ssize_t w = write (fd , (const char * )buf + total , n - total );
72+ if (w <= 0 ) {
73+ if (w < 0 && errno == EINTR )
74+ continue ;
75+
76+ if (w == 0 )
77+ errno = EIO ;
78+
79+ return -1 ;
80+ }
81+ total += w ;
82+ }
83+ return (ssize_t )total ;
84+ }
85+
3486/*
3587 * Forward ethernet packets to/from the host vsock providing network access and
3688 * the guest TAP device routing application network traffic.
@@ -43,12 +95,12 @@ static int tap_vsock_forward(int tun_fd, int vsock_fd, int shutdown_fd,
4395 bool event_found ;
4496 struct ifreq ifr ;
4597 int ret , sock_fd ;
46- unsigned int sz ;
98+ uint32_t sz ;
4799 ssize_t nread ;
48100
49101 /*
50102 * Fetch the TAP device's Maximum Transfer Unit (MTU) and allocate a buffer
51- * in that size to transfer ethernet frames to/from the host .
103+ * large enough for a full eth frame (MTU + eth header) .
52104 */
53105 sock_fd = socket (AF_INET , SOCK_DGRAM , 0 );
54106 if (sock_fd < 0 ) {
@@ -68,17 +120,19 @@ static int tap_vsock_forward(int tun_fd, int vsock_fd, int shutdown_fd,
68120
69121 close (sock_fd );
70122
71- buf = (unsigned char * )malloc (ifr .ifr_mtu );
123+ unsigned int buffer_size = ifr .ifr_mtu + ETH_HEADER_LEN ;
124+ buf = (unsigned char * )malloc (buffer_size );
72125 if (buf == NULL ) {
73126 perror ("allocate buffer for TAP/vsock communication" );
74127 exit (-1 );
75128 }
76129
77130 // Forward the MTU to the host for it to allocate a corresponding buffer.
78- ret = write (vsock_fd , (void * )& ifr .ifr_mtu , sizeof (int ));
79- if (ret < sizeof (int )) {
131+ // The host is expecting a 32-bit header.
132+ uint32_t mtu = ifr .ifr_mtu ;
133+ if (write_all (vsock_fd , & mtu , sizeof (mtu )) < 0 ) {
80134 perror ("write TAP device MTU to host" );
81- exit (- errno );
135+ exit (EXIT_FAILURE );
82136 }
83137
84138 pfds [0 ].fd = vsock_fd ;
@@ -97,25 +151,62 @@ static int tap_vsock_forward(int tun_fd, int vsock_fd, int shutdown_fd,
97151 event_found = false;
98152 // Event on vsock. Read the frame and write it to the TAP device.
99153 if (pfds [0 ].revents & POLLIN ) {
100- nread = read (vsock_fd , & sz , 4 );
101- if (nread != 4 )
154+ nread = read_exact (vsock_fd , & sz , sizeof (sz ));
155+ if (nread < 0 ) {
156+ perror ("failure to read header" );
157+ exit (EXIT_FAILURE );
158+ } else if (nread == 0 ) {
159+ // vsock connection is closed
102160 exit (0 );
161+ }
162+
163+ unsigned int len = ntohl (sz );
164+ if (len > buffer_size ) {
165+ fprintf (stderr , "frame size %u exceeds buffer %u\n" , len ,
166+ buffer_size );
167+ exit (EXIT_FAILURE );
168+ }
103169
104- unsigned int len = htonl (sz );
170+ nread = read_exact (vsock_fd , buf , len );
171+ if (nread != (ssize_t )len ) {
172+ if (nread == 0 )
173+ errno = EIO ;
174+ perror ("failure to read from buffer" );
175+ exit (EXIT_FAILURE );
176+ }
105177
106- nread = read (vsock_fd , buf , len );
107- write (tun_fd , buf , nread );
178+ // TAP device is expected to write exactly one eth frame
179+ ssize_t w ;
180+ do {
181+ w = write (tun_fd , buf , nread );
182+ } while (w < 0 && errno == EINTR );
183+
184+ if (w != nread ) {
185+ if (w >= 0 )
186+ errno = EIO ;
187+ perror ("failure to write buffer to tap device" );
188+ exit (EXIT_FAILURE );
189+ }
108190
109191 event_found = true;
110192 }
111193
112194 // Event on the TAP device. Read the frame and write it to the vsock.
113195 if (pfds [1 ].revents & POLLIN ) {
114- nread = read (tun_fd , buf , ifr .ifr_mtu );
196+ do {
197+ nread = read (tun_fd , buf , buffer_size );
198+ } while (nread < 0 && errno == EINTR );
199+
115200 if (nread > 0 ) {
116201 sz = htonl (nread );
117- write (vsock_fd , (void * )& sz , 4 );
118- write (vsock_fd , buf , nread );
202+ if (write_all (vsock_fd , & sz , sizeof (sz )) < 0 ) {
203+ perror ("unable to write header to vsock" );
204+ exit (EXIT_FAILURE );
205+ }
206+ if (write_all (vsock_fd , buf , nread ) < 0 ) {
207+ perror ("unable to write buffer to vsock" );
208+ exit (EXIT_FAILURE );
209+ }
119210 }
120211
121212 event_found = true;
0 commit comments