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/hgGene/rnaStructure.c src/hg/hgGene/rnaStructure.c index 2c6d1a59068..de4ef002a20 100644 --- src/hg/hgGene/rnaStructure.c +++ src/hg/hgGene/rnaStructure.c @@ -3,30 +3,31 @@ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include <limits.h> #include "hash.h" #include "linefile.h" #include "jksql.h" #include "rnaFold.h" #include "hui.h" #include "web.h" #include "portable.h" #include "hgGene.h" #include "hgConfig.h" #include "pipeline.h" +#include "trashDir.h" static void rnaTrashDirsInit(char **tables, int count) /* create trash directories if necessary */ { for ( count--; count > -1; count--) mkdirTrashDirectory(tables[count]); } static boolean rnaStructureExists(struct section *section, struct sqlConnection *conn, char *geneId) /* Return TRUE if tables exists and have our gene. */ { if (sqlTableExists(conn, "foldUtr3") && sqlRowExists(conn, "foldUtr3", "name", geneId)) @@ -238,30 +239,37 @@ } else if (sameString(how, "picture")) { char *psFile = cartString(cart, hggMrnaFoldPs); // Sanity check the psFile variable // It should point to a .ps file that exists in the trash/foldUtr5 or foldUtr3 directory. // That means it should match trashDir()/foldUtr[35]/foldUtr[35]_.*\.ps as a regex, // and that the file should exist. if (!endsWith(psFile, ".ps")) { warn("Invalid file provided for creating of RNA structure pdf/image"); return; } + // The prefix tests below match on the front of the name only, so a ".." further along + // would still walk out of the trash directory. isTrashPath refuses that. + if (!isTrashPath(psFile)) + { + warn("Invalid file provided for creating of RNA structure pdf/image"); + return; + } char sanCheck[4096]; safef(sanCheck, sizeof(sanCheck), "%s/foldUtr5/foldUtr5_", trashDir()); if (!startsWith(sanCheck, psFile)) { safef(sanCheck, sizeof(sanCheck), "%s/foldUtr3/foldUtr3_", trashDir()); if (!startsWith(sanCheck, psFile)) { warn("Invalid file provided for creating of RNA structure pdf/image"); return; } } if (!fileExists(psFile)) { warn("Indicated postscript file for RNA structure pdf/image generation does not exist."); return;