fsck.cramfs: Fix bus error on broken file system.
PATCH 1/1 fsck.cramfs: Fix bus error on broken file system.
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfs
--- disk-utils/fsck.cramfs.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
disk-utils/fsck.cramfs.c +9 -9
@@ -219,24 +219,24 @@ static void test_crc(int start) crc =crc32 (0L ,NULL ,0 ); - buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 ); + buf =mmap (NULL , start + super.size,PROT_READ |PROT_WRITE , +MAP_PRIVATE , fd,0 );if (buf ==MAP_FAILED ) { - buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE , -MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 ); + buf =mmap (NULL , start + super.size,PROT_READ |PROT_WRITE , +MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 );if (buf !=MAP_FAILED ) { -if (lseek (fd,0 ,SEEK_SET ) == (off_t) -1 ) +if (lseek (fd, start,SEEK_SET ) == (off_t) -1 )err (FSCK_EX_ERROR ,_ ("seek on %s failed" ), filename); -if (read (fd, buf, super.size) != (ssize_t ) super.size) +if (read (fd, (unsigned char *) buf + start, super.size) != + (ssize_t ) super.size)err (FSCK_EX_ERROR ,_ ("cannot read %s" ), filename); } }if (buf !=MAP_FAILED ) { ((struct cramfs_super *)((unsigned char *) buf + start))->fsid.crc =crc32 (0L ,NULL ,0 ); - crc =crc32 (crc, (unsigned char *) buf + start, super.size - start); -munmap (buf, super.size); + crc =crc32 (crc, (unsigned char *) buf + start, super.size); +munmap (buf, start + super.size); }else {int retval;size_t length =0 ;
Signature · 1 line
2.14.3
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfs
---
This is the second and much cleaner version of the initial patch. We can easily use the offset of mmap, which heavily reduces the manual buf + start calculation.
--- disk-utils/fsck.cramfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
disk-utils/fsck.cramfs.c +3 -4
@@ -220,7 +220,7 @@ static void test_crc(int start) crc =crc32 (0L ,NULL ,0 ); buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 ); +mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd, start);if (buf ==MAP_FAILED ) { buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE,
@@ -233,9 +233,8 @@ static void test_crc(int start) } }if (buf !=MAP_FAILED ) { - ((struct cramfs_super *)((unsigned char *) buf + start))->fsid.crc = -crc32 (0L ,NULL ,0 ); - crc =crc32 (crc, (unsigned char *) buf + start, super.size - start); + ((struct cramfs_super *) buf)->fsid.crc =crc32 (0L ,NULL ,0 ); + crc =crc32 (crc, buf, super.size);munmap (buf, super.size); }else {int retval;
Signature · 1 line
2.14.3
Karel Zak
maintainerQuoted 27 lines · Tobias Stoeckmann
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfsSigned-off-by Tobias Stoeckmann <[email protected]>---
This is the second and much cleaner version of the initial patch. We can easily use the offset of mmap, which heavily reduces the manual buf + start calculation.--- disk-utils/fsck.cramfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)disk-utils/fsck.cramfs.c +0
-0
disk-utils/fsck.cramfs.c static void test_crc(int start) · line 223
Quoted 5 lines
disk-utils/fsck.cramfs.c +1
-1@@ -220,7 +220,7 @@ static void test_crc(int start) crc =crc32 (0L ,NULL ,0 ); buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 ); +mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd, start);
mmap() offset should be aligned to PAGE_SIZE. The function test_super() is able to set "start" to PAD_SIZE (=512). It does not seem correct.
disk-utils/fsck.cramfs.c static void test_crc(int start) · line 226
Quoted 3 lines
disk-utils/fsck.cramfs.c +0
-0if (buf ==MAP_FAILED ) { buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE,
on failed mmap() it tries to use open+read to get "buf" and it reads it from the begin of the file. It seems incompatible with mmap() now. I guess we need seek(start) there too.
disk-utils/fsck.cramfs.c static void test_crc(int start) · line 240
Quoted 12 lines
disk-utils/fsck.cramfs.c +2
-3@@ -233,9 +233,8 @@ static void test_crc(int start) } }if (buf !=MAP_FAILED ) { - ((struct cramfs_super *)((unsigned char *) buf + start))->fsid.crc = -crc32 (0L ,NULL ,0 ); - crc =crc32 (crc, (unsigned char *) buf + start, super.size - start); + ((struct cramfs_super *) buf)->fsid.crc =crc32 (0L ,NULL ,0 ); + crc =crc32 (crc, buf, super.size);munmap (buf, super.size); }else {int retval;
Karel
Signature · 2 lines
Karel Zak <[email protected]> http://karelzak.blogspot.com
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfs
---
This version avoids mmap offset again and properly sets lseek offset.
--- disk-utils/fsck.cramfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
disk-utils/fsck.cramfs.c +6 -6
@@ -220,23 +220,23 @@ static void test_crc(int start) crc =crc32 (0L ,NULL ,0 ); buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 ); +mmap (NULL , start + super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 );if (buf ==MAP_FAILED ) { buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE , +mmap (NULL , start + super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 );if (buf !=MAP_FAILED ) { -if (lseek (fd,0 ,SEEK_SET ) == (off_t) -1 ) +if (lseek (fd, start,SEEK_SET ) == (off_t) -1 )err (FSCK_EX_ERROR ,_ ("seek on %s failed" ), filename); -if (read (fd, buf, super.size) != (ssize_t ) super.size) +if (read (fd, buf + start, super.size) != (ssize_t ) super.size)err (FSCK_EX_ERROR ,_ ("cannot read %s" ), filename); } }if (buf !=MAP_FAILED ) { ((struct cramfs_super *)((unsigned char *) buf + start))->fsid.crc =crc32 (0L ,NULL ,0 ); - crc =crc32 (crc, (unsigned char *) buf + start, super.size - start); -munmap (buf, super.size); + crc =crc32 (crc, (unsigned char *) buf + start, super.size); +munmap (buf, start + super.size); }else {int retval;size_t length =0 ;
Signature · 1 line
2.14.3
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfs
---
Update to last patch: read lacked a proper cast to (unsigned char *).
--- disk-utils/fsck.cramfs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
disk-utils/fsck.cramfs.c +7 -6
@@ -220,23 +220,24 @@ static void test_crc(int start) crc =crc32 (0L ,NULL ,0 ); buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 ); +mmap (NULL , start + super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE , fd,0 );if (buf ==MAP_FAILED ) { buf = -mmap (NULL , super.size,PROT_READ |PROT_WRITE , +mmap (NULL , start + super.size,PROT_READ |PROT_WRITE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 );if (buf !=MAP_FAILED ) { -if (lseek (fd,0 ,SEEK_SET ) == (off_t) -1 ) +if (lseek (fd, start,SEEK_SET ) == (off_t) -1 )err (FSCK_EX_ERROR ,_ ("seek on %s failed" ), filename); -if (read (fd, buf, super.size) != (ssize_t ) super.size) +if (read (fd, (unsigned char *) buf + start, super.size) != + (ssize_t ) super.size)err (FSCK_EX_ERROR ,_ ("cannot read %s" ), filename); } }if (buf !=MAP_FAILED ) { ((struct cramfs_super *)((unsigned char *) buf + start))->fsid.crc =crc32 (0L ,NULL ,0 ); - crc =crc32 (crc, (unsigned char *) buf + start, super.size - start); -munmap (buf, super.size); + crc =crc32 (crc, (unsigned char *) buf + start, super.size); +munmap (buf, start + super.size); }else {int retval;size_t length =0 ;
Signature · 1 line
2.14.3
Quoted 5 lines · Tobias Stoeckmann
The utility fsck.cramfs is prone to a bus error on file systems for big endian systems with non-standard header sizes. While calculating the crc32 checksum, it does not properly handle a possible offset for bootcodes, resulting in out of boundary access of mmap'ed area.
Quoted 7 lines
You can trigger the issue with the following commands:
$ mkdir -p cramfs-poc/root/subdir $ cd cramfs-poc $ mkfs.cramfs -p -N big root cramfs $ echo -ne \\00\\x4c | dd of=cramfs bs=1 seek=518 count=2 conv=notrunc $ fsck.cramfs cramfs
Added between tests.
Quoted 2 lines
disk-utils/fsck.cramfs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
Applied, thanks.
Karel
Signature · 2 lines
Karel Zak <[email protected]> http://karelzak.blogspot.com