mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
Fix tree.c->tree_get_entry_at() buffer overflow
I observed a crash on buflib>move_block after dumping ram I noticed that the buffer for filetypes was being corrupted tree_get_entry_at returns a entry from the buflib 'tree entry' buffer filetree.c->ft_load writes data to this buffer before checking if it has reached the last entry resulting in buffer overflow that overwrites the next entry in the buffer ['filetypes'] Patch checks that the index passed to tree_get_entry_at() is in range otherwise it returns NULL Added checks + panic in other functions using tree_get_entry_at() Fixed tree_lock_cache() calls in playlist and filetree Change-Id: Ibf9e65652b4e00445e8e509629aebbcddffcfd4d
This commit is contained in:
parent
ce0b31d87d
commit
3f110daf30
4 changed files with 58 additions and 27 deletions
|
@ -137,8 +137,9 @@ static void check_file_thumbnails(struct tree_context* c)
|
||||||
if(!dir)
|
if(!dir)
|
||||||
return;
|
return;
|
||||||
/* mark all files as non talking, except the .talk ones */
|
/* mark all files as non talking, except the .talk ones */
|
||||||
entries = tree_get_entries(c);
|
|
||||||
tree_lock_cache(c);
|
tree_lock_cache(c);
|
||||||
|
entries = tree_get_entries(c);
|
||||||
|
|
||||||
for (i=0; i < c->filesindir; i++)
|
for (i=0; i < c->filesindir; i++)
|
||||||
{
|
{
|
||||||
if (entries[i].attr & ATTR_DIRECTORY)
|
if (entries[i].attr & ATTR_DIRECTORY)
|
||||||
|
|
|
@ -1573,10 +1573,10 @@ static int get_next_dir(char *dir, bool is_forward)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree_lock_cache(tc);
|
||||||
files = tree_get_entries(tc);
|
files = tree_get_entries(tc);
|
||||||
num_files = tc->filesindir;
|
num_files = tc->filesindir;
|
||||||
|
|
||||||
tree_lock_cache(tc);
|
|
||||||
for (i=0; i<num_files; i++)
|
for (i=0; i<num_files; i++)
|
||||||
{
|
{
|
||||||
/* user abort */
|
/* user abort */
|
||||||
|
@ -1666,9 +1666,10 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree_lock_cache(tc);
|
||||||
files = tree_get_entries(tc);
|
files = tree_get_entries(tc);
|
||||||
num_files = tc->filesindir;
|
num_files = tc->filesindir;
|
||||||
|
|
||||||
for (i=0; i<num_files; i++)
|
for (i=0; i<num_files; i++)
|
||||||
{
|
{
|
||||||
if (files[i].attr & ATTR_DIRECTORY)
|
if (files[i].attr & ATTR_DIRECTORY)
|
||||||
|
@ -1681,9 +1682,11 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_music)
|
if (has_music)
|
||||||
|
{
|
||||||
|
tree_unlock_cache(tc);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
tree_lock_cache(tc);
|
|
||||||
if (has_subdir && recurse)
|
if (has_subdir && recurse)
|
||||||
{
|
{
|
||||||
for (i=0; i<num_files; i++)
|
for (i=0; i<num_files; i++)
|
||||||
|
|
69
apps/tree.c
69
apps/tree.c
|
@ -22,6 +22,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "string-extra.h"
|
#include "string-extra.h"
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
#include "applimits.h"
|
#include "applimits.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
@ -111,11 +112,12 @@ struct entry* tree_get_entries(struct tree_context *t)
|
||||||
|
|
||||||
struct entry* tree_get_entry_at(struct tree_context *t, int index)
|
struct entry* tree_get_entry_at(struct tree_context *t, int index)
|
||||||
{
|
{
|
||||||
|
if(index < 0 || index >= t->cache.max_entries)
|
||||||
|
return NULL; /* no entry */
|
||||||
struct entry* entries = tree_get_entries(t);
|
struct entry* entries = tree_get_entries(t);
|
||||||
return &entries[index];
|
return &entries[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char* tree_get_filename(int selected_item, void *data,
|
static const char* tree_get_filename(int selected_item, void *data,
|
||||||
char *buffer, size_t buffer_len)
|
char *buffer, size_t buffer_len)
|
||||||
{
|
{
|
||||||
|
@ -133,9 +135,11 @@ static const char* tree_get_filename(int selected_item, void *data,
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct entry* e = tree_get_entry_at(local_tc, selected_item);
|
struct entry *entry = tree_get_entry_at(local_tc, selected_item);
|
||||||
name = e->name;
|
if (!entry)
|
||||||
attr = e->attr;
|
panicf("Invalid tree entry");
|
||||||
|
name = entry->name;
|
||||||
|
attr = entry->attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(attr & ATTR_DIRECTORY))
|
if(!(attr & ATTR_DIRECTORY))
|
||||||
|
@ -175,8 +179,11 @@ static int tree_get_filecolor(int selected_item, void * data)
|
||||||
if (*tc.dirfilter == SHOW_ID3DB)
|
if (*tc.dirfilter == SHOW_ID3DB)
|
||||||
return -1;
|
return -1;
|
||||||
struct tree_context * local_tc=(struct tree_context *)data;
|
struct tree_context * local_tc=(struct tree_context *)data;
|
||||||
struct entry* e = tree_get_entry_at(local_tc, selected_item);
|
struct entry *entry = tree_get_entry_at(local_tc, selected_item);
|
||||||
return filetype_get_color(e->name, e->attr);
|
if (!entry)
|
||||||
|
panicf("Invalid tree entry");
|
||||||
|
|
||||||
|
return filetype_get_color(entry->name, entry->attr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -191,8 +198,11 @@ static enum themable_icons tree_get_fileicon(int selected_item, void * data)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct entry* e = tree_get_entry_at(local_tc, selected_item);
|
struct entry *entry = tree_get_entry_at(local_tc, selected_item);
|
||||||
return filetype_get_icon(e->attr);
|
if (!entry)
|
||||||
|
panicf("Invalid tree entry");
|
||||||
|
|
||||||
|
return filetype_get_icon(entry->attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +223,12 @@ static int tree_voice_cb(int selected_item, void * data)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct entry* e = tree_get_entry_at(local_tc, selected_item);
|
struct entry *entry = tree_get_entry_at(local_tc, selected_item);
|
||||||
name = e->name;
|
if (!entry)
|
||||||
attr = e->attr;
|
panicf("Invalid tree entry");
|
||||||
|
|
||||||
|
name = entry->name;
|
||||||
|
attr = entry->attr;
|
||||||
}
|
}
|
||||||
bool is_dir = (attr & ATTR_DIRECTORY);
|
bool is_dir = (attr & ATTR_DIRECTORY);
|
||||||
bool did_clip = false;
|
bool did_clip = false;
|
||||||
|
@ -318,17 +331,22 @@ struct tree_context* tree_get_context(void)
|
||||||
*/
|
*/
|
||||||
static int tree_get_file_position(char * filename)
|
static int tree_get_file_position(char * filename)
|
||||||
{
|
{
|
||||||
int i;
|
int i, ret = -1;/* no file match, return undefined */
|
||||||
struct entry* e;
|
|
||||||
|
tree_lock_cache(&tc);
|
||||||
|
struct entry *entries = tree_get_entries(&tc);
|
||||||
|
|
||||||
/* use lastfile to determine the selected item (default=0) */
|
/* use lastfile to determine the selected item (default=0) */
|
||||||
for (i=0; i < tc.filesindir; i++)
|
for (i=0; i < tc.filesindir; i++)
|
||||||
{
|
{
|
||||||
e = tree_get_entry_at(&tc, i);
|
if (!strcasecmp(entries[i].name, filename))
|
||||||
if (!strcasecmp(e->name, filename))
|
{
|
||||||
return(i);
|
ret = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return(-1);/* no file can match, returns undefined */
|
tree_unlock_cache(&tc);
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -527,14 +545,14 @@ char* get_current_file(char* buffer, size_t buffer_len)
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct entry* e = tree_get_entry_at(&tc, tc.selected_item);
|
struct entry *entry = tree_get_entry_at(&tc, tc.selected_item);
|
||||||
if (getcwd(buffer, buffer_len))
|
if (entry && getcwd(buffer, buffer_len))
|
||||||
{
|
{
|
||||||
if (tc.dirlength)
|
if (tc.dirlength)
|
||||||
{
|
{
|
||||||
if (buffer[strlen(buffer)-1] != '/')
|
if (buffer[strlen(buffer)-1] != '/')
|
||||||
strlcat(buffer, "/", buffer_len);
|
strlcat(buffer, "/", buffer_len);
|
||||||
if (strlcat(buffer, e->name, buffer_len) >= buffer_len)
|
if (strlcat(buffer, entry->name, buffer_len) >= buffer_len)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -670,7 +688,11 @@ static int dirbrowse(void)
|
||||||
if ( numentries == 0 )
|
if ( numentries == 0 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
short attr = tree_get_entry_at(&tc, tc.selected_item)->attr;
|
struct entry *entry = tree_get_entry_at(&tc, tc.selected_item);
|
||||||
|
if (!entry)
|
||||||
|
panicf("Invalid tree entry");
|
||||||
|
|
||||||
|
short attr = entry->attr;
|
||||||
if ((tc.browse->flags & BROWSE_SELECTONLY) &&
|
if ((tc.browse->flags & BROWSE_SELECTONLY) &&
|
||||||
!(attr & ATTR_DIRECTORY))
|
!(attr & ATTR_DIRECTORY))
|
||||||
{
|
{
|
||||||
|
@ -798,6 +820,9 @@ static int dirbrowse(void)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct entry *entry = tree_get_entry_at(&tc, tc.selected_item);
|
struct entry *entry = tree_get_entry_at(&tc, tc.selected_item);
|
||||||
|
if (!entry)
|
||||||
|
panicf("Invalid tree entry");
|
||||||
|
|
||||||
attr = entry->attr;
|
attr = entry->attr;
|
||||||
|
|
||||||
if (currdir[1]) /* Not in / */
|
if (currdir[1]) /* Not in / */
|
||||||
|
@ -1017,7 +1042,7 @@ static int move_callback(int handle, void* current, void* new)
|
||||||
if (cache->lock_count > 0)
|
if (cache->lock_count > 0)
|
||||||
return BUFLIB_CB_CANNOT_MOVE;
|
return BUFLIB_CB_CANNOT_MOVE;
|
||||||
|
|
||||||
size_t diff = new - current;
|
ptrdiff_t diff = (int32_t *) new - (int32_t *) current;
|
||||||
/* FIX_PTR makes sure to not accidentally update static allocations */
|
/* FIX_PTR makes sure to not accidentally update static allocations */
|
||||||
#define FIX_PTR(x) \
|
#define FIX_PTR(x) \
|
||||||
{ if ((void*)x >= current && (void*)x < (current+cache->name_buffer_size)) x+= diff; }
|
{ if ((void*)x >= current && (void*)x < (current+cache->name_buffer_size)) x+= diff; }
|
||||||
|
|
|
@ -105,7 +105,9 @@ struct tree_context {
|
||||||
/*
|
/*
|
||||||
* Call one of the two below after yields since the entrys may move inbetween */
|
* Call one of the two below after yields since the entrys may move inbetween */
|
||||||
struct entry* tree_get_entries(struct tree_context *t);
|
struct entry* tree_get_entries(struct tree_context *t);
|
||||||
|
/* returns NULL on invalid index */
|
||||||
struct entry* tree_get_entry_at(struct tree_context *t, int index);
|
struct entry* tree_get_entry_at(struct tree_context *t, int index);
|
||||||
|
|
||||||
void tree_mem_init(void) INIT_ATTR;
|
void tree_mem_init(void) INIT_ATTR;
|
||||||
void tree_gui_init(void) INIT_ATTR;
|
void tree_gui_init(void) INIT_ATTR;
|
||||||
char* get_current_file(char* buffer, size_t buffer_len);
|
char* get_current_file(char* buffer, size_t buffer_len);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue