On Wed, Jan 26, 2022 at 12:36:31PM +0100, Sebastian Benoit wrote:
> Claudio Jeker(cje...@diehard.n-r-g.com) on 2022.01.26 11:54:41 +0100:
> > On Wed, Jan 26, 2022 at 11:43:25AM +0100, Theo Buehler wrote:
> > > On Wed, Jan 26, 2022 at 10:06:37AM +0100, Claudio Jeker wrote:
> > > > This diff removes the valid/ subdir in favor of a more direct directory
> > > > layout for all valid CA repository files.
> > > > It moves rrdp and rsync to .rsync and .rrdp but keeps ta/ because trust
> > > > anchors are special.
> > > > 
> > > > The biggest change is probably in the FTS code to cleanup the repo since
> > > > the traversing now starts at ".". Apart from that removing valid results
> > > > in some simplified code (esp. in -f mode).
> > > > 
> > > > This diff is mostly from job@, I just did fixed the FTS bits so the
> > > > cleanup works again.
> > > 
> > > If I do a full run with this diff, I run into
> > > 
> > > rpki-client: both possibilities of file present
> > > 
> > > Instrumenting this error (should it include fn?) it turns out to be
> > 
> > Yes, it should show at least one fn.
> > 
> > > pki-repo.registro.br/repo/A2x6icaKpVWP5uUBzJQzRvEpjvS7PV2qt1Ct/1/3230302e3138392e34302e302f32332d3234203d3e20313roa
> > > 
> > > I have not yet figured out why.
> > 
> > Grrrrr. I once hit this but thought it was something that was wrong with
> > some of my other diffs I have around. Need to look into this. It it for
> > sure something that should not happen.
> 
> interestingly, i did not get that.
> 
> diff reads ok to me otherwise.

I added a check to leave empty .rsync and .rrdp dirs behind.
Also the 'both possibilities of file present' error now prints the
filename.  Apart from that this is the same diff.

tb@ did you manage to reproduce this error? I only hit it if I
free(fp->file) first and with that create the use-after-free on the
filename.
-- 
:wq Claudio

Index: parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.54
diff -u -p -r1.54 parser.c
--- parser.c    24 Jan 2022 17:29:37 -0000      1.54
+++ parser.c    25 Jan 2022 16:36:12 -0000
@@ -737,9 +737,9 @@ parse_entity(struct entityq *q, struct m
  * verification.
  */
 static void
-parse_load_crl(const char *uri)
+parse_load_crl(char *uri)
 {
-       char *nfile, *f;
+       char *f;
        size_t flen;
 
        if (uri == NULL)
@@ -750,19 +750,14 @@ parse_load_crl(const char *uri)
        }
        uri += strlen("rsync://");
 
-       if (asprintf(&nfile, "valid/%s", uri) == -1)
-               err(1, NULL);
-
-       f = load_file(nfile, &flen);
+       f = load_file(uri, &flen);
        if (f == NULL) {
-               warn("parse file %s", nfile);
-               goto done;
+               warn("parse file %s", uri);
+               return;
        }
 
-       proc_parser_crl(nfile, f, flen);
+       proc_parser_crl(uri, f, flen);
 
-done:
-       free(nfile);
        free(f);
 }
 
@@ -773,10 +768,10 @@ done:
  * necessary certs were loaded. Returns NULL on failure.
  */
 static struct cert *
-parse_load_cert(const char *uri)
+parse_load_cert(char *uri)
 {
        struct cert *cert = NULL;
-       char *nfile, *f;
+       char *f;
        size_t flen;
 
        if (uri == NULL)
@@ -788,33 +783,28 @@ parse_load_cert(const char *uri)
        }
        uri += strlen("rsync://");
 
-       if (asprintf(&nfile, "valid/%s", uri) == -1)
-               err(1, NULL);
-
-       f = load_file(nfile, &flen);
+       f = load_file(uri, &flen);
        if (f == NULL) {
-               warn("parse file %s", nfile);
+               warn("parse file %s", uri);
                goto done;
        }
 
-       cert = cert_parse(nfile, f, flen);
+       cert = cert_parse(uri, f, flen);
        free(f);
 
        if (cert == NULL)
                goto done;
        if (cert->purpose != CERT_PURPOSE_CA) {
-               warnx("AIA reference to bgpsec cert %s", nfile);
+               warnx("AIA reference to bgpsec cert %s", uri);
                goto done;
        }
        /* try to load the CRL of this cert */
        parse_load_crl(cert->crl);
 
-       free(nfile);
        return cert;
 
-done:
+ done:
        cert_free(cert);
-       free(nfile);
        return NULL;
 }
 
Index: repo.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v
retrieving revision 1.27
diff -u -p -r1.27 repo.c
--- repo.c      24 Jan 2022 15:50:34 -0000      1.27
+++ repo.c      26 Jan 2022 11:48:48 -0000
@@ -224,8 +224,14 @@ repo_dir(const char *uri, const char *di
                        local = uri;
        }
 
-       if (asprintf(&out, "%s/%s", dir, local) == -1)
-               err(1, NULL);
+       if (dir == NULL) {
+               if ((out = strdup(local)) == NULL)
+                       err(1, NULL);
+       } else {
+               if (asprintf(&out, "%s/%s", dir, local) == -1)
+                       err(1, NULL);
+       }
+
        free(hdir);
        return out;
 }
@@ -436,7 +442,7 @@ rsync_get(const char *uri, const char *v
        SLIST_INSERT_HEAD(&rsyncrepos, rr, entry);
 
        rr->repouri = repo;
-       rr->basedir = repo_dir(repo, "rsync", 0);
+       rr->basedir = repo_dir(repo, ".rsync", 0);
 
        /* create base directory */
        if (mkpath(rr->basedir) == -1) {
@@ -484,13 +490,16 @@ rrdp_filename(const struct rrdprepo *rr,
        char *nfile;
        const char *dir = rr->basedir;
 
-       if (valid)
-               dir = "valid";
        if (!valid_uri(uri, strlen(uri), "rsync://"))
                errx(1, "%s: bad URI %s", rr->basedir, uri);
        uri += strlen("rsync://");      /* skip proto */
-       if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
-               err(1, NULL);
+       if (valid) {
+               if ((nfile = strdup(uri)) == NULL)
+                       err(1, NULL);
+       } else {
+               if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
+                       err(1, NULL);
+       }
        return nfile;
 }
 
@@ -734,7 +743,7 @@ rrdp_get(const char *uri)
 
        if ((rr->notifyuri = strdup(uri)) == NULL)
                err(1, NULL);
-       rr->basedir = repo_dir(uri, "rrdp", 1);
+       rr->basedir = repo_dir(uri, ".rrdp", 1);
 
        RB_INIT(&rr->deleted);
 
@@ -1058,7 +1067,7 @@ repo_lookup(int talid, const char *uri, 
        }
 
        rp = repo_alloc(talid);
-       rp->basedir = repo_dir(repouri, "valid", 0);
+       rp->basedir = repo_dir(repouri, NULL, 0);
        rp->repouri = repouri;
        if (notify != NULL)
                if ((rp->notifyuri = strdup(notify)) == NULL)
@@ -1270,42 +1279,40 @@ static void
 repo_move_valid(struct filepath_tree *tree)
 {
        struct filepath *fp, *nfp;
-       size_t rsyncsz = strlen("rsync/");
-       size_t rrdpsz = strlen("rrdp/");
+       size_t rsyncsz = strlen(".rsync/");
+       size_t rrdpsz = strlen(".rrdp/");
        char *fn, *base;
 
        RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) {
-               if (strncmp(fp->file, "rsync/", rsyncsz) != 0 &&
-                   strncmp(fp->file, "rrdp/", rrdpsz) != 0)
+               if (strncmp(fp->file, ".rsync/", rsyncsz) != 0 &&
+                   strncmp(fp->file, ".rrdp/", rrdpsz) != 0)
                        continue; /* not a temporary file path */
 
-               if (strncmp(fp->file, "rsync/", rsyncsz) == 0) {
-                       if (asprintf(&fn, "valid/%s", fp->file + rsyncsz) == -1)
-                               err(1, NULL);
+               if (strncmp(fp->file, ".rsync/", rsyncsz) == 0) {
+                       fn = fp->file + rsyncsz;
                } else {
                        base = strchr(fp->file + rrdpsz, '/');
                        assert(base != NULL);
-                       if (asprintf(&fn, "valid/%s", base + 1) == -1)
-                               err(1, NULL);
+                       fn = base + 1;
                }
 
-               if (repo_mkpath(fn) == -1) {
-                       free(fn);
+               if (repo_mkpath(fn) == -1)
                        continue;
-               }
 
                if (rename(fp->file, fn) == -1) {
                        warn("rename %s", fp->file);
-                       free(fn);
                        continue;
                }
 
                /* switch filepath node to new path */
                RB_REMOVE(filepath_tree, tree, fp);
-               free(fp->file);
-               fp->file = fn;
+               base = fp->file;
+               if ((fp->file = strdup(fn)) == NULL)
+                       err(1, NULL);
+               free(base);
                if (RB_INSERT(filepath_tree, tree, fp) != NULL)
-                       errx(1, "both possibilities of file present");
+                       errx(1, "%s: both possibilities of file present",
+                           fp->file);
        }
 }
 
@@ -1313,12 +1320,20 @@ repo_move_valid(struct filepath_tree *tr
 #define        RSYNC_DIR       (void *)0x73796e63
 #define        RRDP_DIR        (void *)0x52524450
 
+static inline char *
+skip_dotslash(char *in)
+{
+       if (memcmp(in, "./", 2) == 0)
+               return in + 2;
+       return in;
+}
+
 void
 repo_cleanup(struct filepath_tree *tree)
 {
        size_t i, cnt, delsz = 0, dirsz = 0;
        char **del = NULL, **dir = NULL;
-       char *argv[5] = { "ta", "rsync", "rrdp", "valid", NULL };
+       char *argv[2] = { ".", NULL };
        FTS *fts;
        FTSENT *e;
 
@@ -1331,38 +1346,38 @@ repo_cleanup(struct filepath_tree *tree)
                err(1, "fts_open");
        errno = 0;
        while ((e = fts_read(fts)) != NULL) {
+               char *path = skip_dotslash(e->fts_path);
                switch (e->fts_info) {
                case FTS_NSOK:
-                       /* handle rrdp .state files explicitly */
-                       if (e->fts_parent->fts_pointer == RRDP_DIR &&
-                           e->fts_level == 2 &&
-                           strcmp(e->fts_name, ".state") == 0) {
+                       if (filepath_exists(tree, path)) {
                                e->fts_parent->fts_number++;
-                       } else if (filepath_exists(tree, e->fts_path)) {
+                               break;
+                       }
+                       if (e->fts_parent->fts_pointer == RRDP_DIR) {
                                e->fts_parent->fts_number++;
-                       } else if (e->fts_parent->fts_pointer == RRDP_DIR) {
+                               /* handle rrdp .state files explicitly */
+                               if (e->fts_level == 3 &&
+                                   strcmp(e->fts_name, ".state") == 0)
+                                       break;
                                /* can't delete these extra files */
-                               e->fts_parent->fts_number++;
                                stats.extra_files++;
                                if (verbose > 1)
-                                       logx("superfluous %s", e->fts_path);
-                       } else {
-                               if (e->fts_parent->fts_pointer == RSYNC_DIR) {
-                                       /* no need to keep rsync files */
-                                       stats.extra_files++;
-                                       if (verbose > 1)
-                                               logx("superfluous %s",
-                                                   e->fts_path);
-                               }
-                               del = add_to_del(del, &delsz,
-                                   e->fts_path);
+                                       logx("superfluous %s", path);
+                               break;
+                       }
+                       if (e->fts_parent->fts_pointer == RSYNC_DIR) {
+                               /* no need to keep rsync files */
+                               stats.extra_files++;
+                               if (verbose > 1)
+                                       logx("superfluous %s", path);
                        }
+                       del = add_to_del(del, &delsz, path);
                        break;
                case FTS_D:
-                       if (e->fts_level == FTS_ROOTLEVEL) {
-                               if (strcmp("rsync", e->fts_path) == 0)
+                       if (e->fts_level == 1) {
+                               if (strcmp(".rsync", e->fts_name) == 0)
                                        e->fts_pointer = RSYNC_DIR;
-                               else if (strcmp("rrdp", e->fts_path) == 0)
+                               else if (strcmp(".rrdp", e->fts_name) == 0)
                                        e->fts_pointer = RRDP_DIR;
                                else
                                        e->fts_pointer = BASE_DIR;
@@ -1375,35 +1390,40 @@ repo_cleanup(struct filepath_tree *tree)
                         * only if rrdp is active.
                         */
                        if (e->fts_pointer == RRDP_DIR && !noop && rrdpon &&
-                           e->fts_level == 1) {
-                               if (!rrdp_is_active(e->fts_path))
+                           e->fts_level == 2) {
+                               if (!rrdp_is_active(path))
                                        e->fts_pointer = NULL;
                        }
                        break;
                case FTS_DP:
                        if (e->fts_level == FTS_ROOTLEVEL)
                                break;
+                       if (e->fts_level == 1)
+                               /* do not remove .rsync and .rrdp */
+                               if (e->fts_pointer == RRDP_DIR ||
+                                   e->fts_pointer == RSYNC_DIR)
+                                       break;
                        if (e->fts_number == 0)
-                               dir = add_to_del(dir, &dirsz, e->fts_path);
+                               dir = add_to_del(dir, &dirsz, path);
 
                        e->fts_parent->fts_number += e->fts_number;
                        break;
                case FTS_SL:
                case FTS_SLNONE:
-                       warnx("symlink %s", e->fts_path);
-                       del = add_to_del(del, &delsz, e->fts_path);
+                       warnx("symlink %s", path);
+                       del = add_to_del(del, &delsz, path);
                        break;
                case FTS_NS:
                case FTS_ERR:
                        if (e->fts_errno == ENOENT &&
                            e->fts_level == FTS_ROOTLEVEL)
                                continue;
-                       warnx("fts_read %s: %s", e->fts_path,
+                       warnx("fts_read %s: %s", path,
                            strerror(e->fts_errno));
                        break;
                default:
-                       warnx("unhandled[%x] %s", e->fts_info,
-                           e->fts_path);
+                       warnx("fts_read %s: unhandled[%x]", path,
+                           e->fts_info);
                        break;
                }
 

Reply via email to