]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Fix tar 4G limit and handle paths containing dot.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 25 Oct 2011 16:12:36 +0000 (18:12 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 25 Oct 2011 16:12:36 +0000 (18:12 +0200)
* 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.

ChangeLog
grub-core/fs/cpio.c

index 586de218fffd1c9254a80f50ea3f90244b24a639..19bf1326e25d2ceea80d4650c9a9002dd03ab9be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        Fix handling of uncompressed blocks on squashfs and break 4G limit.
index 0d84382acc098b45a9ba2d2bcc8f6dcc6a5faf23..92531390e060d8181e8fda1a3a27637badb3544c 100644 (file)
@@ -71,80 +71,102 @@ struct head
 struct grub_cpio_data
 {
   grub_disk_t disk;
-  grub_uint32_t hofs;
-  grub_uint32_t dofs;
-  grub_uint32_t size;
+  grub_off_t hofs;
+  grub_off_t dofs;
+  grub_off_t size;
 };
 
 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
 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
-      struct head hd;
+  struct head hd;
 
-      if (grub_disk_read
-         (data->disk, 0, data->hofs, sizeof (hd), &hd))
-       return grub_errno;
+  if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
+    return grub_errno;
 
-      if (hd.magic != MAGIC_BCPIO)
-       return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
+  if (hd.magic != MAGIC_BCPIO)
+    return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
 
-      data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
-      if (mtime)
-       *mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
+  data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
+  if (mtime)
+    *mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
 
-      if (hd.namesize & 1)
-       hd.namesize++;
+  if (hd.namesize & 1)
+    hd.namesize++;
 
-      if ((*name = grub_malloc (hd.namesize)) == NULL)
-       return grub_errno;
+  if ((*name = grub_malloc (hd.namesize)) == NULL)
+    return grub_errno;
 
-      if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
-                         hd.namesize, *name))
-       {
-         grub_free (*name);
-         return grub_errno;
-       }
+  if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
+                     hd.namesize, *name))
+    {
+      grub_free (*name);
+      return grub_errno;
+    }
 
-      if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
-         && ! grub_memcmp(*name, "TRAILER!!!", 11))
-       {
-         *ofs = 0;
-         return GRUB_ERR_NONE;
-       }
+  if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
+      && ! grub_memcmp(*name, "TRAILER!!!", 11))
+    {
+      *ofs = 0;
+      return GRUB_ERR_NONE;
+    }
+
+  canonicalize (*name);
 
-      data->dofs = data->hofs + sizeof (hd) + hd.namesize;
-      *ofs = data->dofs + data->size;
-      if (data->size & 1)
-       (*ofs)++;
+  data->dofs = data->hofs + sizeof (hd) + hd.namesize;
+  *ofs = data->dofs + data->size;
+  if (data->size & 1)
+    (*ofs)++;
 #else
-      struct head hd;
+  struct head hd;
 
-      if (grub_disk_read
-         (data->disk, 0, data->hofs, sizeof (hd), &hd))
-       return grub_errno;
+  if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
+    return grub_errno;
 
-      if (!hd.name[0])
-       {
-         *ofs = 0;
-         return GRUB_ERR_NONE;
-       }
+  if (!hd.name[0])
+    {
+      *ofs = 0;
+      return GRUB_ERR_NONE;
+    }
 
-      if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
-       return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
+  if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
+    return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
 
-      if ((*name = grub_strdup (hd.name)) == NULL)
-       return grub_errno;
+  if ((*name = grub_strdup (hd.name)) == NULL)
+    return grub_errno;
 
-      data->size = grub_strtoul (hd.size, NULL, 8);
-      data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
-      *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
-                          ~(GRUB_DISK_SECTOR_SIZE - 1));
-      if (mtime)
-       *mtime = grub_strtoul (hd.mtime, NULL, 8);
+  data->size = grub_strtoull (hd.size, NULL, 8);
+  data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
+  *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
+                      ~(GRUB_DISK_SECTOR_SIZE - 1));
+  if (mtime)
+    *mtime = grub_strtoul (hd.mtime, NULL, 8);
+  canonicalize (*name);
 #endif
   return GRUB_ERR_NONE;
 }
@@ -191,10 +213,10 @@ grub_cpio_dir (grub_device_t device, const char *path,
                            const struct grub_dirhook_info *info))
 {
   struct grub_cpio_data *data;
-  grub_uint32_t ofs;
+  grub_disk_addr_t ofs;
   char *prev, *name;
   const char *np;
-  int len;
+  grub_size_t len;
 
   grub_dl_ref (my_mod);
 
@@ -230,7 +252,7 @@ grub_cpio_dir (grub_device_t device, const char *path,
          if (p)
            *p = 0;
 
-         if ((!prev) || (grub_strcmp (prev, name) != 0))
+         if (((!prev) || (grub_strcmp (prev, name) != 0)) && name[len] != 0)
            {
              struct grub_dirhook_info 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)
 {
   struct grub_cpio_data *data;
-  grub_uint32_t ofs;
+  grub_disk_addr_t ofs;
   char *fn;
   int i, j;