[PATCH] qnx4 causes memory corruption in 2.2.12

Andries.Brouwer@cwi.nl
Thu, 9 Sep 1999 04:12:40 +0200 (MET DST)


When mounting something without the -t option,
the program mount will try all known filesystems.
The unfortunate soul that has qnx4 compiled into
her kernel will experience memory corruption.

What happens? First, the test that the fs starts with QNX4FS
is ifdef'ed out, so that we don't notice right away that
something is wrong. Then, the
d_alloc_root(iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK), NULL);
will allocate dentries and put inodes in the hash table.
Further down in qnx4_read_super() a qnx4_checkroot() is done
and we decide that this after all is not a valid qnx4 filesystem.
The mount fails, and bogus data remains in the inode hash table.

There are other things in the qnx4 code that look extremely suspect.
Here a patch that moves the qnx4_checkroot() to before the iget().
It fixes a reproducible memory corruption.
For extra safety I removed the #if 0 .. #endif from the signature check.

Andries

---------------------------------------------------------------
diff -u --recursive --new-file ../linux-2.2.12/linux/fs/qnx4/inode.c ./linux/fs/qnx4/inode.c
--- ../linux-2.2.12/linux/fs/qnx4/inode.c Sun Sep 6 02:01:45 1998
+++ ./linux/fs/qnx4/inode.c Thu Sep 9 03:39:47 1999
@@ -26,7 +26,6 @@

#define QNX4_VERSION 4
#define QNX4_BMNAME ".bitmap"
-#define CHECK_BOOT_SIGNATURE 0

static struct super_operations qnx4_sops;

@@ -256,9 +255,6 @@
int i, j;
int found = 0;

- if (s == NULL) {
- return "no qnx4 filesystem (null superblock).";
- }
if (*(s->u.qnx4_sb.sb->RootDir.di_fname) != '/') {
return "no qnx4 filesystem (no root dir).";
} else {
@@ -281,6 +277,8 @@
}
}
}
+ /* WAIT! s->u.qnx4_sb.BitMap points into bh->b_data
+ and now we release bh?? */
brelse(bh);
if (found != 0) {
break;
@@ -298,9 +296,8 @@
{
struct buffer_head *bh;
kdev_t dev = s->s_dev;
-#if CHECK_BOOT_SIGNATURE
+ struct inode *root;
char *tmpc;
-#endif
const char *errmsg;

MOD_INC_USE_COUNT;
@@ -310,7 +307,9 @@
s->s_blocksize_bits = 9;
s->s_dev = dev;

-#if CHECK_BOOT_SIGNATURE
+ /* Check the boot signature. Since the qnx4 code is
+ dangerous, we should leave as quickly as possible
+ if we don't belong here... */
bh = bread(dev, 0, QNX4_BLOCK_SIZE);
if (!bh) {
printk("qnx4: unable to read the boot sector\n");
@@ -319,11 +318,12 @@
tmpc = (char *) bh->b_data;
if (tmpc[4] != 'Q' || tmpc[5] != 'N' || tmpc[6] != 'X' ||
tmpc[7] != '4' || tmpc[8] != 'F' || tmpc[9] != 'S') {
- printk("qnx4: wrong fsid in boot sector.\n");
+ if (!silent)
+ printk("qnx4: wrong fsid in boot sector.\n");
goto out;
}
brelse(bh);
-#endif
+
bh = bread(dev, 1, QNX4_BLOCK_SIZE);
if (!bh) {
printk("qnx4: unable to read the superblock\n");
@@ -336,23 +336,34 @@
#endif
s->u.qnx4_sb.sb_buf = bh;
s->u.qnx4_sb.sb = (struct qnx4_super_block *) bh->b_data;
- s->s_root =
- d_alloc_root(iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK), NULL);
- if (s->s_root == NULL) {
- printk("qnx4: get inode failed\n");
- goto out;
- }
+
+ /* check before allocating dentries, inodes, .. */
errmsg = qnx4_checkroot(s);
if (errmsg != NULL) {
- printk("qnx4: %s\n", errmsg);
+ if (!silent)
+ printk("qnx4: %s\n", errmsg);
goto out;
}
+
+ /* does root not have inode number QNX4_ROOT_INO ?? */
+ root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
+ if (!root) {
+ printk("qnx4: get inode failed\n");
+ goto out;
+ }
+
+ s->s_root = d_alloc_root(root, NULL);
+ if (s->s_root == NULL)
+ goto outi;
+
brelse(bh);
unlock_super(s);
s->s_dirt = 1;

return s;

+ outi:
+ iput(root);
out:
brelse(bh);
outnobh:

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/