9ad04e0a0b06ec3c4f09ef1b6c3ce6be79b61c68 braney Sun Aug 16 11:56:56 2026 -0700 cart: validate file names read back out of the cart Several cart variables hold the name of a file the server created for a user. Route them through one shared check, isServerUserFilePath(), which accepts the trash directory, the session-data directories and myVariantsDataDir, and apply it both where values enter the cart and where the file names are used. A few of these variables may instead hold a remote URL. Those get their own list and isServerUserFileOrUrl(), because the code that reads them chooses between a fetch and a local open by looking for a protocol. Consolidates two hand-rolled copies of the same test in blatShare.c and customFactory.c, and drops the weaker private copy in sessionData.c. Adds hg/utils/cartFileVarCatalog, a registry that scans the tree for a cart value reaching a file call and reconciles what it finds against the lists in cart.c, so a new one of these cannot be added without somebody noticing. Its --reconcile is quiet enough for the nightly cron the other catalogs use, and it is what turned up seven of the names now on those lists. refs #37623 diff --git src/hg/lib/dupTrack.c src/hg/lib/dupTrack.c index 9a2caf78f0e..ad69d5c1457 100644 --- src/hg/lib/dupTrack.c +++ src/hg/lib/dupTrack.c @@ -1,27 +1,37 @@ /* Stuff to help handle a track that is a duplicate of a another - sharing data * and type, but having it's own cart settings. */ #include "common.h" #include "hash.h" #include "cart.h" #include "dupTrack.h" #include "ra.h" #include "portable.h" #include "trashDir.h" #include "hgConfig.h" +static char *dupFileNameFromCart(struct cart *cart) +/* Return the name of the trash file holding the dupe track stanzas, or NULL. The value comes + * out of the cart, so only use it if it names a file the server itself made. */ +{ +char *dupFileName = cartUsualString(cart, DUP_TRACKS_VAR, NULL); +if (dupFileName != NULL && !isServerUserFilePath(dupFileName)) + return NULL; +return dupFileName; +} + boolean isDupTrack(char *track) /* determine if track name refers to a custom track */ { return (startsWith(DUP_TRACK_PREFIX, track)); } char *dupTrackSkipToSourceName(char *dupeTrackName) /* If it looks like it's a dupe track then skip over duppy part * in particular skip over dup_N_ form prefix for numerical N. */ { char *name = dupeTrackName; if ((name != NULL ) && startsWith(DUP_TRACK_PREFIX, name)) { char *s = name + strlen(DUP_TRACK_PREFIX); @@ -46,31 +56,31 @@ /* Make up a name of format dup_N_sourceTrack where N is a small unique number */ { int i; for (i=0; ;++i) { makeDupName(sourceName, i, nameBuf, nameBufSize); if (!hashLookup(dupHash, nameBuf)) return; } } char *dupTrackInCartAndTrash(char *sourceTrack, struct cart *cart, struct trackDb *sourceTdb) /* Update cart vars to reflect existance of duplicate of sourceTrack. * Also write out or append to dupe track trash file */ { -char *dupFileName = cartUsualString(cart, DUP_TRACKS_VAR, NULL); +char *dupFileName = dupFileNameFromCart(cart); FILE *f = NULL; // This will be our output /* We keep duplicate's name here. */ int bufSize = strlen(sourceTrack) + 32; char dupeTrackName[bufSize]; makeDupName(sourceTrack, 0, dupeTrackName, sizeof(dupeTrackName)); if (dupFileName != NULL && fileExists(dupFileName)) // Try and read in from old file { /* If there are already duplicates and trash cleaner hasn't nuked file read it in * and make sre we come up with a unique name before we append to existing file */ struct hash *dupHash = raReadAll(dupFileName, "track"); findUniqDupName(sourceTrack, dupHash, dupeTrackName, sizeof(dupeTrackName)); f = mustOpen(dupFileName, "a"); // Append to old file but use new name fputc('\n', f); @@ -116,31 +126,31 @@ cartRemovePrefix(cart, namePlusBuf); namePlusBuf[nameSize] = '_'; cartRemovePrefix(cart, namePlusBuf); } static void dupTracksRemoveAllFromCart(struct cart *cart) /* Remove all trace of dupe tracks from cart */ { cartRemovePrefix(cart, DUP_TRACK_PREFIX); } void undupTrackInCartAndTrash(char *dupName, struct cart *cart) /* Update cart vars to reflect removal of dupTrack. Also reduce or * remove trash file */ { -char *dupFileName = cartUsualString(cart, DUP_TRACKS_VAR, NULL); +char *dupFileName = dupFileNameFromCart(cart); if (dupFileName == NULL) return; // Nothing to do here /* We'll try and create our new list from info in old file */ struct dupTrack *newList = NULL; if (fileExists(dupFileName)) { struct dupTrack *dupList = dupTrackReadAll(dupFileName); /* Turn newList into a copy of dupList with our own stanza removed */ struct dupTrack *dup, *next; for (dup = dupList; dup != NULL; dup = next) { next = dup->next; if (!sameString(dupName, dup->name)) @@ -209,31 +219,31 @@ if (!sameString(tag->name, "track")) { if (sameString(tag->name, "longLabel")) tdb->longLabel = tag->val; else if (sameString(tag->name, "shortLabel")) tdb->shortLabel = tag->val; hashAdd(tdb->settingsHash, tag->name, tag->val); } } } struct dupTrack *dupTrackListFromCart(struct cart *cart) /* Consult cart for dup track variable and if it's there return * list of dupes */ { -char *dupFileName = cartUsualString(cart, DUP_TRACKS_VAR, NULL); +char *dupFileName = dupFileNameFromCart(cart); if (dupFileName == NULL) return NULL; struct dupTrack *list = dupTrackReadAll(dupFileName); if (list == NULL) // Trash cleaner got it, so clean up cart too dupTracksRemoveAllFromCart(cart); return list; } struct dupTrack *dupTrackFindInList(struct dupTrack *list, char *name) /* Return matching element in list */ { struct dupTrack *dup; for (dup = list; dup != NULL; dup = dup->next) if (sameString(dup->name, name)) break;