From 52e22b253d7b7d2419a9fb22e2f40c5aeeaa821d Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Tue, 26 Mar 2024 19:02:09 -0400 Subject: [Bugfix] ft_assemble_path extra slashes, Volume unmound double free Change-Id: Ie2e7702d8e252ce29af0b9dbd2e8d9e892b9ca18 --- apps/filetree.c | 58 ++++++++++++++++++++++++++---------- firmware/common/rb_namespace.c | 19 ++++++------ firmware/include/dircache_redirect.h | 5 ++-- 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/filetree.c b/apps/filetree.c index 4f59804686..66b5c843ca 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -477,41 +477,46 @@ static void ft_apply_skin_file(char *buf, char *file, const int maxlen) int ft_assemble_path(char *buf, size_t bufsz, const char* currdir, const char* filename) { - int len; + size_t len; if (!filename) filename = ""; + #ifdef HAVE_MULTIVOLUME if (currdir && currdir[0] && currdir[1]) /* Not in / */ { if (currdir[1] != VOL_START_TOK) { - len = snprintf(buf, bufsz, "%s%s/%s", root_realpath(), currdir, filename); + len = path_append(buf, root_realpath(), currdir, bufsz); + if (len < bufsz) + len = path_append(buf, buf + len, filename, bufsz - len); } - else - len = snprintf(buf, bufsz, "%s/%s", currdir, filename); + len = path_append(buf, currdir, filename, bufsz); } else /* In / */ { if (filename[0] != VOL_START_TOK) { - len = snprintf(buf, bufsz, "%s/%s",root_realpath(), filename); + len = path_append(buf, root_realpath(), filename, bufsz); } else - len = snprintf(buf, bufsz, "/%s", filename); + len = path_append(buf, PATH_SEPSTR, filename, bufsz); } #else if (currdir && currdir[0] && currdir[1]) /* Not in / */ { - len = snprintf(buf, bufsz, "%s%s/%s", root_realpath(), currdir, filename); + len = path_append(buf, root_realpath(), currdir, bufsz); + if(len < bufsz) + len = path_append(buf, buf + len, filename, bufsz - len); } else /* In / */ { - len = snprintf(buf, bufsz, "%s/%s",root_realpath(), filename); + len = path_append(buf, root_realpath(), filename, bufsz); } #endif - if ((unsigned) len > bufsz) + + if (len > bufsz) splash(HZ, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); - return len; + return (int)len; } int ft_enter(struct tree_context* c) @@ -528,7 +533,6 @@ int ft_enter(struct tree_context* c) int file_attr = file->attr; ft_assemble_path(buf, sizeof(buf), c->currdir, file->name); - if (file_attr & ATTR_DIRECTORY) { memcpy(c->currdir, buf, sizeof(c->currdir)); if ( c->dirlevel < MAX_DIR_LEVELS ) @@ -814,17 +818,39 @@ int ft_exit(struct tree_context* c) extern char lastfile[]; /* from tree.c */ char buf[MAX_PATH]; int rc = 0; - bool exit_func = false; - + bool exit_func = false; int i = strlen(c->currdir); if (i>1) { - while (c->currdir[i-1]!='/') + while (c->currdir[i-1]!=PATH_SEPCH) i--; strcpy(buf,&c->currdir[i]); if (i==1) - c->currdir[i]=0; + c->currdir[i]='\0'; else - c->currdir[i-1]=0; + c->currdir[i-1]='\0'; + +#ifdef HAVE_MULTIVOLUME /* un-redirect the realpath */ + if ((unsigned)c->dirlevel<=2) /* only expect redirect two levels max */ + { + char *currdir = c->currdir; + const char *root = root_realpath(); + int len = i-1; + /* compare to the root path bail if they don't match except single '/' */ + for (; len > 0 && *root != '\0' && *root == *currdir; len--) + { + root++; + currdir++; + } + if (*root == PATH_SEPCH) /* root may have trailing slash */ + root++; + if (*root == '\0' && + (len == 0 || (len == 1 && *currdir == PATH_SEPCH))) + { + strcpy(c->currdir, PATH_ROOTSTR); + c->dirlevel=1; + } + } +#endif if (*c->dirfilter > NUM_FILTER_MODES && c->dirlevel < 1) exit_func = true; diff --git a/firmware/common/rb_namespace.c b/firmware/common/rb_namespace.c index 85f647c474..5069a8681e 100644 --- a/firmware/common/rb_namespace.c +++ b/firmware/common/rb_namespace.c @@ -74,7 +74,7 @@ static void unmount_item(int item) if (!state) return; - if (state & NSITEM_CONTENTS) + if (item == ROOT_CONTENTS_INDEX && state & NSITEM_CONTENTS) { fileobj_unmount(root_bindp); root_bindp = NULL; @@ -139,18 +139,19 @@ int root_mount_path(const char *path, unsigned int flags) int root_state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS)); set_root_item_state(ROOT_CONTENTS_INDEX, root_state); flags |= state; /* preserve the state of the mounted volume */ - if (!folder) - { - folder = ""; - } - else + + if (folder) { + while (*folder == PATH_SEPCH) + folder++; /*if a folder has been enumerated don't mark the whole volume */ - if (folder[0] != '\0' && folder[1] != '\0') + if (folder[0] != '\0') flags &= ~NSITEM_CONTENTS; - + else + folder = NULL; /*Ensure separator is added by path_append */ } - snprintf(root_realpath_internal(), ROOT_MAX_REALPATH,"%s%s", volname, folder); + + path_append(root_realpath_internal(), volname, folder, ROOT_MAX_REALPATH); } else if (state) /* error volume already mounted */ return -EBUSY; diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h index 36f68b7251..f51ce70690 100644 --- a/firmware/include/dircache_redirect.h +++ b/firmware/include/dircache_redirect.h @@ -139,10 +139,8 @@ static inline void fileop_onsync_internal(struct filestr_base *stream) static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) { -#if (defined(HAVE_MULTIVOLUME) || (defined(HAVE_MULTIBOOT) && !defined(BOOTLOADER))) - char path[VOL_MAX_LEN+2]; -#endif #if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER) + char path[VOL_MAX_LEN+2]; char rtpath[MAX_PATH / 2]; make_volume_root(volume, path); @@ -185,6 +183,7 @@ standard_redirect: root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS); } #elif defined(HAVE_MULTIVOLUME) + char path[VOL_MAX_LEN+2]; make_volume_root(volume, path); root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0); if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false)) -- cgit v1.2.3