From 2a40badf82c24742c8524687d71f4b8279f06b8a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 20 Oct 2013 23:07:50 +0200 Subject: [PATCH] * grub-core/fs/ufs.c: Remove variable length arrays. --- ChangeLog | 4 + grub-core/fs/ufs.c | 273 ++++++++++++++++++++++++--------------------- 2 files changed, 150 insertions(+), 127 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4d2e9e86..4cc433a3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-10-20 Vladimir Serbinenko + + * grub-core/fs/ufs.c: Remove variable length arrays. + 2013-10-20 Vladimir Serbinenko * grub-core/fs/ntfs.c: Add comment about fixed allocation size. diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index a855f8c45..c9c2556d1 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -61,6 +61,22 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define grub_cpu_to_ufs32_compile_time grub_cpu_to_le32_compile_time #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. */ #define UFS_BLKSZ(sblock) (grub_ufs_to_cpu32 (sblock->bsize)) #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 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; 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; indirsz = 1 << log_indirsz; + /* Single indirect block. */ if (blk < indirsz) { -#ifdef MODE_UFS2 - 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_ufs_blk_t indir; grub_disk_read (data->disk, ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 0)) << log2_blksz, - 0, sizeof (indir), indir); - return indir[blk]; + blk * sizeof (indir), sizeof (indir), &indir); + return indir; } blk -= indirsz; /* Double indirect block. */ if (blk < (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz) { -#ifdef MODE_UFS2 - 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_ufs_blk_t indir; grub_disk_read (data->disk, ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 1)) << log2_blksz, - 0, sizeof (indir), indir); + (blk >> log_indirsz) * sizeof (indir), + sizeof (indir), &indir); grub_disk_read (data->disk, - ((grub_disk_addr_t) indir [blk >> log_indirsz]) - << log2_blksz, - 0, sizeof (indir), indir); + grub_ufs_to_cpu_blk (indir) << log2_blksz, + (blk & ((1 << log_indirsz) - 1)) * sizeof (indir), + sizeof (indir), &indir); - return indir[blk & ((1 << log_indirsz) - 1)]; + return indir; } 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. */ if (!(blk >> (3 * log_indirsz))) { -#ifdef MODE_UFS2 - 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_ufs_blk_t indir; grub_disk_read (data->disk, ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 2)) << log2_blksz, - 0, sizeof (indir), indir); + (blk >> (2 * log_indirsz)) * sizeof (indir), + sizeof (indir), &indir); grub_disk_read (data->disk, - ((grub_disk_addr_t) indir [blk >> (2 * log_indirsz)]) - << log2_blksz, - 0, sizeof (indir), indir); + grub_ufs_to_cpu_blk (indir) << log2_blksz, + ((blk >> log_indirsz) + & ((1 << log_indirsz) - 1)) * sizeof (indir), + sizeof (indir), &indir); grub_disk_read (data->disk, - ((grub_disk_addr_t) indir [(blk >> log_indirsz) - & ((1 << log_indirsz) - 1)]) - << log2_blksz, - 0, sizeof (indir), indir); + grub_ufs_to_cpu_blk (indir) << log2_blksz, + (blk & ((1 << log_indirsz) - 1)) * sizeof (indir), + sizeof (indir), &indir); - return indir[blk & ((1 << log_indirsz) - 1)]; + return indir; } 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 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) 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. 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 @@ -455,8 +465,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) && INODE_SIZE (data) <= sizeof (data->inode.symlink)) grub_strcpy (symlink, (char *) data->inode.symlink); else - grub_ufs_read_file (data, 0, 0, 0, INODE_SIZE (data), symlink); - symlink[INODE_SIZE (data)] = '\0'; + grub_ufs_read_file (data, 0, 0, 0, sz, symlink); + symlink[sz] = '\0'; /* The symlink is an absolute path, go back to the root inode. */ if (symlink[0] == '/') @@ -464,10 +474,15 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) /* Now load in the old inode. */ if (grub_ufs_read_inode (data, ino, 0)) - return grub_errno; + { + grub_free (symlink); + return grub_errno; + } grub_ufs_find_file (data, symlink); + grub_free (symlink); + return grub_errno; } @@ -477,95 +492,91 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) static grub_err_t grub_ufs_find_file (struct grub_ufs_data *data, const char *path) { - char fpath[grub_strlen (path) + 1]; - char *name = fpath; - char *next; + const char *name; + const char *next = path; unsigned int pos = 0; 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; - /* Skip the first slash. */ - while (*name == '/') - name++; - if (!*name) - return 0; - - /* Extract the actual part from the pathname. */ - next = grub_strchr (name, '/'); - if (next) - { - next[0] = '\0'; - next++; - while (*next == '/') - next++; - } - - do + while (1) { struct grub_ufs_dirent dirent; - int namelen; - if (grub_strlen (name) == 0) - return GRUB_ERR_NONE; + name = next; + /* Skip the first slash. */ + while (*name == '/') + name++; + if (*name == 0) + { + grub_free (filename); + return GRUB_ERR_NONE; + } - if (grub_ufs_read_file (data, 0, 0, pos, sizeof (dirent), - (char *) &dirent) < 0) - return grub_errno; + 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)) + { + int namelen; + + if (pos >= INODE_SIZE (data)) + { + 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), + (char *) &dirent) < 0) + goto fail; #ifdef MODE_UFS2 - namelen = dirent.namelen_bsd; + namelen = dirent.namelen_bsd; #else - namelen = grub_ufs_to_cpu16 (dirent.namelen); + namelen = grub_ufs_to_cpu16 (dirent.namelen); #endif - { - char filename[namelen + 1]; - - if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), - namelen, filename) < 0) - return grub_errno; - - filename[namelen] = '\0'; - - if (!grub_strcmp (name, filename)) - { - dirino = data->ino; - grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0); - - if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) - == GRUB_UFS_ATTR_LNK) - { - grub_ufs_lookup_symlink (data, dirino); - if (grub_errno) - return grub_errno; - } - - if (!next) - 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")); - + if (namelen < next - name) continue; - } - } - pos += grub_ufs_to_cpu16 (dirent.direntlen); - } while (pos < INODE_SIZE (data)); + if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), + next - name + (namelen != next - name), + filename) < 0) + goto fail; - grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), path); + if (grub_strncmp (name, filename, next - name) == 0 + && (namelen == next - name || filename[next - name] == '\0')) + { + dirino = data->ino; + grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0); + + if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) + == GRUB_UFS_ATTR_LNK) + { + grub_ufs_lookup_symlink (data, dirino); + if (grub_errno) + goto fail; + } + + break; + } + } + } + fail: + grub_free (filename); return grub_errno; } @@ -672,33 +683,41 @@ grub_ufs_dir (grub_device_t device, const char *path, namelen = grub_ufs_to_cpu16 (dirent.namelen); #endif - { - char filename[namelen + 1]; - struct grub_dirhook_info info; - struct grub_ufs_inode inode; + char *filename = grub_malloc (namelen + 1); + if (!filename) + goto fail; + struct grub_dirhook_info info; + struct grub_ufs_inode inode; - grub_memset (&info, 0, sizeof (info)); + grub_memset (&info, 0, sizeof (info)); - if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), - namelen, filename) < 0) + if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent), + namelen, filename) < 0) + { + grub_free (filename); break; + } - filename[namelen] = '\0'; - grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), - (char *) &inode); + filename[namelen] = '\0'; + grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), + (char *) &inode); - info.dir = ((grub_ufs_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE) - == GRUB_UFS_ATTR_DIR); + info.dir = ((grub_ufs_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE) + == GRUB_UFS_ATTR_DIR); #ifdef MODE_UFS2 - info.mtime = grub_ufs_to_cpu64 (inode.mtime); + info.mtime = grub_ufs_to_cpu64 (inode.mtime); #else - info.mtime = grub_ufs_to_cpu32 (inode.mtime); + info.mtime = grub_ufs_to_cpu32 (inode.mtime); #endif - info.mtimeset = 1; + info.mtimeset = 1; - if (hook (filename, &info, hook_data)) + if (hook (filename, &info, hook_data)) + { + grub_free (filename); break; - } + } + + grub_free (filename); pos += grub_ufs_to_cpu16 (dirent.direntlen); }