Disallow adding files with absolute path or traversing upward

(Except as part of srb2home, srb2path or addons_folder --
this lets addons menu work, primarily.)

- disallowed when using addfile or addfolder
- security check for xcmd receive
This commit is contained in:
James R 2022-10-14 17:40:13 -07:00
parent 373af01092
commit b1a86b0b34
3 changed files with 94 additions and 22 deletions

View file

@ -1689,3 +1689,74 @@ const char *D_Home(void)
if (usehome) return userhome;
else return NULL;
}
static boolean check_top_dir(const char **path, const char *top)
{
// empty string does NOT match
if (!strcmp(top, ""))
return false;
if (!startswith(*path, top))
return false;
*path += strlen(top);
// if it doesn't already end with a path separator,
// check if a separator follows
if (!endswith(top, PATHSEP))
{
if (startswith(*path, PATHSEP))
*path += strlen(PATHSEP);
else
return false;
}
return true;
}
static int cmp_strlen_desc(const void *a, const void *b)
{
return ((int)strlen(*(const char*const*)b) - (int)strlen(*(const char*const*)a));
}
boolean D_IsPathAllowed(const char *path)
{
const char *paths[] = {
srb2home,
srb2path,
cv_addons_folder.string
};
const size_t n_paths = sizeof paths / sizeof *paths;
size_t i;
// Sort folder paths by longest to shortest so
// overlapping paths work. E.g.:
// Path 1: /home/james/.srb2/addons
// Path 2: /home/james/.srb2
qsort(paths, n_paths, sizeof *paths, cmp_strlen_desc);
// These paths are allowed to be absolute
// path is offset so ".." can be checked only in the
// rest of the path
for (i = 0; i < n_paths; ++i)
{
if (check_top_dir(&path, paths[i]))
break;
}
// Only if none of the presets matched
if (i == n_paths)
{
// Cannot be an absolute path
if (M_IsPathAbsolute(path))
return false;
}
// Cannot traverse upwards
if (strstr(path, ".."))
return false;
return true;
}

View file

@ -44,6 +44,8 @@ void D_ProcessEvents(void);
const char *D_Home(void);
boolean D_IsPathAllowed(const char *path);
//
// BASE LEVEL
//

View file

@ -7860,8 +7860,10 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
//
static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
static boolean P_LoadAddon(UINT16 numlumps)
{
const UINT16 wadnum = (UINT16)(numwadfiles-1);
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
char *name;
lumpinfo_t *lumpinfo;
@ -7883,6 +7885,12 @@ static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
// UINT16 flaPos, flaNum = 0;
// UINT16 mapPos, mapNum = 0;
if (numlumps == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
switch(wadfiles[wadnum]->type)
{
case RET_PK3:
@ -8051,34 +8059,25 @@ static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
return true;
}
boolean P_AddWadFile(const char *wadfilename)
static boolean P_CheckAddonPath(const char *path)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
if (!D_IsPathAllowed(path))
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Alert(CONS_WARNING, "%s: tried to add file, location is not allowed\n", path);
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
return true;
}
boolean P_AddWadFile(const char *wadfilename)
{
return P_CheckAddonPath(wadfilename) &&
P_LoadAddon(W_InitFile(wadfilename, false, false));
}
boolean P_AddFolder(const char *folderpath)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFolder(folderpath, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
return P_CheckAddonPath(folderpath) &&
P_LoadAddon(W_InitFolder(folderpath, false, false));
}