[PATCH] Fix for write to an array past its size

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

This patch fixes a bug in file fs/devices.c, function kdevname(),
where it overwrites the memory location following the end of static
array "buffer".

In file fs/minix/dir.c, function minix_dir_read(), changed its
declaration from using traditional C to ansi C.

Several improvements to code in fs and fs/minix directories

Code size was reduced by 176 bytes and data size reduced in 96 bytes.

Greetings,

Juan
diff -Nur elks.orig/fs/buffer.c elks/fs/buffer.c
--- elks.orig/fs/buffer.c	2014-12-01 14:07:00.000000000 -0600
+++ elks/fs/buffer.c	2014-12-01 15:41:32.000000000 -0600
@@ -167,12 +167,12 @@
 
 static struct buffer_head *find_buffer(kdev_t dev, block_t block)
 {
-    register struct buffer_head *tmp;
+    register struct buffer_head *bh;
 
-    for (tmp = bh_chain; tmp != NULL; tmp = tmp->b_next)
-	if (tmp->b_blocknr == block && tmp->b_dev == dev)
+    for (bh = bh_chain; bh != NULL; bh = bh->b_next)
+	if (bh->b_blocknr == block && bh->b_dev == dev)
 	    break;
-    return tmp;
+    return bh;
 }
 
 static struct buffer_head *get_free_buffer(void)
@@ -521,8 +521,10 @@
 
 #ifdef CONFIG_FS_EXTERNAL_BUFFER
     _buf_ds = mm_alloc(NR_BUFFERS * 0x40);
-    for (i = 0; i < NR_MAPBUFS; i++)
+    i = 0;
+    do {
 	bufmem_map[i] = NULL;
+    } while(++i < NR_MAPBUFS);
 #endif
 
     buffers[0].b_prev_lru = NULL;
