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/inc/trashDir.h src/hg/inc/trashDir.h index b4f19424456..c752ac3e694 100644 --- src/hg/inc/trashDir.h +++ src/hg/inc/trashDir.h @@ -1,26 +1,56 @@ /* trashDir.c - temporary file creation and directory creation in /trash */ /* Copyright (C) 2010 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #ifndef TRASHDIR_H #define TRASHDIR_H #include "portable.h" void trashDirFile(struct tempName *tn, char *dirName, char *base, char *suffix); /* obtain a trash file name trash/dirName/base*.suffix */ void trashDirDateFile(struct tempName *tn, char *dirName, char *base, char *suffix); /* obtain a trash file name trash/dirName.dayOfYear/base*.suffix */ boolean trashDirReusableFile(struct tempName *tn, char *dirName, char *base, char *suffix); /* obtain a resusable trash file name as trash/dirName/base.suffix * returns TRUE if already exists. */ void copyFileToTrash(char **pFileName, char *dirName, char *base, char *suffix); /* If *pFileName is not NULL and exists, then create a new file in the * given dirName of trash/ with the given base and suffix, copy *pFileName's * contents to it, and set *pFileName to the new filename. */ +boolean isTrashPath(char *path); +/* Return TRUE if path names a file inside the trash directory. */ + +boolean isTrashOrSessionDataPath(char *path); +/* Return TRUE if path is under the trash directory, or under one of the durable session-data + * directories that trash files are moved to when a session is saved. This is the allow-list + * isValidBigDataUrl() uses for a bigDataUrl that names a local file. */ + +boolean isServerUserFilePath(char *path); +/* Return TRUE if path is under one of the directories where the server keeps files it made + * for a user: the trash directory, the session-data directories, or a per-feature data + * directory such as myVariantsDataDir. + * + * Use this on any file name that comes back out of the cart before opening, reading, writing + * or deleting it. Cart values are not ours: they arrive from CGI parameters, from an uploaded + * or fetched hgSession file, and from another user's shared session. Note that a trash file + * may itself be a symbolic link pointing at session storage, so a realpath() check is not + * usable here -- sessionDataSaveTrashFile() creates exactly those links on purpose. */ + +boolean isRemoteUrl(char *path); +/* Return TRUE if path is a URL fetched over the network rather than a file name. */ + +boolean isServerUserFileOrUrl(char *path); +/* Return TRUE if path is either a remote URL or a file the server made for a user. + * + * Use this instead of isServerUserFilePath() on the cart variables that legitimately hold + * either one, such as multiRegionsBedUrl and the hgSession load-from-URL name. Both are read + * by code that decides between the two by looking for a protocol and falls through to opening + * a local file, so a value with no protocol has to be one of ours. */ + #endif /* TRASHDIR_H */