On Fri, Oct 22, 2021 at 06:21:44PM +0200, [email protected] wrote:
> >Synopsis:    opening and closeing bpf rapidly causes problems
> >Category:    system
> >Environment:
>       System      : OpenBSD 7.0
>       Details     : OpenBSD 7.0 (GENERIC.MP) #1332: Thu Sep 30 16:53:51 MDT 
> 2021
>                        
> [email protected]:/usr/src/sys/arch/arm64/compile/GENERIC.MP
> 
>       Architecture: OpenBSD.arm64
>       Machine     : arm64
> >Description:
>       Trying to attack a switch on my own network caused my raspberry pi to
> freeze (watchdog rebooted it).  Though after disabling watchdog it just froze.
> Whether there is a panic I could not tell as I'm console-less and my dongle 
> for
> serial doesn't reach the wires to my Pi where it's currently located.  It'd be
> a hardship.  Thankfully I can repeat the problem.  Other thankfulness is it
> can only be done as root in a default system.
> >How-To-Repeat:
> The following program repeats this:
> 
> #include <sys/param.h>
> #include <sys/time.h>
> #include <sys/ioctl.h>
> #include <sys/socket.h>
> 
> #include <net/bpf.h>
> #include <net/if.h>
> 
> #include <errno.h>
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <fcntl.h>
> 
> int open_filter(char *interface);
> 
> int
> main(void)
> {
>       int fd;
> 
>       for (int i = 0; i < 10000; i++) {
>               fd = open_filter("bse0");
>               if (fd < 0)
>                       continue;
>               close(fd);
>       }
> 
>       exit(0);
> }
>               
>               
> 
> 
> /* 
>  * open the bpf devices and attach them to the corresponding interface that
>  * is provided
>  */
> 
> int
> open_filter(char *interface)
> {
>       struct ifreq ifr;
>       char buf[PATH_MAX];
>       int i = 0, fd;
>       u_int hdrcomplete, dltype;
> 
>       do {
>               snprintf(buf, sizeof(buf), "/dev/bpf%d", i++);
>               fd = open(buf, O_RDWR, 0);
>       } while (fd < 0 && errno == EBUSY);
> 
>       if (fd < 0) {
>               perror("open");
>               return -1;
>       }
> 
>       /* set interface on bpf */
>       memset(&ifr, 0, sizeof(ifr));
>       strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name) - 1);
>       if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
>               perror("ioctl 2");
>               close (fd);
>               return -1;
>       }
>       /* write complete frame headers */
>       hdrcomplete=1;
>       if (ioctl(fd, BIOCSHDRCMPLT, &hdrcomplete) < 0) {
>               perror("ioctl 3");
>               return -1;
>       }
>       /* 
>        * If we're not ethernet return with -1 as there is no point opening
>        * bpf for a utility that is a ethernet spoofer
>        */
>       if (ioctl(fd, BIOCGDLT, &dltype) < 0) {
>               perror("ioctl 4");
>               return -1;
>       }
>       if (dltype == DLT_EN10MB) 
>               return (fd);
> 
>       fprintf(stderr, "dltype != DLT_EN10MB, missing -l flag?\n");
> 
>       errno = ENOSYS;
>       close (fd);
>       return -1;
> }
> >Fix:
> None provided.  Unfortunately I don't have a DDB capable console.

Thank you for the report. It looks that the bug is generic and not
specific to the machine.

On amd64, the test program triggers the following:

panic: free: size too large 32768 > 512 (0xffff800005683000) type devbuf
Stopped at      db_enter+0x10:  popq    %rbp
    TID    PID    UID     PRFLAGS     PFLAGS  CPU  COMMAND
 182043  96299      0         0x3          0    3K bpftest
*203812   7765      0     0x14000      0x200    1  smr
db_enter() at db_enter+0x10
panic(ffffffff81e64303) at panic+0xbf
free(ffff800005683000,2,8000) at free+0x409
bpf_d_smr(ffff800005612e00) at bpf_d_smr+0x4f
smr_thread(ffff8000225da548) at smr_thread+0x21e
end trace frame: 0x0, count: 10

The panic happens when freeing bd->bd_fbuf. Curiously, both bd->bd_sbuf
and bd->bd_hbuf are NULL. Also, many calls of ioctl(BIOCSETIF) have
failed with ENOMEM. If bpf_allocbufs() fails, bd->bd_fbuf might be
a dangling pointer.

The following fix seems to help:

Index: net/bpf.c
===================================================================
RCS file: src/sys/net/bpf.c,v
retrieving revision 1.205
diff -u -p -r1.205 bpf.c
--- net/bpf.c   15 Jun 2021 05:24:47 -0000      1.205
+++ net/bpf.c   23 Oct 2021 03:19:56 -0000
@@ -1553,6 +1553,7 @@ bpf_allocbufs(struct bpf_d *d)
        d->bd_sbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT);
        if (d->bd_sbuf == NULL) {
                free(d->bd_fbuf, M_DEVBUF, d->bd_bufsize);
+               d->bd_fbuf = NULL;
                return (ENOMEM);
        }
 

Reply via email to