diff -Nur elks.orig/fs/devices.c elks/fs/devices.c
--- elks.orig/fs/devices.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/devices.c	2014-12-01 15:48:49.000000000 -0600
@@ -241,7 +241,7 @@
 {
 #if (MINORBITS == 8) && (MINORMASK == 255)
     static char buffer[5];
-    register char *bp = buffer + 5;
+    register char *bp = buffer + 4;
     *bp = 0;
     do {
 	*--bp = hex_string[dev & 0xf];
diff -Nur elks.orig/fs/exec.c elks/fs/exec.c
--- elks.orig/fs/exec.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/exec.c	2014-12-01 16:18:20.000000000 -0600
@@ -66,7 +66,6 @@
     gid_t effgid;
     lsize_t len;
     size_t result;
-    char load_code = 0;
 
     /*
      *      Open the image
@@ -183,7 +182,18 @@
         if (!cseg) {
             goto error_exec2;
         }
-        load_code = 1;
+        tregs->ds = cseg;
+        result = filp->f_op->read(inode, filp, 0, mh.tseg);
+        tregs->ds = ds;
+        if (result != mh.tseg) {
+            debug2("EXEC(tseg read): bad result %u, expected %u\n",
+	       result, mh.tseg);
+	    retval = -ENOEXEC;
+	    goto error_exec3;
+        }
+    }
+    else {
+        filp->f_pos += mh.tseg;
     }
 
     /*
@@ -210,19 +220,6 @@
     debug2("EXEC: Malloc succeeded - cs=%x ds=%x\n", cseg, dseg);
 
     retval = -ENOEXEC;
-    if(load_code){
-        tregs->ds = cseg;
-        result = filp->f_op->read(inode, filp, 0, mh.tseg);
-        tregs->ds = ds;
-        if (result != mh.tseg) {
-            debug2("EXEC(tseg read): bad result %u, expected %u\n",
-	       result, mh.tseg);
-	    goto error_exec4;
-        }
-    } else {
-        filp->f_pos += mh.tseg;
-    }
-
     tregs->ds = dseg;
     result = filp->f_op->read(inode, filp, (char *)stack_top, mh.dseg);
     tregs->ds = ds;
diff -Nur elks.orig/fs/minix/dir.c elks/fs/minix/dir.c
--- elks.orig/fs/minix/dir.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/minix/dir.c	2014-12-01 15:46:09.000000000 -0600
@@ -16,11 +16,7 @@
 
 #include <arch/segment.h>
 
-static int minix_dir_read(inode, filp, buf, count)
-     struct inode *inode;
-     struct file *filp;
-     char *buf;
-     int count;
+static int minix_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
 {
     return -EISDIR;
 }
diff -Nur elks.orig/fs/minix/inode.c elks/fs/minix/inode.c
--- elks.orig/fs/minix/inode.c	2014-12-01 14:07:00.000000000 -0600
+++ elks/fs/minix/inode.c	2014-12-01 15:29:52.000000000 -0600
@@ -30,7 +30,7 @@
 
 /* Function definitions */
 
-void minix_put_inode(register struct inode *inode)
+static void minix_put_inode(register struct inode *inode)
 {
     if (!inode->i_nlink) {
 	inode->i_size = 0;
@@ -420,50 +420,59 @@
 }
 
 /*
- * The minix V1 function to read an inode.
+ * The minix V1 function to read an inode into a buffer.
  */
 
-static void minix_read_inode(register struct inode *inode)
+static struct buffer_head *minix_get_inode(register struct inode *inode,
+					   struct minix_inode **raw_inode)
 {
-    struct buffer_head *bh;
-    struct minix_inode *raw_inode;
+    register struct buffer_head *bh = NULL;
     unsigned short block;
     unsigned int ino;
 
     ino = inode->i_ino;
-    inode->i_op = NULL;
-    inode->i_mode = 0;
-    {
-	/* Isolate register variable */
-	register struct super_block *isb = inode->i_sb;
-
-	if (!ino || ino > isb->u.minix_sb.s_ninodes) {
-	    printk("Bad inode number on dev %s: %d is out of range\n",
-		   kdevname(inode->i_dev), ino);
-	    return;
-	}
-	block = isb->u.minix_sb.s_imap_blocks + 2 +
-	    isb->u.minix_sb.s_zmap_blocks + (ino - 1) / MINIX_INODES_PER_BLOCK;
+    if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
+	printk("Bad inode number on dev %s: %d is out of range\n",
+		kdevname(inode->i_dev), ino);
     }
-    if (!(bh = bread(inode->i_dev, (block_t) block))) {
-	printk("Major problem: unable to read inode from dev %s\n",
-	       kdevname(inode->i_dev));
-	return;
+    else {
+	block = inode->i_sb->u.minix_sb.s_imap_blocks + 2 +
+	    inode->i_sb->u.minix_sb.s_zmap_blocks + (ino - 1) / MINIX_INODES_PER_BLOCK;
+	if (!(bh = bread(inode->i_dev, (block_t) block))) {
+	    printk("unable to read i-node block\n");
+	}
+	else {
+	    map_buffer(bh);
+	    *raw_inode = ((struct minix_inode *) bh->b_data) +
+		(ino - 1) % MINIX_INODES_PER_BLOCK;
+	}
     }
-    map_buffer(bh);
-    raw_inode = ((struct minix_inode *) bh->b_data) +
-	(ino - 1) % MINIX_INODES_PER_BLOCK;
-    memcpy(inode, raw_inode, sizeof(struct minix_inode));
-    inode->i_ctime = inode->i_atime = inode->i_mtime;
+    return bh;
+}
+
+/*
+ * The minix V1 function to read an inode.
+ */
+
+static void minix_read_inode(register struct inode *inode)
+{
+    register struct buffer_head *bh;
+    struct minix_inode *raw_inode;
+
+    bh = minix_get_inode(inode, &raw_inode);
+    if(bh) {
+	memcpy(inode, raw_inode, sizeof(struct minix_inode));
+	inode->i_ctime = inode->i_atime = inode->i_mtime;
 
 #ifdef BLOAT_FS
-    inode->i_blocks = inode->i_blksize = 0;
+	inode->i_blocks = inode->i_blksize = 0;
 #endif
 
-    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-	inode->i_rdev = to_kdev_t(raw_inode->i_zone[0]);
-    unmap_brelse(bh);
-    minix_set_ops(inode);
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+	    inode->i_rdev = to_kdev_t(raw_inode->i_zone[0]);
+	unmap_brelse(bh);
+	minix_set_ops(inode);
+    }
 }
 
 /*
@@ -472,36 +481,17 @@
 
 static struct buffer_head *minix_update_inode(register struct inode *inode)
 {
-    register struct buffer_head *bh;
+    register struct buffer_head *bh = NULL;
     struct minix_inode *raw_inode;
-    unsigned int ino;
-    unsigned short block;
 
-    ino = inode->i_ino;
-    if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
-	printk("Bad inode number on dev %s: %d is out of range\n",
-	       kdevname(inode->i_dev), ino);
+    bh = minix_get_inode(inode, &raw_inode);
+    if(bh) {
+	memcpy(raw_inode, inode, sizeof(struct minix_inode));
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+	    raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	inode->i_dirt = 0;
-	bh = 0;
-    } else {
-	block = inode->i_sb->u.minix_sb.s_imap_blocks + 2 +
-	    inode->i_sb->u.minix_sb.s_zmap_blocks + (ino - 1)
-	    / MINIX_INODES_PER_BLOCK;
-
-	if (!(bh = bread(inode->i_dev, (block_t) block))) {
-	    printk("unable to read i-node block\n");
-	    inode->i_dirt = 0;
-	} else {
-	    map_buffer(bh);
-	    raw_inode = ((struct minix_inode *) bh->b_data) +
-		(ino - 1) % MINIX_INODES_PER_BLOCK;
-	    memcpy(raw_inode, inode, sizeof(struct minix_inode));
-	    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
-	    inode->i_dirt = 0;
-	    mark_buffer_dirty(bh, 1);
-	    unmap_buffer(bh);
-	}
+	mark_buffer_dirty(bh, 1);
+	unmap_buffer(bh);
     }
     return bh;
 }
diff -Nur elks.orig/fs/read_write.c elks/fs/read_write.c
--- elks.orig/fs/read_write.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/read_write.c	2014-12-01 17:26:57.000000000 -0600
@@ -19,7 +19,7 @@
 {
     register struct file *file;
     register struct file_operations *fop;
-    loff_t offset, tmp;
+    loff_t offset;
 
     offset = (loff_t) get_user_long(p_offset);
     if (fd >= NR_OPEN || !(file = current->files.fd[fd])
@@ -33,27 +33,23 @@
 
     /* this is the default handler if no lseek handler is present */
     /* Note: We already determined above that origin is in range. */
-    if (origin == 2) {
-	if (!file->f_inode)
-	    return -EINVAL;
-	tmp = file->f_inode->i_size + offset;
-    } else {
-	tmp = (!origin) ? offset : file->f_pos + offset;
-    }
+    if(origin == 1)
+	offset += file->f_pos;
+    else if(origin == 2)
+	offset += file->f_inode->i_size;
 
-    if (tmp < 0)
+    if(offset < 0)
 	return -EINVAL;
-    if (tmp != file->f_pos) {
-	file->f_pos = tmp;
 
 #ifdef BLOAT_FS
+    if(offset != file->f_pos) {
 	file->f_reada = 0;
 	file->f_version = ++event;
-#endif
-
     }
+#endif
 
-    put_user_long((unsigned long int)tmp, (void *)p_offset);
+    file->f_pos = offset;
+    put_user_long((unsigned long int)offset, (void *)p_offset);
 
     return 0;
 }

[Index of Archives]     [Kernel]     [Linux ia64]     [DCCP]     [Linux for ARM]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux