1a85cdaa59f02695ccecc1aac8a9d40bac188064 max Sun Sep 6 07:10:47 2026 -0700 hgTrackUi: tighten the dataVersion path check, refs #38268 checkDataVersion() decides whether a dataVersion setting that looks like a local path may be opened. Do that test on the path after $D substitution rather than on the raw setting, and accept only a plain path in the /gbdb tree. A quickLifted track no longer needs a case of its own, its file is under /gbdb as well. diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 134c01e9acc..41aba5d4191 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -10789,58 +10789,77 @@ AllocArray(fieldNames, fieldCount); AllocArray(fieldVals, fieldCount); int i; struct slPair *field; for (i=0, field=fields; inext) { char buf[64]; safef(buf, sizeof buf, "$<%s>", field->name); fieldNames[i] = cloneString(buf); fieldVals[i] = (char *)field->val; } struct dyString *fUrl = subMulti(eUrl->string, fieldCount, fieldNames, fieldVals); return fUrl->string; } +static boolean isPublicDataPath(char *path) +/* Return TRUE if path names a file in the /gbdb tree. Only a plain path counts, a ".." + * component makes the name mean something outside that tree, so it is not accepted. */ +{ +if (!startsWith("/gbdb/", path)) + return FALSE; +char *s = path + strlen("/gbdb/"); +while (s != NULL && s[0] != '\0') + { + if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) + return FALSE; + s = strchr(s, '/'); + if (s != NULL) + s += 1; + } +return TRUE; +} + char *checkDataVersion(char *database, struct trackDb *tdb) /* see if trackDb has a dataVersion setting and check that file for version */ { // try the metadata metadataForTable(database, tdb, NULL); char *version = (char *)metadataFindValue(tdb, "dataVersion"); // try trackDb itself, this automatically will go up the hierarchy if (version == NULL) version = trackDbSetting(tdb, "dataVersion"); if (version != NULL && startsWith("/", version)) { // dataVersion can also be the path to a local file, for otto tracks. // For quickLifted tracks the file lives on the source assembly, so // substitute $D using quickLiftDb rather than the destination database. char *liftDb = trackDbSetting(tdb, "quickLiftDb"); char *resolveDb = trackHubSkipHubName(liftDb ? liftDb : database); - // A hub is user-supplied, so a hub track may not name just any local file. - // Paths under /gbdb are the exception: that tree is public data, mirrored on - // hgdownload, so reading one discloses nothing. Curated-hub assemblies need - // this - hs1 and friends are served to the browser as a hub, which makes their - // otto tracks hub tracks, and without it hgTrackUi prints the raw path where - // the version should be. - if (liftDb != NULL || startsWith("/gbdb/", version) || + char *path = replaceInUrl(version, "", NULL, resolveDb, "", 0, 0, tdb->track, FALSE, NULL); + // A hub is user-supplied, so a hub track may not name just any local file. Paths under + // /gbdb are the exception: that tree is public data, mirrored on hgdownload, so reading + // one discloses nothing. Curated-hub assemblies need this - hs1 and friends are served + // to the browser as a hub, which makes their otto tracks hub tracks, and without it + // hgTrackUi prints the raw path where the version should be. quickLifted tracks land + // here too, their dataVersion file is under /gbdb on the source assembly. $D is + // substituted before the test, since on a quickLifted track it comes from the hub. + if (isPublicDataPath(path) || (!trackHubDatabase(database) && !isHubTrack(tdb->table))) { - char *path = replaceInUrl(version, "", NULL, resolveDb, "", 0, 0, tdb->track, FALSE, NULL); struct lineFile* lf = lineFileMayOpen(path, TRUE); if (lf) version = lineFileReadAll(lf); else version = NULL; lineFileClose(&lf); } } return version; } void printDataVersion(char *database, struct trackDb *tdb) /* If this annotation has a dataVersion setting, print it. * check hgFixed.trackVersion, meta data and trackDb 'dataVersion'. */ {