On Fri, Jul 10, 2020 at 01:22:40PM +0200, Martin Pieuchot wrote:
> On 10/07/20(Fri) 14:07, Vitaliy Makkoveev wrote:
> > We have some races in pppac(4)
> > 1. malloc(9) can sleep so we must check `sc' presence after malloc(9)
>
> Makes sense.
>
> > 2. we can sleep between `sc' insertion to `sc_entry' list and
> > `sc_pipex_iface' initialization. Concurrent pppacioctl() can touch
> > this incomplete `sc'.
>
> Why not insert the descriptor at the end? Shouldn't the order of
> operations be:
>
> pipex_iface_init();
> if_attach();
> LIST_INSERT_HEAD()
>
> This way there's no need for a `ready' flag since the descriptor is only
> added to global data structures once it is completely initialized.
>
> Using a `sc_ready' or `sc_dead' approach is something that require
> touching all drivers whereas serializing insertions to global data
> structures can be done at once for all the kernel.
No, because we introduce the races with if_attach(). The similar races
are in if_clone_attach(). We can do multiple `ifp' attachment with the
same name.
---- cut begin ----
int
pppacopen(dev_t dev, int flags, int mode, struct proc *p)
{
sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
ifp = &sc->sc_if;
snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u",
minor(dev));
pipex_iface_init(); /* XXX: can sleep */
if_attach(); /* XXX: can sleep */
LIST_INSERT_HEAD();
}
---- cut end ----
So we insert incomplete `sc' with used `dev' before context switch.
Or if_attach() should check passed `ifp'.