On Sun, Nov 20, 2022 at 02:15:24AM +0100, Alexandr Nedvedicky wrote:
> Hello Olivier,
> 
> thank your for reporting a bug. Patch is always welcomed,
> though I think there is a better way to fix it.
> 
> I was able to reproduce the bug. After adding a 64 groups to
> interface vio0 I was getting 'Bad Address' too.
> 
> On Fri, Nov 18, 2022 at 06:09:38PM +0100, Olivier Croquin wrote:
> </snip>
> > 
> >         In the fix proposed below, I choose arbitrarily to set the
> > pfrb_size to two times the number of interfaces found whith getifaddrs.
> >         Most of the times, it will be too large, but, with this value, we
> > are sure to handle all the interfaces and interfaces groups.
> > 
> >         An other option. The DIOCIGETIFACES ioctl command could behave as
> > DIOCRGETTABLES when the buffer is too small (cf. man pf) :
> >         "f the buffer is too small, the kernel does not store anything but
> > just returns the required buffer size, without error".
> > 
> 
>     the interesting thing is that 'other option' is almost implemented in
>     pf(4) already. Unfortunately there is kind of off-by-one bug. Diff below
>     makes pfctl -sI to work when more than 64 interfaces/interface groups
>     are to be displayed.

Reads fine and works, OK kn.

Limiting output to specific groups/interfaces keeps working as well:

        # ./pfctl -sI -i g64g 
        g64g
        vio0

> 
>     In order to test diff below I create 64 groups for vio0 interface:
> 
>       for i in `seq 64` ; do ifconfig vio0 group g$i\g ; done
> 
>     then I use pfctl -sI to display them. with diff below things do work:
> 
>       netlock# pfctl -sI|wc -l
>             72
>       netlock# 

You might as well turn that into a new regress test.

> does diff below work for you too?
> thank you for giving patch below a try.
> 
> regards
> sashan
> 
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
> index 5c0c32e5961..7966fe9ac51 100644
> --- a/sbin/pfctl/pfctl_table.c
> +++ b/sbin/pfctl/pfctl_table.c
> @@ -583,18 +583,16 @@ pfctl_show_ifaces(const char *filter, int opts)
>  {
>       struct pfr_buffer        b;
>       struct pfi_kif          *p;
> -     int                      i = 0;
>  
>       bzero(&b, sizeof(b));
>       b.pfrb_type = PFRB_IFACES;
>       for (;;) {
> -             pfr_buf_grow(&b, b.pfrb_size);
> +             pfr_buf_grow(&b, 0);
>               b.pfrb_size = b.pfrb_msize;
>               if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size))
>                       errx(1, "%s", pf_strerror(errno));
> -             if (b.pfrb_size <= b.pfrb_msize)
> +             if (b.pfrb_size < b.pfrb_msize)
>                       break;
> -             i++;
>       }
>       if (opts & PF_OPT_SHOWALL)
>               pfctl_print_title("INTERFACES:");
> diff --git a/sys/net/pf_if.c b/sys/net/pf_if.c
> index e23c14e6769..24d37ab4f20 100644
> --- a/sys/net/pf_if.c
> +++ b/sys/net/pf_if.c
> @@ -766,12 +766,13 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, 
> int *size)
>               nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
>               if (pfi_skip_if(name, p))
>                       continue;
> -             if (*size > n++) {
> +             if (*size > ++n) {

You can save the else and one level of indent by doing
                if (*size <= ++n)
                        break;
                ...

>                       if (!p->pfik_tzero)
>                               p->pfik_tzero = gettime();
>                       memcpy(buf++, p, sizeof(*buf));
>                       nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);

This duplicate nextp assignment seems useless.

It's already pointing at the next entry as done in the first line of the
for loop...

which might as well be a simpler RB_FOREACH, avoiding nextp completely.

I can send a follow-up diff for that after you fixed it, or we clean out
the unused i and nextp variables and switch to RB_FOREACH first.

As you like.

> -             }
> +             } else
> +                     break;
>       }
>       *size = n;
>  }
> 

Reply via email to