mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 04:46:55 +03:00
vfs/vfs.c: valgrind: fixed read-of-unallocated memory
Comment snippet: We can't just allocate struct dirent as (see man dirent.h) struct dirent has VERY nonnaive semantics of allocating d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_, than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy heap corrupter. So, allocate longliving dirent with at least (NAME_MAX + 1) for d_name in it. Strictly saying resulting dirent is unusable as we don't adjust internal structures, holding dirent size. But we don't use it in libc infrastructure. TODO: to make simpler homemade dirent-alike structure. Signed-off-by: Sergei Trofimovich <slyfox@inbox.ru>
This commit is contained in:
parent
b88147f0c6
commit
27fbf91c28
26
vfs/vfs.c
26
vfs/vfs.c
@ -732,16 +732,32 @@ mc_opendir (const char *dirname)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dirent * mc_readdir_result = NULL;
|
||||||
|
|
||||||
struct dirent *
|
struct dirent *
|
||||||
mc_readdir (DIR *dirp)
|
mc_readdir (DIR *dirp)
|
||||||
{
|
{
|
||||||
int handle;
|
int handle;
|
||||||
struct vfs_class *vfs;
|
struct vfs_class *vfs;
|
||||||
static struct dirent result;
|
|
||||||
struct dirent *entry = NULL;
|
struct dirent *entry = NULL;
|
||||||
struct vfs_dirinfo *dirinfo;
|
struct vfs_dirinfo *dirinfo;
|
||||||
estr_t state;
|
estr_t state;
|
||||||
|
|
||||||
|
if (!mc_readdir_result)
|
||||||
|
{
|
||||||
|
/* We can't just allocate struct dirent as (see man dirent.h)
|
||||||
|
* struct dirent has VERY nonnaive semantics of allocating
|
||||||
|
* d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
|
||||||
|
* than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
|
||||||
|
* heap corrupter. So, allocate longliving dirent with at least
|
||||||
|
* (NAME_MAX + 1) for d_name in it.
|
||||||
|
* Strictly saying resulting dirent is unusable as we don't adjust internal
|
||||||
|
* structures, holding dirent size. But we don't use it in libc infrastructure.
|
||||||
|
* TODO: to make simpler homemade dirent-alike structure.
|
||||||
|
*/
|
||||||
|
mc_readdir_result = (struct dirent *)malloc(sizeof(struct dirent *) + NAME_MAX + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!dirp) {
|
if (!dirp) {
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -757,12 +773,12 @@ mc_readdir (DIR *dirp)
|
|||||||
state = str_vfs_convert_from (dirinfo->converter,
|
state = str_vfs_convert_from (dirinfo->converter,
|
||||||
entry->d_name, vfs_str_buffer);
|
entry->d_name, vfs_str_buffer);
|
||||||
// } while (state != ESTR_SUCCESS);
|
// } while (state != ESTR_SUCCESS);
|
||||||
memcpy (&result, entry, sizeof (struct dirent));
|
|
||||||
g_strlcpy (result.d_name, vfs_str_buffer->str, NAME_MAX + 1);
|
mc_readdir_result->d_ino = entry->d_ino;
|
||||||
result.d_reclen = strlen (result.d_name);
|
g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, NAME_MAX + 1);
|
||||||
}
|
}
|
||||||
if (entry == NULL) errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
|
if (entry == NULL) errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
|
||||||
return (entry != NULL) ? &result : NULL;
|
return (entry != NULL) ? mc_readdir_result : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
Loading…
Reference in New Issue
Block a user