Fix tar 4G limit and handle paths containing dot.

* grub-core/fs/cpio.c (grub_cpio_data): Use grub_off_t for offsets.
	(canonicalize): New function.
	(grub_cpio_find_file): Use canonicalize. Store offs in
	grub_disk_addr_t.
	(grub_cpio_dir): Use grub_disk_addr_t.
	(grub_cpio_open): Likewise.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-25 18:12:36 +02:00
parent 9f12e664cc
commit d4888031f2
2 changed files with 89 additions and 56 deletions

View file

@ -1,3 +1,14 @@
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
Fix tar 4G limit and handle paths containing dot.
* grub-core/fs/cpio.c (grub_cpio_data): Use grub_off_t for offsets.
(canonicalize): New function.
(grub_cpio_find_file): Use canonicalize. Store offs in
grub_disk_addr_t.
(grub_cpio_dir): Use grub_disk_addr_t.
(grub_cpio_open): Likewise.
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com> 2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
Fix handling of uncompressed blocks on squashfs and break 4G limit. Fix handling of uncompressed blocks on squashfs and break 4G limit.

View file

@ -71,80 +71,102 @@ struct head
struct grub_cpio_data struct grub_cpio_data
{ {
grub_disk_t disk; grub_disk_t disk;
grub_uint32_t hofs; grub_off_t hofs;
grub_uint32_t dofs; grub_off_t dofs;
grub_uint32_t size; grub_off_t size;
}; };
static grub_dl_t my_mod; static grub_dl_t my_mod;
static inline void
canonicalize (char *name)
{
char *iptr, *optr;
for (iptr = name, optr = name; *iptr; )
{
while (*iptr == '/')
iptr++;
if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
{
iptr += 2;
continue;
}
while (*iptr && *iptr != '/')
*optr++ = *iptr++;
if (*iptr)
*optr++ = *iptr++;
}
*optr = 0;
}
static grub_err_t static grub_err_t
grub_cpio_find_file (struct grub_cpio_data *data, char **name, grub_cpio_find_file (struct grub_cpio_data *data, char **name,
grub_int32_t *mtime, grub_uint32_t * ofs) grub_int32_t *mtime, grub_disk_addr_t * ofs)
{ {
#ifndef MODE_USTAR #ifndef MODE_USTAR
struct head hd; struct head hd;
if (grub_disk_read if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
(data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno;
return grub_errno;
if (hd.magic != MAGIC_BCPIO) if (hd.magic != MAGIC_BCPIO)
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2; data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
if (mtime) if (mtime)
*mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2; *mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
if (hd.namesize & 1) if (hd.namesize & 1)
hd.namesize++; hd.namesize++;
if ((*name = grub_malloc (hd.namesize)) == NULL) if ((*name = grub_malloc (hd.namesize)) == NULL)
return grub_errno; return grub_errno;
if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd), if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
hd.namesize, *name)) hd.namesize, *name))
{ {
grub_free (*name); grub_free (*name);
return grub_errno; return grub_errno;
} }
if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1 if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
&& ! grub_memcmp(*name, "TRAILER!!!", 11)) && ! grub_memcmp(*name, "TRAILER!!!", 11))
{ {
*ofs = 0; *ofs = 0;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
data->dofs = data->hofs + sizeof (hd) + hd.namesize; canonicalize (*name);
*ofs = data->dofs + data->size;
if (data->size & 1) data->dofs = data->hofs + sizeof (hd) + hd.namesize;
(*ofs)++; *ofs = data->dofs + data->size;
if (data->size & 1)
(*ofs)++;
#else #else
struct head hd; struct head hd;
if (grub_disk_read if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
(data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno;
return grub_errno;
if (!hd.name[0]) if (!hd.name[0])
{ {
*ofs = 0; *ofs = 0;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1)) if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
if ((*name = grub_strdup (hd.name)) == NULL) if ((*name = grub_strdup (hd.name)) == NULL)
return grub_errno; return grub_errno;
data->size = grub_strtoul (hd.size, NULL, 8); data->size = grub_strtoull (hd.size, NULL, 8);
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
*ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
~(GRUB_DISK_SECTOR_SIZE - 1)); ~(GRUB_DISK_SECTOR_SIZE - 1));
if (mtime) if (mtime)
*mtime = grub_strtoul (hd.mtime, NULL, 8); *mtime = grub_strtoul (hd.mtime, NULL, 8);
canonicalize (*name);
#endif #endif
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
@ -191,10 +213,10 @@ grub_cpio_dir (grub_device_t device, const char *path,
const struct grub_dirhook_info *info)) const struct grub_dirhook_info *info))
{ {
struct grub_cpio_data *data; struct grub_cpio_data *data;
grub_uint32_t ofs; grub_disk_addr_t ofs;
char *prev, *name; char *prev, *name;
const char *np; const char *np;
int len; grub_size_t len;
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
@ -230,7 +252,7 @@ grub_cpio_dir (grub_device_t device, const char *path,
if (p) if (p)
*p = 0; *p = 0;
if ((!prev) || (grub_strcmp (prev, name) != 0)) if (((!prev) || (grub_strcmp (prev, name) != 0)) && name[len] != 0)
{ {
struct grub_dirhook_info info; struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info)); grub_memset (&info, 0, sizeof (info));
@ -262,7 +284,7 @@ static grub_err_t
grub_cpio_open (grub_file_t file, const char *name) grub_cpio_open (grub_file_t file, const char *name)
{ {
struct grub_cpio_data *data; struct grub_cpio_data *data;
grub_uint32_t ofs; grub_disk_addr_t ofs;
char *fn; char *fn;
int i, j; int i, j;