On Mon, Aug 06, 2018 at 03:50:41PM +0200, Claudio Jeker wrote:
> On Mon, Aug 06, 2018 at 03:34:10PM +0200, Claudio Jeker wrote:
> > On Mon, Aug 06, 2018 at 03:26:16PM +0200, Pierre Emeriaud wrote:
> > > Not sure about this, I guess if you're using 'network bulk add|del'
> > > you're supposed to know what you're doing and not shoot yourself in
> > > the foot, but here it goes:
> > > 
> > > echo | bgpctl network bulk del
> > > crashes bgpd. On 6.3 and current as of today at least.
> > > 
> > > $ doas bgpd -dvf bgpd.conf
> > > startup
> > > rereading config
> > > route decision engine ready
> > > session engine ready
> > > myas = "64751"
> > > ktable_new: rdomain_0 for rtableid 0
> > > listening on 127.0.0.1
> > > SE reconfigured
> > > RDE reconfigured
> > > 
> > > #### bgpd started, time to run 'echo | bgpctl network bulk del'
> > > 
> > > fatal in RDE: pt_fill: unknown af
> > > peer closed imsg connection
> > > main: Lost connection to RDE
> > > peer closed imsg connection
> > > SE: Lost connection to parent
> > > session engine exiting
> > > kernel routing table 0 (Loc-RIB) decoupled
> > > ktable_destroy: freeing ktable Loc-RIB rtableid 0
> > > waiting for children to terminate
> > > terminating
> > > 
> > > 
> > > This somewhat fixes the empty line issue, but it's still possible to
> > > crash with any other string not beeing an ip prefix. A better
> > > workaround would be parse prefixes beforehand, or maybe just don't be
> > > a moron and don't feed bgpctl with anything stupid.
> > > 
> > > Index: bgpctl.c
> > > ===================================================================
> > > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> > > retrieving revision 1.210
> > > diff -u -p -r1.210 bgpctl.c
> > > --- bgpctl.c    29 Jul 2018 13:02:01 -0000      1.210
> > > +++ bgpctl.c    6 Aug 2018 13:11:23 -0000
> > > @@ -1978,6 +1978,9 @@ network_bulk(struct parse_result *res)
> > >                                 /* Don't process commented entries */
> > >                                 if (strchr(b, '#') != NULL)
> > >                                         break;
> > > +                               /* Don't process empty lines */
> > > +                               if (strcmp(b, "\0") == 0)
> > > +                                       break;
> > >                                 bzero(&net, sizeof(net));
> > >                                 parse_prefix(b, strlen(b), &h, &len);
> > >                                 net.prefix = h;
> > > 
> > 
> > Thanks for the diff and the report. I will look into this.
> > 
> 
> Here a diff to protect bgpd a bit better. It uses the same logic as for
> the IMSG_NETWORK_ADD case and does a very basic check of the prefix passed
> in.
> 
> Skipping empty lines in bgpctl is also something we should do but that
> code needs some rework.
> 

I looked at the way we parse those files and I refactored it a fair
amount. I think this new version is more what we actually want.

People using the bulk loading feature (e.g. for bgpd spamd) please test.
-- 
:wq Claudio

Index: bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.210
diff -u -p -r1.210 bgpctl.c
--- bgpctl.c    29 Jul 2018 13:02:01 -0000      1.210
+++ bgpctl.c    7 Aug 2018 08:09:13 -0000
@@ -1956,53 +1956,48 @@ network_bulk(struct parse_result *res)
        struct network_config net;
        struct filter_set *s = NULL;
        struct bgpd_addr h;
-       char *b, *buf, *lbuf;
-       size_t slen;
+       char *line = NULL;
+       size_t linesize = 0;
+       ssize_t linelen;
        u_int8_t len;
        FILE *f;
 
-       if ((f = fdopen(STDIN_FILENO, "r")) != NULL) {
-               while ((buf = fgetln(f, &slen))) {
-                       lbuf = NULL;
-                       if (buf[slen - 1] == '\n')
-                               buf[slen - 1] = '\0';
-                       else {
-                               if ((lbuf = malloc(slen + 1)) == NULL)
-                                       err(1, NULL);
-                               memcpy(lbuf, buf, slen);
-                               lbuf[slen] = '\0';
-                               buf = lbuf;
-                       }
+       if ((f = fdopen(STDIN_FILENO, "r")) == NULL)
+               err(1, "Failed to open stdin\n");
 
-                       while ((b = strsep(&buf, " \t")) != NULL) {
-                               /* Don't process commented entries */
-                               if (strchr(b, '#') != NULL)
-                                       break;
-                               bzero(&net, sizeof(net));
-                               parse_prefix(b, strlen(b), &h, &len);
-                               net.prefix = h;
-                               net.prefixlen = len;
+       while ((linelen = getline(&line, &linesize, f)) != -1) {
+               char *b, *buf = line;
+               while ((b = strsep(&buf, " \t\n")) != NULL) {
+                       if (*b == '\0') /* skip empty tokens */
+                               continue;
+                       /* Stop processing after a comment */
+                       if (*b == '#')
+                               break;
+                       bzero(&net, sizeof(net));
+                       if (parse_prefix(b, strlen(b), &h, &len) != 1)
+                               errx(1, "bad prefix: %s", b);
+                       net.prefix = h;
+                       net.prefixlen = len;
 
-                               if (res->action == NETWORK_BULK_ADD) {
-                                       imsg_compose(ibuf, IMSG_NETWORK_ADD,
-                                           0, 0, -1, &net, sizeof(net));
-                                       TAILQ_FOREACH(s, &res->set, entry) {
-                                               imsg_compose(ibuf,
-                                                   IMSG_FILTER_SET,
-                                                   0, 0, -1, s, sizeof(*s));
-                                       }
-                                       imsg_compose(ibuf, IMSG_NETWORK_DONE,
-                                           0, 0, -1, NULL, 0);
-                               } else
-                                       imsg_compose(ibuf, IMSG_NETWORK_REMOVE,
-                                            0, 0, -1, &net, sizeof(net));
-                       }
-                       free(lbuf);
+                       if (res->action == NETWORK_BULK_ADD) {
+                               imsg_compose(ibuf, IMSG_NETWORK_ADD,
+                                   0, 0, -1, &net, sizeof(net));
+                               TAILQ_FOREACH(s, &res->set, entry) {
+                                       imsg_compose(ibuf,
+                                           IMSG_FILTER_SET,
+                                           0, 0, -1, s, sizeof(*s));
+                               }
+                               imsg_compose(ibuf, IMSG_NETWORK_DONE,
+                                   0, 0, -1, NULL, 0);
+                       } else
+                               imsg_compose(ibuf, IMSG_NETWORK_REMOVE,
+                                    0, 0, -1, &net, sizeof(net));
                }
-               fclose(f);
-       } else {
-               err(1, "Failed to open stdin\n");
        }
+       free(line);
+       if (ferror(f))
+               err(1, "getline");
+       fclose(f);
 }
 
 void

Reply via email to