Hello,

One of the teams in Oracle Solaris uses sophisticated naming scheme for PF
rulesets. The anchor (ruleset) is identified by something like that:

    root/whatever:component:name/some-virtual-instance-long-name/inbound

That particular team hit a bug in pfctl, when they were trying to load rule to
ruleset specified by anchor above. pfctl(8) on OpenBSD suffers from same
problem:

    echo 'pass'|pfctl -a 
root/whatever:component:name/some-virtual-instance-long-name/inbound -f -
    pfctl: pfctl_add_rule: strlcpy

the command above bails out in pfctl_rules() function at line 1488:

    1481         pf_init_ruleset(rs);
    1482         rs->anchor = pf.anchor;
    1483         if (strlcpy(pf.anchor->path, anchorname,
    1484             sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
    1485                 errx(1, "pfctl_add_rule: strlcpy");
    1486         if (strlcpy(pf.anchor->name, anchorname,
    1487             sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
    1488                 errx(1, "pfctl_add_rule: strlcpy");
    1489 

Looks like pfctl confuses anchorname with anchorpath. The anchorname uses 64B
buffer. Anchorname is a leaf-path component. If we stick to example above, then
anchorname should be '/inbound'.  The snippet above has been fixed by change
below:

    +
    +   if ((p = strrchr(anchorname, '/')) != NULL) {
    +           if (!strlen(p))
    +                   err(1, "pfctl_add_rule: bad anchor name %s",
    +                       anchorname);
    +   } else
    +           p = anchorname;
    +
    +   if (strlcpy(pf.anchor->name, p,

same code already exists in pfctl_add_rule(). After giving a try I hit
a different error:

    pfctl: pfctl_get_ticket: assertion failed

This time game over happened at line 1505:

    1496        if ((opts & PF_OPT_NOACTION) == 0) {
    1497                 /*
    1498                  * XXX For the time being we need to open transactions 
for
    1499                  * the main ruleset before parsing, because tables are 
still
    1500                  * loaded at parse time.
    1501                  */
    1502                 if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
    1503                         ERRX("pfctl_rules");
    1504                 pf.astack[0]->ruleset.tticket =
    1505                     pfctl_get_ticket(t, PF_TRANS_TABLE, anchorname);
    1506         }

After some more debugging I've arrived to pfctl_load_ruleset():

    1340         pf->anchor = rs->anchor;
    1341 
    1342         if (path[0])
    1343                 snprintf(&path[len], PATH_MAX - len, "/%s", 
pf->anchor->name);
    1344         else
    1345                 snprintf(&path[len], PATH_MAX - len, "%s", 
pf->anchor->name);

I think the else branch should be using ->path instead of ->name.
Complete patch is further below. The patch works fine for me (Solaris),
still I'm not quite sure it's 100% correct.

thanks and
regards
sasha

--------8<---------------8<---------------8<------------------8<--------
diff -r 2f5f0295677c src/sbin/pfctl/pfctl.c
--- a/src/sbin/pfctl/pfctl.c    Fri Sep 02 15:53:45 2016 +0200
+++ b/src/sbin/pfctl/pfctl.c    Fri Sep 02 17:31:05 2016 +0200
@@ -1342,7 +1342,7 @@ pfctl_load_ruleset(struct pfctl *pf, cha
        if (path[0])
                snprintf(&path[len], PATH_MAX - len, "/%s", pf->anchor->name);
        else
-               snprintf(&path[len], PATH_MAX - len, "%s", pf->anchor->name);
+               snprintf(&path[len], PATH_MAX - len, "%s", pf->anchor->path);
 
        if (depth) {
                if (TAILQ_FIRST(rs->rules.active.ptr) != NULL) {
@@ -1447,6 +1447,7 @@ pfctl_rules(int dev, char *filename, int
        struct pfr_table         trs;
        char                    *path = NULL;
        int                      osize;
+       char                    *p;
 
        bzero(&pf, sizeof(pf));
        RB_INIT(&pf_anchors);
@@ -1483,7 +1484,15 @@ pfctl_rules(int dev, char *filename, int
        if (strlcpy(pf.anchor->path, anchorname,
            sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
                errx(1, "pfctl_add_rule: strlcpy");
-       if (strlcpy(pf.anchor->name, anchorname,
+
+       if ((p = strrchr(anchorname, '/')) != NULL) {
+               if (!strlen(p))
+                       err(1, "pfctl_add_rule: bad anchor name %s",
+                           anchorname);
+       } else
+               p = anchorname;
+
+       if (strlcpy(pf.anchor->name, p,
            sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
                errx(1, "pfctl_add_rule: strlcpy");
 

Reply via email to