* grub-core/fs/ufs.c: Remove variable length arrays.

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-10-20 23:07:50 +02:00
parent 1ba6b9b96f
commit 2a40badf82
2 changed files with 150 additions and 127 deletions

View file

@ -1,3 +1,7 @@
2013-10-20 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/ufs.c: Remove variable length arrays.
2013-10-20 Vladimir Serbinenko <phcoder@gmail.com> 2013-10-20 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/ntfs.c: Add comment about fixed allocation size. * grub-core/fs/ntfs.c: Add comment about fixed allocation size.

View file

@ -61,6 +61,22 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define grub_cpu_to_ufs32_compile_time grub_cpu_to_le32_compile_time #define grub_cpu_to_ufs32_compile_time grub_cpu_to_le32_compile_time
#endif #endif
#ifdef MODE_UFS2
typedef grub_uint64_t grub_ufs_blk_t;
static inline grub_disk_addr_t
grub_ufs_to_cpu_blk (grub_ufs_blk_t blk)
{
return grub_ufs_to_cpu64 (blk);
}
#else
typedef grub_uint32_t grub_ufs_blk_t;
static inline grub_disk_addr_t
grub_ufs_to_cpu_blk (grub_ufs_blk_t blk)
{
return grub_ufs_to_cpu32 (blk);
}
#endif
/* Calculate in which group the inode can be found. */ /* Calculate in which group the inode can be found. */
#define UFS_BLKSZ(sblock) (grub_ufs_to_cpu32 (sblock->bsize)) #define UFS_BLKSZ(sblock) (grub_ufs_to_cpu32 (sblock->bsize))
#define UFS_LOG_BLKSZ(sblock) (data->log2_blksz) #define UFS_LOG_BLKSZ(sblock) (data->log2_blksz)
@ -241,7 +257,6 @@ static grub_err_t grub_ufs_find_file (struct grub_ufs_data *data,
static grub_disk_addr_t static grub_disk_addr_t
grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk) grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk)
{ {
struct grub_ufs_sblock *sblock = &data->sblock;
unsigned long indirsz; unsigned long indirsz;
int log2_blksz, log_indirsz; int log2_blksz, log_indirsz;
@ -255,41 +270,35 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk)
log_indirsz = data->log2_blksz - LOG_INODE_BLKSZ; log_indirsz = data->log2_blksz - LOG_INODE_BLKSZ;
indirsz = 1 << log_indirsz; indirsz = 1 << log_indirsz;
/* Single indirect block. */ /* Single indirect block. */
if (blk < indirsz) if (blk < indirsz)
{ {
#ifdef MODE_UFS2 grub_ufs_blk_t indir;
grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
#else
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 0)) ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 0))
<< log2_blksz, << log2_blksz,
0, sizeof (indir), indir); blk * sizeof (indir), sizeof (indir), &indir);
return indir[blk]; return indir;
} }
blk -= indirsz; blk -= indirsz;
/* Double indirect block. */ /* Double indirect block. */
if (blk < (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz) if (blk < (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz)
{ {
#ifdef MODE_UFS2 grub_ufs_blk_t indir;
grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
#else
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 1)) ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 1))
<< log2_blksz, << log2_blksz,
0, sizeof (indir), indir); (blk >> log_indirsz) * sizeof (indir),
sizeof (indir), &indir);
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) indir [blk >> log_indirsz]) grub_ufs_to_cpu_blk (indir) << log2_blksz,
<< log2_blksz, (blk & ((1 << log_indirsz) - 1)) * sizeof (indir),
0, sizeof (indir), indir); sizeof (indir), &indir);
return indir[blk & ((1 << log_indirsz) - 1)]; return indir;
} }
blk -= (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz; blk -= (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz;
@ -297,28 +306,25 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk)
/* Triple indirect block. */ /* Triple indirect block. */
if (!(blk >> (3 * log_indirsz))) if (!(blk >> (3 * log_indirsz)))
{ {
#ifdef MODE_UFS2 grub_ufs_blk_t indir;
grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
#else
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 2)) ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 2))
<< log2_blksz, << log2_blksz,
0, sizeof (indir), indir); (blk >> (2 * log_indirsz)) * sizeof (indir),
sizeof (indir), &indir);
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) indir [blk >> (2 * log_indirsz)]) grub_ufs_to_cpu_blk (indir) << log2_blksz,
<< log2_blksz, ((blk >> log_indirsz)
0, sizeof (indir), indir); & ((1 << log_indirsz) - 1)) * sizeof (indir),
sizeof (indir), &indir);
grub_disk_read (data->disk, grub_disk_read (data->disk,
((grub_disk_addr_t) indir [(blk >> log_indirsz) grub_ufs_to_cpu_blk (indir) << log2_blksz,
& ((1 << log_indirsz) - 1)]) (blk & ((1 << log_indirsz) - 1)) * sizeof (indir),
<< log2_blksz, sizeof (indir), &indir);
0, sizeof (indir), indir);
return indir[blk & ((1 << log_indirsz) - 1)]; return indir;
} }
grub_error (GRUB_ERR_BAD_FS, grub_error (GRUB_ERR_BAD_FS,
@ -441,11 +447,15 @@ grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
static grub_err_t static grub_err_t
grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
{ {
char symlink[INODE_SIZE (data) + 1]; char *symlink;
grub_size_t sz = INODE_SIZE (data);
if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT) if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
return grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks")); return grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks"));
symlink = grub_malloc (sz + 1);
if (!symlink)
return grub_errno;
/* Normally we should just check that data->inode.nblocks == 0. /* Normally we should just check that data->inode.nblocks == 0.
However old Linux doesn't maintain nblocks correctly and so it's always However old Linux doesn't maintain nblocks correctly and so it's always
0. If size is bigger than inline space then the symlink is surely not 0. If size is bigger than inline space then the symlink is surely not
@ -455,8 +465,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
&& INODE_SIZE (data) <= sizeof (data->inode.symlink)) && INODE_SIZE (data) <= sizeof (data->inode.symlink))
grub_strcpy (symlink, (char *) data->inode.symlink); grub_strcpy (symlink, (char *) data->inode.symlink);
else else
grub_ufs_read_file (data, 0, 0, 0, INODE_SIZE (data), symlink); grub_ufs_read_file (data, 0, 0, 0, sz, symlink);
symlink[INODE_SIZE (data)] = '\0'; symlink[sz] = '\0';
/* The symlink is an absolute path, go back to the root inode. */ /* The symlink is an absolute path, go back to the root inode. */
if (symlink[0] == '/') if (symlink[0] == '/')
@ -464,10 +474,15 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
/* Now load in the old inode. */ /* Now load in the old inode. */
if (grub_ufs_read_inode (data, ino, 0)) if (grub_ufs_read_inode (data, ino, 0))
{
grub_free (symlink);
return grub_errno; return grub_errno;
}
grub_ufs_find_file (data, symlink); grub_ufs_find_file (data, symlink);
grub_free (symlink);
return grub_errno; return grub_errno;
} }
@ -477,57 +492,73 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
static grub_err_t static grub_err_t
grub_ufs_find_file (struct grub_ufs_data *data, const char *path) grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
{ {
char fpath[grub_strlen (path) + 1]; const char *name;
char *name = fpath; const char *next = path;
char *next;
unsigned int pos = 0; unsigned int pos = 0;
int dirino; int dirino;
char *filename;
grub_strcpy (fpath, path); /* We reject filenames longer than the one we're looking
for without reading, so this allocation is enough. */
filename = grub_malloc (grub_strlen (path) + 2);
if (!filename)
return grub_errno;
while (1)
{
struct grub_ufs_dirent dirent;
name = next;
/* Skip the first slash. */ /* Skip the first slash. */
while (*name == '/') while (*name == '/')
name++; name++;
if (!*name) if (*name == 0)
return 0;
/* Extract the actual part from the pathname. */
next = grub_strchr (name, '/');
if (next)
{ {
next[0] = '\0'; grub_free (filename);
next++; return GRUB_ERR_NONE;
while (*next == '/')
next++;
} }
do if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
!= GRUB_UFS_ATTR_DIR)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE,
N_("not a directory"));
goto fail;
}
/* Extract the actual part from the pathname. */
for (next = name; *next && *next != '/'; next++);
for (pos = 0; ; pos += grub_ufs_to_cpu16 (dirent.direntlen))
{ {
struct grub_ufs_dirent dirent;
int namelen; int namelen;
if (grub_strlen (name) == 0) if (pos >= INODE_SIZE (data))
return GRUB_ERR_NONE; {
grub_error (GRUB_ERR_FILE_NOT_FOUND,
N_("file `%s' not found"),
path);
goto fail;
}
if (grub_ufs_read_file (data, 0, 0, pos, sizeof (dirent), if (grub_ufs_read_file (data, 0, 0, pos, sizeof (dirent),
(char *) &dirent) < 0) (char *) &dirent) < 0)
return grub_errno; goto fail;
#ifdef MODE_UFS2 #ifdef MODE_UFS2
namelen = dirent.namelen_bsd; namelen = dirent.namelen_bsd;
#else #else
namelen = grub_ufs_to_cpu16 (dirent.namelen); namelen = grub_ufs_to_cpu16 (dirent.namelen);
#endif #endif
{ if (namelen < next - name)
char filename[namelen + 1]; continue;
if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent),
namelen, filename) < 0) next - name + (namelen != next - name),
return grub_errno; filename) < 0)
goto fail;
filename[namelen] = '\0'; if (grub_strncmp (name, filename, next - name) == 0
&& (namelen == next - name || filename[next - name] == '\0'))
if (!grub_strcmp (name, filename))
{ {
dirino = data->ino; dirino = data->ino;
grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0); grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0);
@ -537,35 +568,15 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
{ {
grub_ufs_lookup_symlink (data, dirino); grub_ufs_lookup_symlink (data, dirino);
if (grub_errno) if (grub_errno)
return grub_errno; goto fail;
} }
if (!next) break;
return 0;
pos = 0;
name = next;
next = grub_strchr (name, '/');
if (next)
{
next[0] = '\0';
next++;
while (*next == '/')
next++;
}
if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
continue;
} }
} }
}
pos += grub_ufs_to_cpu16 (dirent.direntlen); fail:
} while (pos < INODE_SIZE (data)); grub_free (filename);
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), path);
return grub_errno; return grub_errno;
} }
@ -672,8 +683,9 @@ grub_ufs_dir (grub_device_t device, const char *path,
namelen = grub_ufs_to_cpu16 (dirent.namelen); namelen = grub_ufs_to_cpu16 (dirent.namelen);
#endif #endif
{ char *filename = grub_malloc (namelen + 1);
char filename[namelen + 1]; if (!filename)
goto fail;
struct grub_dirhook_info info; struct grub_dirhook_info info;
struct grub_ufs_inode inode; struct grub_ufs_inode inode;
@ -681,7 +693,10 @@ grub_ufs_dir (grub_device_t device, const char *path,
if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent),
namelen, filename) < 0) namelen, filename) < 0)
{
grub_free (filename);
break; break;
}
filename[namelen] = '\0'; filename[namelen] = '\0';
grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino),
@ -697,9 +712,13 @@ grub_ufs_dir (grub_device_t device, const char *path,
info.mtimeset = 1; info.mtimeset = 1;
if (hook (filename, &info, hook_data)) if (hook (filename, &info, hook_data))
{
grub_free (filename);
break; break;
} }
grub_free (filename);
pos += grub_ufs_to_cpu16 (dirent.direntlen); pos += grub_ufs_to_cpu16 (dirent.direntlen);
} }