4040#include "bpf.h"
4141#include "logerr.h"
4242
43- const char * bpf_name = "Berkley Packet Filter" ;
43+ const char * bpf_name = "Berkeley Packet Filter" ;
4444
4545struct bpf *
4646bpf_open (const struct interface * ifp ,
@@ -66,8 +66,6 @@ bpf_open(const struct interface *ifp,
6666 bpf = calloc (1 , sizeof (* bpf ));
6767 if (bpf == NULL )
6868 return NULL ;
69- bpf -> bpf_ifp = ifp ;
70- bpf -> bpf_flags = BPF_EOF ;
7169
7270 /* /dev/bpf is a cloner on modern kernels */
7371 bpf -> bpf_fd = open ("/dev/bpf" , BPF_OPEN_FLAGS );
@@ -86,6 +84,9 @@ bpf_open(const struct interface *ifp,
8684 if (bpf -> bpf_fd == -1 )
8785 goto eexit ;
8886
87+ bpf -> bpf_ifp = ifp ;
88+ bpf -> bpf_flags = BPF_EOF ;
89+
8990#ifndef O_CLOEXEC
9091 if ((fd_opts = fcntl (bpf -> bpf_fd , F_GETFD )) == -1 ||
9192 fcntl (bpf -> bpf_fd , F_SETFD , fd_opts | FD_CLOEXEC ) == -1 )
@@ -125,9 +126,7 @@ bpf_open(const struct interface *ifp,
125126 return bpf ;
126127
127128eexit :
128- if (bpf -> bpf_fd != -1 )
129- close (bpf -> bpf_fd );
130- free (bpf );
129+ bpf_close (bpf );
131130 return NULL ;
132131}
133132
@@ -138,54 +137,67 @@ bpf_read(struct bpf *bpf, void *data, size_t len)
138137{
139138 ssize_t bytes ;
140139 struct bpf_hdr packet ;
141- const char * payload ;
140+ size_t hdr_max ;
141+ const uint8_t * payload ;
142142
143143 bpf -> bpf_flags &= ~BPF_EOF ;
144- for (;;) {
145- if (bpf -> bpf_len == 0 ) {
146- bytes = read (bpf -> bpf_fd , bpf -> bpf_buffer ,
147- bpf -> bpf_size );
148- #if defined(__sun )
149- /* After 2^31 bytes, the kernel offset overflows.
150- * To work around this bug, lseek 0. */
151- if (bytes == -1 && errno == EINVAL ) {
152- lseek (bpf -> bpf_fd , 0 , SEEK_SET );
153- continue ;
154- }
155- #endif
156- if (bytes == -1 || bytes == 0 )
157- return bytes ;
158- bpf -> bpf_len = (size_t )bytes ;
159- bpf -> bpf_pos = 0 ;
144+ if (bpf -> bpf_len == 0 ) {
145+ bytes = read (bpf -> bpf_fd , bpf -> bpf_buffer , bpf -> bpf_size );
146+ #ifdef __sun
147+ /* After 2^31 bytes, the kernel offset overflows.
148+ * To work around this bug, lseek 0. */
149+ if (bytes == -1 && errno == EINVAL ) {
150+ lseek (bpf -> bpf_fd , 0 , SEEK_SET );
151+ return 0 ;
160152 }
161- bytes = -1 ;
162- payload = (const char * )bpf -> bpf_buffer + bpf -> bpf_pos ;
163- memcpy (& packet , payload , sizeof (packet ));
164- if (bpf -> bpf_pos + packet .bh_caplen + packet .bh_hdrlen >
165- bpf -> bpf_len )
166- goto next ; /* Packet beyond buffer, drop. */
167- payload += packet .bh_hdrlen ;
168- if (packet .bh_caplen > len )
169- bytes = (ssize_t )len ;
170- else
171- bytes = (ssize_t )packet .bh_caplen ;
172- if (bpf_frame_bcast (bpf -> bpf_ifp , payload ) == 0 )
173- bpf -> bpf_flags |= BPF_BCAST ;
174- else
175- bpf -> bpf_flags &= ~BPF_BCAST ;
176- memcpy (data , payload , (size_t )bytes );
177- next :
178- bpf -> bpf_pos += BPF_WORDALIGN (
179- packet .bh_hdrlen + packet .bh_caplen );
180- if (bpf -> bpf_pos >= bpf -> bpf_len ) {
181- bpf -> bpf_len = bpf -> bpf_pos = 0 ;
182- bpf -> bpf_flags |= BPF_EOF ;
183- }
184- if (bytes != -1 )
153+ #endif
154+ if (bytes == -1 || bytes == 0 )
185155 return bytes ;
156+ bpf -> bpf_len = (size_t )bytes ;
157+ bpf -> bpf_pos = 0 ;
158+ }
159+
160+ if (bpf -> bpf_pos + sizeof (packet ) > bpf -> bpf_len ) {
161+ errno = EINVAL ;
162+ goto err ;
163+ }
164+
165+ payload = (const uint8_t * )bpf -> bpf_buffer + bpf -> bpf_pos ;
166+ memcpy (& packet , payload , sizeof (packet ));
167+
168+ hdr_max = SIZE_MAX - packet .bh_caplen ;
169+ if (packet .bh_hdrlen > hdr_max ) {
170+ errno = EOVERFLOW ;
171+ goto err ;
172+ }
173+ if (packet .bh_hdrlen + packet .bh_caplen > bpf -> bpf_len - bpf -> bpf_pos ) {
174+ errno = EBADMSG ;
175+ goto err ;
176+ }
177+
178+ payload += packet .bh_hdrlen ;
179+ if (packet .bh_caplen > len )
180+ bytes = (ssize_t )len ;
181+ else
182+ bytes = (ssize_t )packet .bh_caplen ;
183+
184+ if (bpf_frame_bcast (bpf -> bpf_ifp , payload ) == 0 )
185+ bpf -> bpf_flags |= BPF_BCAST ;
186+ else
187+ bpf -> bpf_flags &= ~BPF_BCAST ;
188+ memcpy (data , payload , (size_t )bytes );
189+
190+ bpf -> bpf_pos += BPF_WORDALIGN (packet .bh_hdrlen + packet .bh_caplen );
191+ if (bpf -> bpf_pos >= bpf -> bpf_len ) {
192+ bpf -> bpf_len = bpf -> bpf_pos = 0 ;
193+ bpf -> bpf_flags |= BPF_EOF ;
186194 }
195+ return bytes ;
187196
188- /* NOTREACHED */
197+ err :
198+ bpf -> bpf_len = bpf -> bpf_pos = 0 ;
199+ bpf -> bpf_flags |= BPF_EOF ;
200+ return -1 ;
189201}
190202
191203int
@@ -239,7 +251,8 @@ bpf_writev(const struct bpf *bpf, struct iovec *iov, int iovcnt)
239251void
240252bpf_close (struct bpf * bpf )
241253{
242- close (bpf -> bpf_fd );
254+ if (bpf -> bpf_fd != -1 )
255+ close (bpf -> bpf_fd );
243256 free (bpf -> bpf_buffer );
244257 free (bpf );
245258}
0 commit comments