On Tue, 17 Jun 2008, maximilian attems wrote:
>
> > klibc cpio segfaults extracting various cpio files. It seems to work
for
> > small files, but fail for larger ones, including the d-i root floppy
> > image.
> >
> > For example:
> >
> > joey at kodama:/tmp/empty>wget
http://people.debian.org/~joeyh/d-i/images/20080401-09:01/floppy/root.img
> > joey at kodama:/tmp/empty>zcat root.img | sudo
/usr/lib/klibc/bin/cpio -i
> > zsh: broken pipe zcat root.img |
> > zsh: segmentation fault sudo /usr/lib/klibc/bin/cpio -i
>
> right easy testcase.
ok so doublechecked that it is not a type issue.
right small files needs to be really small according to my tests.
but building klibc with debug aka
make V=1 DEBUG=y KLIBCOPTFLAGS='-g -Os -D DEBUG_MALLOC'
it seems that with gcc-4.3 doesn't get the sscanf() in cpio.c right
so thanks to hpa that patch got proposed
diff --git a/usr/utils/cpio.c b/usr/utils/cpio.c
index 8acfe6f..3df8927 100644
--- a/usr/utils/cpio.c
+++ b/usr/utils/cpio.c
@@ -82,19 +82,24 @@ int io_block_size = 512;
struct new_cpio_header {
unsigned short c_magic;
- unsigned long c_ino;
- unsigned long c_mode;
- unsigned long c_uid;
- unsigned long c_gid;
- unsigned long c_nlink;
- unsigned long c_mtime;
- unsigned long c_filesize;
- long c_dev_maj;
- long c_dev_min;
- long c_rdev_maj;
- long c_rdev_min;
- unsigned long c_namesize;
- unsigned long c_chksum;
+ union {
+ struct {
+ unsigned long c_ino;
+ unsigned long c_mode;
+ unsigned long c_uid;
+ unsigned long c_gid;
+ unsigned long c_nlink;
+ unsigned long c_mtime;
+ unsigned long c_filesize;
+ long c_dev_maj;
+ long c_dev_min;
+ long c_rdev_maj;
+ long c_rdev_min;
+ unsigned long c_namesize;
+ unsigned long c_chksum;
+ };
+ unsigned long c_hdr[13];
+ };
char *c_name;
char *c_tar_linkname;
};
@@ -897,18 +902,17 @@ static void copyin_file(struct new_cpio_header *file_hdr,
int in_file_des)
static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des)
{
- char ascii_header[112];
-
- tape_buffered_read(ascii_header, in_des, 104L);
- ascii_header[104] = '\0';
- sscanf(ascii_header,
- "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
- &file_hdr->c_ino, &file_hdr->c_mode,
&file_hdr->c_uid,
- &file_hdr->c_gid, &file_hdr->c_nlink,
&file_hdr->c_mtime,
- &file_hdr->c_filesize, &file_hdr->c_dev_maj,
- &file_hdr->c_dev_min, &file_hdr->c_rdev_maj,
- &file_hdr->c_rdev_min, &file_hdr->c_namesize,
- &file_hdr->c_chksum);
+ char ascii_header[112], *ah, hexbuf[9];
+ int i;
+
+ tape_buffered_read(ascii_header, in_des, 13*8);
+ ah = ascii_header;
+ hexbuf[8] = '\0';
+ for (i = 0; i < 13; i++) {
+ memcpy(hexbuf, ah, 8);
+ file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16);
+ ah += 8;
+ }
/* Read file name from input. */
if (file_hdr->c_name != NULL)
free(file_hdr->c_name);
but the memory corruption hitting that free seems to come from
another fishy culprit. this looks like a recently-allocated buffer
overwriting the head of the free block following it.
--
maks