Re: ifg_refcnt atomic operation

2021-02-06 Thread Alexander Bluhm
On Sat, Feb 06, 2021 at 04:44:08PM +0100, Alexander Bluhm wrote:
> Or should we go with a self crafted ++ -- refcounting?

This would look like this, also fine with me.  kasserts are also in
refcnt_... API.

ok?

bluhm

Index: net/if.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
retrieving revision 1.626
diff -u -p -r1.626 if.c
--- net/if.c1 Feb 2021 07:43:33 -   1.626
+++ net/if.c6 Feb 2021 16:26:51 -
@@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
return (NULL);
 
strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
-   ifg->ifg_refcnt = 0;
+   ifg->ifg_refcnt = 1;
ifg->ifg_carp_demoted = 0;
TAILQ_INIT(&ifg->ifg_members);
 #if NPF > 0
@@ -2642,13 +2642,18 @@ if_addgroup(struct ifnet *ifp, const cha
if (!strcmp(ifg->ifg_group, groupname))
break;
 
-   if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
+   if (ifg == NULL)
+   ifg = if_creategroup(groupname);
+   else
+   ifg->ifg_refcnt++;
+   KASSERT(ifg->ifg_refcnt != 0);
+
+   if (ifg == NULL) {
free(ifgl, M_TEMP, sizeof(*ifgl));
free(ifgm, M_TEMP, sizeof(*ifgm));
return (ENOMEM);
}
 
-   ifg->ifg_refcnt++;
ifgl->ifgl_group = ifg;
ifgm->ifgm_ifp = ifp;
 
@@ -2692,6 +2697,7 @@ if_delgroup(struct ifnet *ifp, const cha
pfi_group_change(groupname);
 #endif
 
+   KASSERT(ifgl->ifgl_group->ifg_refcnt != 0);
if (--ifgl->ifgl_group->ifg_refcnt == 0) {
TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
 #if NPF > 0
Index: netinet/ip_carp.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.351
diff -u -p -r1.351 ip_carp.c
--- netinet/ip_carp.c   21 Jan 2021 13:18:07 -  1.351
+++ netinet/ip_carp.c   6 Feb 2021 14:45:34 -
@@ -786,10 +786,7 @@ carp_sysctl(int *name, u_int namelen, vo
 void
 carpattach(int n)
 {
-   struct ifg_group*ifg;
-
-   if ((ifg = if_creategroup("carp")) != NULL)
-   ifg->ifg_refcnt++;  /* keep around even if empty */
+   if_creategroup("carp");  /* keep around even if empty */
if_clone_attach(&carp_cloner);
carpcounters = counters_alloc(carps_ncounters);
 }



Re: ifg_refcnt atomic operation

2021-02-06 Thread Alexander Bluhm
On Sat, Feb 06, 2021 at 05:58:35PM +0300, Vitaliy Makkoveev wrote:
> I???m not sure it should be atomic. It seems groups require their own
> lock and this lock should be held while we perform if_addgroup() and
> if_delgroup().

I also think that atomic refcounting is not needed here.  But it
does no harm as adding interface groups is not performance critical.

Question is if we want to use refcnt_... API even if it does more
than required.  Or should we go with a self crafted ++ -- refcounting?

I think the API provides a nicer interface.

bluhm

> However if_creategroup() should set `ifg_refcnt??? to 1
> and carp(4) should not touch groups internals.
> 
> > 
> > Index: net/if.c
> > ===
> > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
> > retrieving revision 1.626
> > diff -u -p -r1.626 if.c
> > --- net/if.c1 Feb 2021 07:43:33 -   1.626
> > +++ net/if.c6 Feb 2021 12:16:20 -
> > @@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
> > return (NULL);
> > 
> > strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
> > -   ifg->ifg_refcnt = 0;
> > +   refcnt_init(&ifg->ifg_refcnt);
> > ifg->ifg_carp_demoted = 0;
> > TAILQ_INIT(&ifg->ifg_members);
> > #if NPF > 0
> > @@ -2642,13 +2642,17 @@ if_addgroup(struct ifnet *ifp, const cha
> > if (!strcmp(ifg->ifg_group, groupname))
> > break;
> > 
> > -   if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
> > +   if (ifg == NULL)
> > +   ifg = if_creategroup(groupname);
> > +   else
> > +   refcnt_take(&ifg->ifg_refcnt);
> > +
> > +   if (ifg == NULL) {
> > free(ifgl, M_TEMP, sizeof(*ifgl));
> > free(ifgm, M_TEMP, sizeof(*ifgm));
> > return (ENOMEM);
> > }
> > 
> > -   ifg->ifg_refcnt++;
> > ifgl->ifgl_group = ifg;
> > ifgm->ifgm_ifp = ifp;
> > 
> > @@ -2692,7 +2696,7 @@ if_delgroup(struct ifnet *ifp, const cha
> > pfi_group_change(groupname);
> > #endif
> > 
> > -   if (--ifgl->ifgl_group->ifg_refcnt == 0) {
> > +   if (refcnt_rele(&ifgl->ifgl_group->ifg_refcnt)) {
> > TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
> > #if NPF > 0
> > pfi_detach_ifgroup(ifgl->ifgl_group);
> > Index: net/if_var.h
> > ===
> > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v
> > retrieving revision 1.112
> > diff -u -p -r1.112 if_var.h
> > --- net/if_var.h29 Jul 2020 12:09:31 -  1.112
> > +++ net/if_var.h6 Feb 2021 12:11:35 -
> > @@ -263,7 +263,7 @@ struct ifmaddr {
> > 
> > struct ifg_group {
> > char ifg_group[IFNAMSIZ];
> > -   u_intifg_refcnt;
> > +   struct refcntifg_refcnt;
> > caddr_t  ifg_pf_kif;
> > int  ifg_carp_demoted;
> > TAILQ_HEAD(, ifg_member) ifg_members;
> > Index: netinet/ip_carp.c
> > ===
> > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_carp.c,v
> > retrieving revision 1.351
> > diff -u -p -r1.351 ip_carp.c
> > --- netinet/ip_carp.c   21 Jan 2021 13:18:07 -  1.351
> > +++ netinet/ip_carp.c   6 Feb 2021 12:11:35 -
> > @@ -786,10 +786,7 @@ carp_sysctl(int *name, u_int namelen, vo
> > void
> > carpattach(int n)
> > {
> > -   struct ifg_group*ifg;
> > -
> > -   if ((ifg = if_creategroup("carp")) != NULL)
> > -   ifg->ifg_refcnt++;  /* keep around even if empty */
> > +   if_creategroup("carp");  /* keep around even if empty */
> > if_clone_attach(&carp_cloner);
> > carpcounters = counters_alloc(carps_ncounters);
> > }
> > 
> 



Re: ifg_refcnt atomic operation

2021-02-06 Thread Vitaliy Makkoveev
> On 6 Feb 2021, at 15:23, Alexander Bluhm  wrote:
> 
> On Sat, Feb 06, 2021 at 05:04:20PM +1000, David Gwynne wrote:
>> refcnt_init starts counting at 1, while the existing code starts at 0. Do
>> the crashes stop because we never fully release all the references and
>> never free it now?
> 
> You are absolutely right.  I was too optimistic.
> 
> Correct diff is below.  It does not fix anything.  Only advantage
> is that carp does not access interface group internals.
> 
> bluhm

I’m not sure it should be atomic. It seems groups require their own
lock and this lock should be held while we perform if_addgroup() and
if_delgroup(). However if_creategroup() should set `ifg_refcnt’ to 1
and carp(4) should not touch groups internals.

> 
> Index: net/if.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
> retrieving revision 1.626
> diff -u -p -r1.626 if.c
> --- net/if.c  1 Feb 2021 07:43:33 -   1.626
> +++ net/if.c  6 Feb 2021 12:16:20 -
> @@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
>   return (NULL);
> 
>   strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
> - ifg->ifg_refcnt = 0;
> + refcnt_init(&ifg->ifg_refcnt);
>   ifg->ifg_carp_demoted = 0;
>   TAILQ_INIT(&ifg->ifg_members);
> #if NPF > 0
> @@ -2642,13 +2642,17 @@ if_addgroup(struct ifnet *ifp, const cha
>   if (!strcmp(ifg->ifg_group, groupname))
>   break;
> 
> - if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
> + if (ifg == NULL)
> + ifg = if_creategroup(groupname);
> + else
> + refcnt_take(&ifg->ifg_refcnt);
> +
> + if (ifg == NULL) {
>   free(ifgl, M_TEMP, sizeof(*ifgl));
>   free(ifgm, M_TEMP, sizeof(*ifgm));
>   return (ENOMEM);
>   }
> 
> - ifg->ifg_refcnt++;
>   ifgl->ifgl_group = ifg;
>   ifgm->ifgm_ifp = ifp;
> 
> @@ -2692,7 +2696,7 @@ if_delgroup(struct ifnet *ifp, const cha
>   pfi_group_change(groupname);
> #endif
> 
> - if (--ifgl->ifgl_group->ifg_refcnt == 0) {
> + if (refcnt_rele(&ifgl->ifgl_group->ifg_refcnt)) {
>   TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
> #if NPF > 0
>   pfi_detach_ifgroup(ifgl->ifgl_group);
> Index: net/if_var.h
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v
> retrieving revision 1.112
> diff -u -p -r1.112 if_var.h
> --- net/if_var.h  29 Jul 2020 12:09:31 -  1.112
> +++ net/if_var.h  6 Feb 2021 12:11:35 -
> @@ -263,7 +263,7 @@ struct ifmaddr {
> 
> struct ifg_group {
>   char ifg_group[IFNAMSIZ];
> - u_intifg_refcnt;
> + struct refcntifg_refcnt;
>   caddr_t  ifg_pf_kif;
>   int  ifg_carp_demoted;
>   TAILQ_HEAD(, ifg_member) ifg_members;
> Index: netinet/ip_carp.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_carp.c,v
> retrieving revision 1.351
> diff -u -p -r1.351 ip_carp.c
> --- netinet/ip_carp.c 21 Jan 2021 13:18:07 -  1.351
> +++ netinet/ip_carp.c 6 Feb 2021 12:11:35 -
> @@ -786,10 +786,7 @@ carp_sysctl(int *name, u_int namelen, vo
> void
> carpattach(int n)
> {
> - struct ifg_group*ifg;
> -
> - if ((ifg = if_creategroup("carp")) != NULL)
> - ifg->ifg_refcnt++;  /* keep around even if empty */
> + if_creategroup("carp");  /* keep around even if empty */
>   if_clone_attach(&carp_cloner);
>   carpcounters = counters_alloc(carps_ncounters);
> }
> 



Re: ifg_refcnt atomic operation

2021-02-06 Thread Alexander Bluhm
On Sat, Feb 06, 2021 at 05:04:20PM +1000, David Gwynne wrote:
> refcnt_init starts counting at 1, while the existing code starts at 0. Do
> the crashes stop because we never fully release all the references and
> never free it now?

You are absolutely right.  I was too optimistic.

Correct diff is below.  It does not fix anything.  Only advantage
is that carp does not access interface group internals.

bluhm

Index: net/if.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
retrieving revision 1.626
diff -u -p -r1.626 if.c
--- net/if.c1 Feb 2021 07:43:33 -   1.626
+++ net/if.c6 Feb 2021 12:16:20 -
@@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
return (NULL);
 
strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
-   ifg->ifg_refcnt = 0;
+   refcnt_init(&ifg->ifg_refcnt);
ifg->ifg_carp_demoted = 0;
TAILQ_INIT(&ifg->ifg_members);
 #if NPF > 0
@@ -2642,13 +2642,17 @@ if_addgroup(struct ifnet *ifp, const cha
if (!strcmp(ifg->ifg_group, groupname))
break;
 
-   if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
+   if (ifg == NULL)
+   ifg = if_creategroup(groupname);
+   else
+   refcnt_take(&ifg->ifg_refcnt);
+
+   if (ifg == NULL) {
free(ifgl, M_TEMP, sizeof(*ifgl));
free(ifgm, M_TEMP, sizeof(*ifgm));
return (ENOMEM);
}
 
-   ifg->ifg_refcnt++;
ifgl->ifgl_group = ifg;
ifgm->ifgm_ifp = ifp;
 
@@ -2692,7 +2696,7 @@ if_delgroup(struct ifnet *ifp, const cha
pfi_group_change(groupname);
 #endif
 
-   if (--ifgl->ifgl_group->ifg_refcnt == 0) {
+   if (refcnt_rele(&ifgl->ifgl_group->ifg_refcnt)) {
TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
 #if NPF > 0
pfi_detach_ifgroup(ifgl->ifgl_group);
Index: net/if_var.h
===
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v
retrieving revision 1.112
diff -u -p -r1.112 if_var.h
--- net/if_var.h29 Jul 2020 12:09:31 -  1.112
+++ net/if_var.h6 Feb 2021 12:11:35 -
@@ -263,7 +263,7 @@ struct ifmaddr {
 
 struct ifg_group {
char ifg_group[IFNAMSIZ];
-   u_intifg_refcnt;
+   struct refcntifg_refcnt;
caddr_t  ifg_pf_kif;
int  ifg_carp_demoted;
TAILQ_HEAD(, ifg_member) ifg_members;
Index: netinet/ip_carp.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.351
diff -u -p -r1.351 ip_carp.c
--- netinet/ip_carp.c   21 Jan 2021 13:18:07 -  1.351
+++ netinet/ip_carp.c   6 Feb 2021 12:11:35 -
@@ -786,10 +786,7 @@ carp_sysctl(int *name, u_int namelen, vo
 void
 carpattach(int n)
 {
-   struct ifg_group*ifg;
-
-   if ((ifg = if_creategroup("carp")) != NULL)
-   ifg->ifg_refcnt++;  /* keep around even if empty */
+   if_creategroup("carp");  /* keep around even if empty */
if_clone_attach(&carp_cloner);
carpcounters = counters_alloc(carps_ncounters);
 }



Re: ifg_refcnt atomic operation

2021-02-05 Thread David Gwynne
refcnt_init starts counting at 1, while the existing code starts at 0. Do
the crashes stop because we never fully release all the references and
never free it now?

On Sat, 6 Feb 2021, 10:55 Alexander Bluhm,  wrote:

> Hi,
>
> When I replace the ++ and -- of ifg_refcnt with an atomic operation,
> it fixes this syzkaller panic.
>
>
> https://syzkaller.appspot.com/bug?id=54e16dc5bce6929e14b42e2f1379f1c18f62be43
>
> Without the fix "syz-execprog -repeat=0 -procs=8 repro-pfi.syz"
> crashes my vmm in a few seconds.  With the diff I cannot reproduce
> for several minutes.
>
> ok?
>
> bluhm
>
> Index: net/if.c
> ===
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.626
> diff -u -p -r1.626 if.c
> --- net/if.c1 Feb 2021 07:43:33 -   1.626
> +++ net/if.c6 Feb 2021 00:37:50 -
> @@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
> return (NULL);
>
> strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
> -   ifg->ifg_refcnt = 0;
> +   refcnt_init(&ifg->ifg_refcnt);
> ifg->ifg_carp_demoted = 0;
> TAILQ_INIT(&ifg->ifg_members);
>  #if NPF > 0
> @@ -2648,7 +2648,7 @@ if_addgroup(struct ifnet *ifp, const cha
> return (ENOMEM);
> }
>
> -   ifg->ifg_refcnt++;
> +   refcnt_take(&ifg->ifg_refcnt);
> ifgl->ifgl_group = ifg;
> ifgm->ifgm_ifp = ifp;
>
> @@ -2692,7 +2692,7 @@ if_delgroup(struct ifnet *ifp, const cha
> pfi_group_change(groupname);
>  #endif
>
> -   if (--ifgl->ifgl_group->ifg_refcnt == 0) {
> +   if (refcnt_rele(&ifgl->ifgl_group->ifg_refcnt)) {
> TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
>  #if NPF > 0
> pfi_detach_ifgroup(ifgl->ifgl_group);
> Index: net/if_var.h
> ===
> RCS file: /cvs/src/sys/net/if_var.h,v
> retrieving revision 1.112
> diff -u -p -r1.112 if_var.h
> --- net/if_var.h29 Jul 2020 12:09:31 -  1.112
> +++ net/if_var.h6 Feb 2021 00:38:23 -
> @@ -263,7 +263,7 @@ struct ifmaddr {
>
>  struct ifg_group {
> char ifg_group[IFNAMSIZ];
> -   u_intifg_refcnt;
> +   struct refcntifg_refcnt;
> caddr_t  ifg_pf_kif;
> int  ifg_carp_demoted;
> TAILQ_HEAD(, ifg_member) ifg_members;
> Index: netinet/ip_carp.c
> ===
> RCS file: /cvs/src/sys/netinet/ip_carp.c,v
> retrieving revision 1.351
> diff -u -p -r1.351 ip_carp.c
> --- netinet/ip_carp.c   21 Jan 2021 13:18:07 -  1.351
> +++ netinet/ip_carp.c   6 Feb 2021 00:39:14 -
> @@ -789,7 +789,7 @@ carpattach(int n)
> struct ifg_group*ifg;
>
> if ((ifg = if_creategroup("carp")) != NULL)
> -   ifg->ifg_refcnt++;  /* keep around even if empty */
> +   refcnt_take(&ifg->ifg_refcnt);  /* keep around even if
> empty */
> if_clone_attach(&carp_cloner);
> carpcounters = counters_alloc(carps_ncounters);
>  }
>
>


ifg_refcnt atomic operation

2021-02-05 Thread Alexander Bluhm
Hi,

When I replace the ++ and -- of ifg_refcnt with an atomic operation,
it fixes this syzkaller panic.

https://syzkaller.appspot.com/bug?id=54e16dc5bce6929e14b42e2f1379f1c18f62be43

Without the fix "syz-execprog -repeat=0 -procs=8 repro-pfi.syz"
crashes my vmm in a few seconds.  With the diff I cannot reproduce
for several minutes.

ok?

bluhm

Index: net/if.c
===
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.626
diff -u -p -r1.626 if.c
--- net/if.c1 Feb 2021 07:43:33 -   1.626
+++ net/if.c6 Feb 2021 00:37:50 -
@@ -2601,7 +2601,7 @@ if_creategroup(const char *groupname)
return (NULL);
 
strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
-   ifg->ifg_refcnt = 0;
+   refcnt_init(&ifg->ifg_refcnt);
ifg->ifg_carp_demoted = 0;
TAILQ_INIT(&ifg->ifg_members);
 #if NPF > 0
@@ -2648,7 +2648,7 @@ if_addgroup(struct ifnet *ifp, const cha
return (ENOMEM);
}
 
-   ifg->ifg_refcnt++;
+   refcnt_take(&ifg->ifg_refcnt);
ifgl->ifgl_group = ifg;
ifgm->ifgm_ifp = ifp;
 
@@ -2692,7 +2692,7 @@ if_delgroup(struct ifnet *ifp, const cha
pfi_group_change(groupname);
 #endif
 
-   if (--ifgl->ifgl_group->ifg_refcnt == 0) {
+   if (refcnt_rele(&ifgl->ifgl_group->ifg_refcnt)) {
TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
 #if NPF > 0
pfi_detach_ifgroup(ifgl->ifgl_group);
Index: net/if_var.h
===
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.112
diff -u -p -r1.112 if_var.h
--- net/if_var.h29 Jul 2020 12:09:31 -  1.112
+++ net/if_var.h6 Feb 2021 00:38:23 -
@@ -263,7 +263,7 @@ struct ifmaddr {
 
 struct ifg_group {
char ifg_group[IFNAMSIZ];
-   u_intifg_refcnt;
+   struct refcntifg_refcnt;
caddr_t  ifg_pf_kif;
int  ifg_carp_demoted;
TAILQ_HEAD(, ifg_member) ifg_members;
Index: netinet/ip_carp.c
===
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.351
diff -u -p -r1.351 ip_carp.c
--- netinet/ip_carp.c   21 Jan 2021 13:18:07 -  1.351
+++ netinet/ip_carp.c   6 Feb 2021 00:39:14 -
@@ -789,7 +789,7 @@ carpattach(int n)
struct ifg_group*ifg;
 
if ((ifg = if_creategroup("carp")) != NULL)
-   ifg->ifg_refcnt++;  /* keep around even if empty */
+   refcnt_take(&ifg->ifg_refcnt);  /* keep around even if empty */
if_clone_attach(&carp_cloner);
carpcounters = counters_alloc(carps_ncounters);
 }