On Fri, Nov 26, 2021 at 11:37:37PM +0100, Alexandr Nedvedicky wrote:
> Hello,
>
> On Fri, Nov 26, 2021 at 01:01:40PM +0100, Claudio Jeker wrote:
> >
> > One more thing to consider, I think the following test in pfi_set_flags():
> >
> > > + if ((p->pfik_flags_new != p->pfik_flags) &&
> > > + (p->pfik_flagrefs == 0))
> > > + pfi_kif_ref(p, PFI_KIF_REF_FLAG);
> >
> > should actually check for the PFI_IFLAG_SKIP flag and not any flag.
> >
> > if (ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP) &&
> > p->pfik_flagrefs == 0)
> > pfi_kif_ref(p, PFI_KIF_REF_FLAG);
> >
> > Same goes for pfi_clear_flags() just in reverse:
> >
> > > + if ((p->pfik_flags_new != p->pfik_flags) &&
> > > + (p->pfik_flagrefs == 1))
> > > + pfi_kif_unref(p, PFI_KIF_REF_FLAG);
> >
> > Should be changed to:
> > if (!ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP) &&
> > p->pfik_flagrefs == 1)
> > pfi_kif_unref(p, PFI_KIF_REF_FLAG);
> >
> > We only want to track the PFI_IFLAG_SKIP flag but not any other flag like
> > PFI_IFLAG_ANY. At least I think we want to do that, but then I guess
> > pfi_set_flags() should only add a kif
> > if (found == 0 && ISSET(flags, PFI_IFLAG_SKIP))
> >
>
> yes it makes sense.
>
> > I don't really like pfi_set_flags() and pfi_clear_flags()
> > and their ioctls DIOCSETIFFLAG and DIOCCLRIFFLAG. There are no checks for
> > valid flag combinations. So anything goes for these functions.
> > Also should the name check not happen in the ioctl handler and return
> > EINVAL for bad input?
> >
>
> the thing is that empty string acts as a kind of wildcard pfi_skip_if()
> matches anything if 'name' is NULL or empty string. So I'm keeping sanity
> check in pfi_set_flags().
>
> But it it still worth to add test for io == NULL to DIOCSETIFFLAG
> and to DIOCCLRIFFLAG to avoid NULL pointer dereference (NULL->pfiio_name)
>
> updated diff is below.
See comments below.
> +void
> +pfi_group_delmember(const char *group, struct ifnet *ifp)
> +{
> + struct pfi_kif *gkif, *ikif;
> +
> + if ((gkif = pfi_kif_get(group, NULL)) == NULL ||
> + (ikif = pfi_kif_get(ifp->if_xname, NULL)) == NULL)
> + panic("%s: pfi_kif_get failed", __func__);
> + ikif->pfik_flags_new = ikif->pfik_flags & ~gkif->pfik_flags;
> +
> + pfi_group_change(group);
> +}
> +
This function is not quite right. For example:
ifconfig vio0 group foo group bar
pfctl -f - <<EOF
set skip on { foo bar }
block return
EOF
ping -qc2 100.64.1.2
PING 100.64.1.2 (100.64.1.2): 56 data bytes
--- 100.64.1.2 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.153/0.178/0.202/0.024 ms
Now lets remove just group bar from the interface.
ifconfig vio0 -group bar
ping -qc2 100.64.1.2
PING 100.64.1.2 (100.64.1.2): 56 data bytes
ping: sendmsg: Permission denied
ping: wrote 100.64.1.2 64 chars, ret=-1
ping: sendmsg: Permission denied
ping: wrote 100.64.1.2 64 chars, ret=-1
pfi_group_delmember() does not take into consideration other groups
(including the interface itself) that may still allow PFI_IFLAG_SKIP.
It just clears the flag.
I think on delete the flag needs to be recalculated after the group has
been removed. Not sure if this is easy possible though.
> --- a/sys/net/pf_ioctl.c
> +++ b/sys/net/pf_ioctl.c
> @@ -2892,6 +2892,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags,
> struct proc *p)
> case DIOCSETIFFLAG: {
> struct pfioc_iface *io = (struct pfioc_iface *)addr;
>
> + if (io == NULL)
> + return (EINVAL);
I would extend this to also make sure that io->pfiio_flags only sets
PFI_IFLAG_SKIP.
if (io == NULL || io->pfiio_flags & ~PFI_IFLAG_SKIP)
return (EINVAL);
Userland is not allowed to touch PFI_IFLAG_ANY (at least that is my
understanding of the code).
> +
> NET_LOCK();
> PF_LOCK();
> error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
> @@ -2903,6 +2906,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags,
> struct proc *p)
> case DIOCCLRIFFLAG: {
> struct pfioc_iface *io = (struct pfioc_iface *)addr;
>
> + if (io == NULL)
> + return (EINVAL);
Same here.
> +
> NET_LOCK();
> PF_LOCK();
> error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
--
:wq Claudio